about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1999-11-03 06:13:09 +0000
committerUlrich Drepper <drepper@redhat.com>1999-11-03 06:13:09 +0000
commitab86fbb1d2866df567219904982dac61751808e5 (patch)
tree7ef290b73205d2a02ca808b585984d6c562857b0
parentdbd3e8629f6efb51bcddbd9e85ab87c0dd95a6ee (diff)
downloadglibc-ab86fbb1d2866df567219904982dac61751808e5.tar.gz
glibc-ab86fbb1d2866df567219904982dac61751808e5.tar.xz
glibc-ab86fbb1d2866df567219904982dac61751808e5.zip
Update.
	* 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.
-rw-r--r--linuxthreads/ChangeLog6
-rw-r--r--linuxthreads/internals.h3
-rw-r--r--linuxthreads/join.c1
-rw-r--r--linuxthreads/manager.c5
-rw-r--r--linuxthreads_db/ChangeLog21
-rw-r--r--linuxthreads_db/Makefile4
-rw-r--r--linuxthreads_db/td_ta_clear_event.c49
-rw-r--r--linuxthreads_db/td_ta_event_getmsg.c124
-rw-r--r--linuxthreads_db/td_ta_new.c20
-rw-r--r--linuxthreads_db/td_ta_set_event.c14
-rw-r--r--linuxthreads_db/td_ta_thr_iter.c110
-rw-r--r--linuxthreads_db/td_thr_clear_event.c35
-rw-r--r--linuxthreads_db/td_thr_get_info.c3
-rw-r--r--linuxthreads_db/td_thr_set_event.c17
-rw-r--r--linuxthreads_db/thread_db.h10
-rw-r--r--linuxthreads_db/thread_dbP.h6
16 files changed, 366 insertions, 62 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 6d00c17699..a670e9f93a 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -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.
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index 531b0424d8..f9eba6b94c 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -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)
diff --git a/linuxthreads/join.c b/linuxthreads/join.c
index a2c8b20ca2..71db541391 100644
--- a/linuxthreads/join.c
+++ b/linuxthreads/join.c
@@ -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();
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index 3b70097232..21a3f6875f 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -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();
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;
 };