diff options
Diffstat (limited to 'linuxthreads_db')
-rw-r--r-- | linuxthreads_db/ChangeLog | 21 | ||||
-rw-r--r-- | linuxthreads_db/Makefile | 4 | ||||
-rw-r--r-- | linuxthreads_db/td_ta_clear_event.c | 49 | ||||
-rw-r--r-- | linuxthreads_db/td_ta_event_getmsg.c | 124 | ||||
-rw-r--r-- | linuxthreads_db/td_ta_new.c | 20 | ||||
-rw-r--r-- | linuxthreads_db/td_ta_set_event.c | 14 | ||||
-rw-r--r-- | linuxthreads_db/td_ta_thr_iter.c | 110 | ||||
-rw-r--r-- | linuxthreads_db/td_thr_clear_event.c | 35 | ||||
-rw-r--r-- | linuxthreads_db/td_thr_get_info.c | 3 | ||||
-rw-r--r-- | linuxthreads_db/td_thr_set_event.c | 17 | ||||
-rw-r--r-- | linuxthreads_db/thread_db.h | 10 | ||||
-rw-r--r-- | linuxthreads_db/thread_dbP.h | 6 |
12 files changed, 351 insertions, 62 deletions
diff --git a/linuxthreads_db/ChangeLog b/linuxthreads_db/ChangeLog index 723f9a4650..0922e9ed24 100644 --- a/linuxthreads_db/ChangeLog +++ b/linuxthreads_db/ChangeLog @@ -1,5 +1,26 @@ 1999-11-02 Ulrich Drepper <drepper@cygnus.com> + * td_ta_thr_iter.c (td_ta_thr_iter): Optimize a bit. Read all + handles at once. + + * thread_dbP.h (struct th_thragent): Add pthread_handle_num. + * td_ta_new.c: Initialize pthread_handle_num. + * td_ta_event_getmsg.c: If last event was already reported search + for another unreported event. + + * td_thr_get_info.c (td_thr_get_info): Initialize ti_events. + + * Makefile (libthread_db-routines): Add td_ta_set_event, + td_ta_event_getmsg, and td_ta_clear_event. + * td_ta_clear_event.c: New file. + * td_ta_event_getmsg.c: New file. + * td_ta_new.c: Get address of __pthread_last_event in target. + * td_ta_set_event.c: Don't overwrite old mask, set additional bits. + * td_thr_set_event.c: Likewise. + * td_thr_clear_event.c: Implement. + * thread_db.h: Declare td_ta_clear_event and td_ta_event_getmsg. + * thread_dbP.h (struct td_thragent): Add pthread_last_event. + * td_ta_new.c: Don't test for __pthread_threads_debug. Get address of __pthread_threads_events and fail if this is not possible. * td_ta_event_addr.c: Implement. diff --git a/linuxthreads_db/Makefile b/linuxthreads_db/Makefile index fb2825cffb..fa6b3bca5f 100644 --- a/linuxthreads_db/Makefile +++ b/linuxthreads_db/Makefile @@ -37,7 +37,9 @@ libthread_db-routines = td_init td_log td_ta_delete td_ta_get_nthreads \ td_ta_setconcurrency td_ta_enable_stats \ td_ta_reset_stats td_ta_get_stats td_ta_event_addr \ td_thr_event_enable td_thr_set_event \ - td_thr_clear_event td_thr_event_getmsg + td_thr_clear_event td_thr_event_getmsg \ + td_ta_set_event td_ta_event_getmsg \ + td_ta_clear_event libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes)) diff --git a/linuxthreads_db/td_ta_clear_event.c b/linuxthreads_db/td_ta_clear_event.c new file mode 100644 index 0000000000..ec7770eae1 --- /dev/null +++ b/linuxthreads_db/td_ta_clear_event.c @@ -0,0 +1,49 @@ +/* Globally disable events. + Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_clear_event (ta, event) + const td_thragent_t *ta; + td_thr_events_t *event; +{ + td_thr_events_t old_event; + int i; + + LOG (__FUNCTION__); + + /* Write the new value into the thread data structure. */ + if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Remove the set bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] &= ~event->event_bits[i]; + + /* Write the new value into the thread data structure. */ + if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/linuxthreads_db/td_ta_event_getmsg.c b/linuxthreads_db/td_ta_event_getmsg.c new file mode 100644 index 0000000000..6b56e0d5e7 --- /dev/null +++ b/linuxthreads_db/td_ta_event_getmsg.c @@ -0,0 +1,124 @@ +/* Retrieve event. + Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <stddef.h> +#include <string.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg) +{ + /* XXX I cannot think of another way but using a static variable. */ + static td_thrhandle_t th; + td_eventbuf_t event; + psaddr_t addr; + + LOG (__FUNCTION__); + + /* Get the pointer to the thread descriptor with the last event. */ + if (ps_pdread (ta->ph, ta->pthread_last_event, + &addr, sizeof (void *)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* If the pointer is NULL no event occurred. */ + if (addr == 0) + return TD_NOMSG; + + /* Read the even structure from the target. */ + if (ps_pdread (ta->ph, + ((char *) addr + + offsetof (struct _pthread_descr_struct, p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Check whether an event occurred. */ + if (event.eventnum == TD_EVENT_NONE) + { + /* Oh well, this means the last event was already read. So + we have to look for any other event. */ + struct pthread_handle_struct handles[ta->pthread_threads_max]; + int num; + int i; + + /* Read the number of currently active threads. */ + if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) + != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Now read the handles. */ + if (ps_pdread (ta->ph, ta->handles, handles, + ta->pthread_threads_max * sizeof (handles[0])) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + for (i = 0; i < ta->pthread_threads_max && num > 0; ++i) + { + if (handles[i].h_descr == NULL) + /* No entry here. */ + continue; + + /* First count this active thread. */ + --num; + + if (handles[i].h_descr == addr) + /* We already handled this. */ + continue; + + /* Read the event data for this thread. */ + if (ps_pdread (ta->ph, + ((char *) handles[i].h_descr + + offsetof (struct _pthread_descr_struct, + p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; + + if (event.eventnum != TD_EVENT_NONE) + { + /* We found a thread with an unreported event. */ + addr = handles[i].h_descr; + break; + } + } + + /* If we haven't found any other event signal this to the user. */ + if (event.eventnum == TD_EVENT_NONE) + return TD_NOMSG; + } + + /* Generate the thread descriptor. */ + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = addr; + + /* Fill the user's data structure. */ + msg->event = event.eventnum; + msg->th_p = &th; + msg->msg.data = (uintptr_t) event.eventdata; + + /* And clear the event message in the target. */ + memset (&event, '\0', sizeof (td_eventbuf_t)); + if (ps_pdwrite (ta->ph, + ((char *) addr + + offsetof (struct _pthread_descr_struct, p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/linuxthreads_db/td_ta_new.c b/linuxthreads_db/td_ta_new.c index eeaf0cbf51..65535f8d14 100644 --- a/linuxthreads_db/td_ta_new.c +++ b/linuxthreads_db/td_ta_new.c @@ -51,15 +51,29 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) /* Remember the address. */ (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr; - /* See whether the library contains the necessary symbols. */ - if (ps_pglobal_lookup (ps, LIBPTHREAD_SO, "__pthread_handles", - &addr) != PS_OK) + /* Get the pointer to the variable pointing to the thread descriptor + with the last event. */ + if (ps_pglobal_lookup (ps, LIBPTHREAD_SO, + "__pthread_last_event", + &(*ta)->pthread_last_event) != PS_OK) { free_return: free (*ta); return TD_ERR; } + /* Get the pointer to the variable containing the number of active + threads. */ + if (ps_pglobal_lookup (ps, LIBPTHREAD_SO, + "__pthread_handles_num", + &(*ta)->pthread_handles_num) != PS_OK) + goto free_return; + + /* See whether the library contains the necessary symbols. */ + if (ps_pglobal_lookup (ps, LIBPTHREAD_SO, "__pthread_handles", + &addr) != PS_OK) + goto free_return; + (*ta)->handles = (struct pthread_handle_struct *) addr; diff --git a/linuxthreads_db/td_ta_set_event.c b/linuxthreads_db/td_ta_set_event.c index 10adbdf04f..f783d7567e 100644 --- a/linuxthreads_db/td_ta_set_event.c +++ b/linuxthreads_db/td_ta_set_event.c @@ -26,11 +26,23 @@ td_ta_set_event (ta, event) const td_thragent_t *ta; td_thr_events_t *event; { + td_thr_events_t old_event; + int i; + LOG (__FUNCTION__); /* Write the new value into the thread data structure. */ + if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Or the new bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] |= event->event_bits[i]; + + /* Write the new value into the thread data structure. */ if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp, - event, sizeof (td_thrhandle_t)) != PS_OK) + &old_event, sizeof (td_thrhandle_t)) != PS_OK) return TD_ERR; /* XXX Other error value? */ return TD_OK; diff --git a/linuxthreads_db/td_ta_thr_iter.c b/linuxthreads_db/td_ta_thr_iter.c index f9b5673ebf..1fe871f4c7 100644 --- a/linuxthreads_db/td_ta_thr_iter.c +++ b/linuxthreads_db/td_ta_thr_iter.c @@ -26,64 +26,72 @@ td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback, void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p, unsigned int ti_user_flags) { - struct pthread_handle_struct *handles = ta->handles; int pthread_threads_max = ta->pthread_threads_max; size_t sizeof_descr = ta->sizeof_descr; + struct pthread_handle_struct phc[pthread_threads_max]; + int num; int cnt; LOG (__FUNCTION__); + /* Read all the descriptors. */ + if (ps_pdread (ta->ph, ta->handles, phc, + sizeof (struct pthread_handle_struct) * pthread_threads_max) + != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Read the number of currently active threads. */ + if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) + != PS_OK) + return TD_ERR; /* XXX Other error value? */ + /* Now get all descriptors, one after the other. */ - for (cnt = 0; cnt < pthread_threads_max; ++cnt, ++handles) - { - struct pthread_handle_struct phc; - - if (ps_pdread (ta->ph, handles, &phc, - sizeof (struct pthread_handle_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - if (phc.h_descr != NULL) - { - struct _pthread_descr_struct pds; - td_thrhandle_t th; - - if (ps_pdread (ta->ph, phc.h_descr, &pds, sizeof_descr) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* The manager thread must be handled special. The descriptor - exists but the thread only gets created when the first - `pthread_create' call is issued. A clear indication that - this happened is when the p_pid field is non-zero. */ - if (cnt == 1 && pds.p_pid == 0) - continue; - - /* Now test whether this thread matches the specified - conditions. */ - - /* Only if the priority level is as high or higher. */ - if (pds.p_priority < ti_pri) - continue; - - /* Test the state. - XXX This is incomplete. */ - if (state != TD_THR_ANY_STATE) - continue; - - /* XXX For now we ignore threads which are not running anymore. - The reason is that gdb tries to get the registers and fails. - In future we should have a special mode of the thread library - in which we keep the process around until the actual join - operation happened. */ - if (pds.p_exited != 0) - continue; - - /* Yep, it matches. Call the callback function. */ - th.th_ta_p = (td_thragent_t *) ta; - th.th_unique = phc.h_descr; - if (callback (&th, cbdata_p) != 0) - return TD_DBERR; - } - } + for (cnt = 0; cnt < pthread_threads_max && num > 0; ++cnt) + if (phc[cnt].h_descr != NULL) + { + struct _pthread_descr_struct pds; + td_thrhandle_t th; + + /* First count this active thread. */ + --num; + + if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr) + != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* The manager thread must be handled special. The descriptor + exists but the thread only gets created when the first + `pthread_create' call is issued. A clear indication that + this happened is when the p_pid field is non-zero. */ + if (cnt == 1 && pds.p_pid == 0) + continue; + + /* Now test whether this thread matches the specified + conditions. */ + + /* Only if the priority level is as high or higher. */ + if (pds.p_priority < ti_pri) + continue; + + /* Test the state. + XXX This is incomplete. */ + if (state != TD_THR_ANY_STATE) + continue; + + /* XXX For now we ignore threads which are not running anymore. + The reason is that gdb tries to get the registers and fails. + In future we should have a special mode of the thread library + in which we keep the process around until the actual join + operation happened. */ + if (pds.p_exited != 0) + continue; + + /* Yep, it matches. Call the callback function. */ + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = phc[cnt].h_descr; + if (callback (&th, cbdata_p) != 0) + return TD_DBERR; + } return TD_OK; } diff --git a/linuxthreads_db/td_thr_clear_event.c b/linuxthreads_db/td_thr_clear_event.c index c3c633b71d..8ef8cbbc40 100644 --- a/linuxthreads_db/td_thr_clear_event.c +++ b/linuxthreads_db/td_thr_clear_event.c @@ -1,4 +1,4 @@ -/* Disable specific event. +/* Disable specific event for thread. Copyright (C) 1999 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999. @@ -18,13 +18,40 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <stddef.h> + #include "thread_dbP.h" td_err_e -td_thr_clear_event (const td_thrhandle_t *th, td_thr_events_t *event) +td_thr_clear_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; { - /* XXX We have to figure out what has to be done. */ + td_thr_events_t old_event; + int i; + LOG (__FUNCTION__); - return TD_NOCAPAB; + + /* Write the new value into the thread data structure. */ + if (ps_pdread (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Remove the set bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] &= ~event->event_bits[i]; + + /* Write the new value into the thread data structure. */ + if (ps_pdwrite (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; } diff --git a/linuxthreads_db/td_thr_get_info.c b/linuxthreads_db/td_thr_get_info.c index 606ca81f78..1e05d4c214 100644 --- a/linuxthreads_db/td_thr_get_info.c +++ b/linuxthreads_db/td_thr_get_info.c @@ -19,6 +19,7 @@ Boston, MA 02111-1307, USA. */ #include <stddef.h> +#include <string.h> #include "thread_dbP.h" @@ -66,6 +67,8 @@ td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) infop->ti_lid = pds.p_pid; infop->ti_ta_p = th->th_ta_p; infop->ti_startfunc = pds.p_start_args.start_routine; + memcpy (&infop->ti_events, &pds.p_eventbuf.eventmask, + sizeof (td_thr_events_t)); return TD_OK; } diff --git a/linuxthreads_db/td_thr_set_event.c b/linuxthreads_db/td_thr_set_event.c index e6b6cbc862..583a2f8042 100644 --- a/linuxthreads_db/td_thr_set_event.c +++ b/linuxthreads_db/td_thr_set_event.c @@ -28,14 +28,29 @@ td_thr_set_event (th, event) const td_thrhandle_t *th; td_thr_events_t *event; { + td_thr_events_t old_event; + int i; + LOG (__FUNCTION__); /* Write the new value into the thread data structure. */ + if (ps_pdread (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Or the new bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] |= event->event_bits[i]; + + /* Write the new value into the thread data structure. */ if (ps_pdwrite (th->th_ta_p->ph, ((char *) th->th_unique + offsetof (struct _pthread_descr_struct, p_eventbuf.eventmask)), - event, sizeof (td_thrhandle_t)) != PS_OK) + &old_event, sizeof (td_thrhandle_t)) != PS_OK) return TD_ERR; /* XXX Other error value? */ return TD_OK; diff --git a/linuxthreads_db/thread_db.h b/linuxthreads_db/thread_db.h index 8e33a06ee8..6301d7fa5f 100644 --- a/linuxthreads_db/thread_db.h +++ b/linuxthreads_db/thread_db.h @@ -331,10 +331,18 @@ extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, td_event_e __event, td_notify_t *__ptr); -/* Enable EVENT for all threads. */ +/* Enable EVENT in global mask. */ extern td_err_e td_ta_set_event (const td_thragent_t *__ta, td_thr_events_t *__event); +/* Disable EVENT in global mask. */ +extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Return information about last event. */ +extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, + td_event_msg_t *msg); + /* Set suggested concurrency level for process associated with TA. */ extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); diff --git a/linuxthreads_db/thread_dbP.h b/linuxthreads_db/thread_dbP.h index 5c7fcde28a..60921834d9 100644 --- a/linuxthreads_db/thread_dbP.h +++ b/linuxthreads_db/thread_dbP.h @@ -41,6 +41,12 @@ struct td_thragent /* Pointer to the `__pthread_threads_events' variable in the target. */ psaddr_t pthread_threads_eventsp; + + /* Pointer to the `__pthread_last_event' variable in the target. */ + psaddr_t pthread_last_event; + + /* Pointer to the `__pthread_handles_num' variable. */ + psaddr_t pthread_handles_num; }; |