* internals.h: Declare __pthread_last_event.
	* manager.c: Define __pthread_last_event.
	(pthread_handle_create): Set __pthread_last_event.
	(pthread_exited): Likewise.
	* join.c (pthread_exit): Likewise.
This commit is contained in:
Ulrich Drepper 1999-11-03 06:13:09 +00:00
parent dbd3e8629f
commit ab86fbb1d2
16 changed files with 358 additions and 54 deletions

View File

@ -1,5 +1,11 @@
1999-11-02 Ulrich Drepper <drepper@cygnus.com>
* internals.h: Declare __pthread_last_event.
* manager.c: Define __pthread_last_event.
(pthread_handle_create): Set __pthread_last_event.
(pthread_exited): Likewise.
* join.c (pthread_exit): Likewise.
* Makefile (libpthread-routines): Add events.
* events.c: New file.
* internals.h: Protect against multiple inclusion.

View File

@ -229,6 +229,9 @@ extern volatile int __pthread_threads_debug;
/* Globally enabled events. */
extern volatile td_thr_events_t __pthread_threads_events;
/* Pointer to descriptor of thread with last event. */
extern volatile pthread_descr __pthread_last_event;
/* Return the handle corresponding to a thread id */
static inline pthread_handle thread_handle(pthread_t id)

View File

@ -54,6 +54,7 @@ void pthread_exit(void * retval)
/* Yep, we have to signal the death. */
THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH);
THREAD_SETMEM(self, p_eventbuf.eventdata, self);
__pthread_last_event = self;
/* Now call the function to signal the event. */
__linuxthreads_death_event();

View File

@ -55,6 +55,9 @@ volatile int __pthread_threads_debug;
/* Globally enabled events. */
volatile td_thr_events_t __pthread_threads_events;
/* Pointer to thread descriptor with last event. */
volatile pthread_descr __pthread_last_event;
/* Mapping from stack segment to thread descriptor. */
/* Stack segment numbers are also indices into the __pthread_handles array. */
/* Stack segment number 0 is reserved for the initial thread. */
@ -422,6 +425,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
already scheduled when we send the event. */
new_thread->p_eventbuf.eventdata = new_thread;
new_thread->p_eventbuf.eventnum = TD_CREATE;
__pthread_last_event = new_thread;
/* Now call the function which signals the event. */
__linuxthreads_create_event ();
@ -523,6 +527,7 @@ static void pthread_exited(pid_t pid)
/* Yep, we have to signal the death. */
th->p_eventbuf.eventnum = TD_DEATH;
th->p_eventbuf.eventdata = th;
__pthread_last_event = th;
/* Now call the function to signal the event. */
__linuxthreads_reap_event();

View File

@ -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.

View File

@ -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))

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
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;
if (ps_pdread (ta->ph, handles, &phc,
sizeof (struct pthread_handle_struct)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
/* First count this active thread. */
--num;
if (phc.h_descr != NULL)
{
struct _pthread_descr_struct pds;
td_thrhandle_t th;
if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr)
!= PS_OK)
return TD_ERR; /* XXX Other error value? */
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;
/* 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. */
/* 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;
/* 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;
/* 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;
/* 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;
}
}
/* 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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
};