This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: Serialize calls to libthread_db event notification functions for NPTL


When event notification is enabled using libthread_db, libpthread.so calls
predefined functions when the corresponding events occur.  The only two
events supported in NPTL are thread creation and (normal) thread death.

In LinuxThreads, the creation event was signalled by the manager thread.
Therefore it was inherently serialized.  This allows gdbserver to avoid
stopping all threads when it sees a thread creation event.  GDB doesn't
take advantage of this yet, but may someday.

The problem that normally causes a debugger to stop all threads is
how to get back out of the event notification function.  We need to
execute the instruction that was shadowed by the breakpoint, but
we don't want any other threads to sweep past us while the
breakpoint is removed, or be otherwise caught up in the code modification
involved in a breakpoint.  So we stop threads, remove the breakpoint,
single step, and reinsert the breakpoint.

There's very few alternatives to this.  You can simulate the instruction in
question and manually advance the PC; or you can use hardware breakpoint
registers, which are per-thread - but scarce, or unavailable on some
platforms.

Having to stop threads, of course, sucks.  Because signal delivery
is involved, some syscalls get interrupted and others restarted.  And
it scales badly.

This patch offers a compromise.  If and only if event reporting is enabled,
it adds mutexes around the calls to the event notification functions.  This
will change the program's behavior slightly when run under a debugger, but
less than having the debugger stop all threads would - and probably less
than the extra context switches of having a debugger attached, except on
many-CPU systems.

Is this acceptable?  If not, gdbserver will either have to stop threads
(much slower than this normally uncontested mutex), avoid event
notification entirely (difficult, because of compatibility with
LinuxThreads - LT's td_ta_map_lwp2thr does not work immediately after
the clone call), or attempt to simulate instructions under breakpoints.

2006-03-15  Daniel Jacobowitz  <dan@codesourcery.com>

	* pthread_create.c (start_thread): Use a mutex around the call to
	__nptl_death_event.
	* sysdeps/pthead/createthread.c (create_thread): Likewise for
	__nptl_create_event.

Index: glibc/nptl/pthread_create.c
===================================================================
--- glibc.orig/nptl/pthread_create.c	2006-03-09 16:02:14.000000000 -0500
+++ glibc/nptl/pthread_create.c	2006-03-15 16:52:30.000000000 -0500
@@ -293,8 +293,13 @@ start_thread (void *arg)
 							   pd, pd->nextevent));
 	    }
 
-	  /* Now call the function to signal the event.  */
+	  /* Now call the function which signals the event.  We
+	     serialize at this point to simplify debug agents which
+	     set a breakpoint at the event function.  */
+	  static pthread_mutex_t death_event_mutex = PTHREAD_MUTEX_INITIALIZER;
+	  pthread_mutex_lock (&death_event_mutex);
 	  __nptl_death_event ();
+	  pthread_mutex_unlock (&death_event_mutex);
 	}
     }
 
Index: glibc/nptl/sysdeps/pthread/createthread.c
===================================================================
--- glibc.orig/nptl/sysdeps/pthread/createthread.c	2006-03-09 16:01:23.000000000 -0500
+++ glibc/nptl/sysdeps/pthread/createthread.c	2006-03-15 16:52:50.000000000 -0500
@@ -206,8 +206,13 @@ create_thread (struct pthread *pd, const
 							   pd, pd->nextevent)
 		     != 0);
 
-	      /* Now call the function which signals the event.  */
+	      /* Now call the function which signals the event.  We
+		 serialize at this point to simplify debug agents
+		 which set a breakpoint at the event function.  */
+	      static pthread_mutex_t create_event_mutex = PTHREAD_MUTEX_INITIALIZER;
+	      pthread_mutex_lock (&create_event_mutex);
 	      __nptl_create_event ();
+	      pthread_mutex_unlock (&create_event_mutex);
 
 	      /* And finally restart the new thread.  */
 	      lll_unlock (pd->lock);


-- 
Daniel Jacobowitz
CodeSourcery


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]