[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Debugging MT programs (slink) ?



cc: to the libc6 maintainer is set.

debugging multithreaded applications is only possible, if the glibc is also
compiled with a patch by the opengroup people. gdb already contains the
necessary patch.

however i tried on two systems with debian 2.0 or 2.1, and was not able to
recompile the libc6 package (2.1) or without breaking c++ applications(2.0).

tha patch is attached (it's not so big).

request to the libc6 maintainer : could you please compile a libc6 with this
patch ? itßs know to be stable (i had a machine with 2.0.4 and this patch
running for months without problems (debian 2.0)). maybe you can put the
package into experimental, so people can try ...

regards, andreas
---
diff -ru glibc-2.0.6-ORIG/linuxthreads/internals.h glibc-2.0.6/linuxthreads/internals.h
--- glibc-2.0.6-ORIG/linuxthreads/internals.h	Mon Dec  8 05:39:54 1997
+++ glibc-2.0.6/linuxthreads/internals.h	Tue Apr 28 20:15:36 1998
@@ -97,7 +97,7 @@
 struct pthread_request {
   pthread_descr req_thread;     /* Thread doing the request */
   enum {                        /* Request kind */
-    REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT
+    REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, REQ_DEBUG
   } req_kind;
   union {                       /* Arguments for request */
     struct {                    /* For REQ_CREATE: */
@@ -247,6 +247,8 @@
 #define ASSERT(x)
 #define MSG(msg,arg...)
 #endif
+
+extern volatile int __pthread_threads_debug;
 
 /* Internal global functions */
 
diff -ru glibc-2.0.6-ORIG/linuxthreads/manager.c glibc-2.0.6/linuxthreads/manager.c
--- glibc-2.0.6-ORIG/linuxthreads/manager.c	Mon Dec  8 05:19:54 1997
+++ glibc-2.0.6/linuxthreads/manager.c	Thu Apr 30 13:43:01 1998
@@ -37,6 +37,14 @@
 struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
 { { 0, &__pthread_initial_thread}, /* All NULLs */ };
 
+/* # active entries in __pthread_handles array (used for library debugging) */
+
+volatile int __pthread_handles_num = 1;
+
+/* Use debugger additional actions for thread creation */
+
+volatile int __pthread_threads_debug = 0;
+
 /* 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. */
@@ -86,10 +94,16 @@
 #ifdef INIT_THREAD_SELF
   INIT_THREAD_SELF(&__pthread_manager_thread);
 #endif
-  /* Block all signals except PTHREAD_SIG_RESTART */
+  /* Block all signals except PTHREAD_SIG_RESTART, PTHREAD_SIG_CANCEL
+     and SIGTRAP */
   sigfillset(&mask);
   sigdelset(&mask, PTHREAD_SIG_RESTART);
+  sigdelset(&mask, PTHREAD_SIG_CANCEL);	/* for debugging new threads */
+  sigdelset(&mask, SIGTRAP);		/* for debugging purposes */
   sigprocmask(SIG_SETMASK, &mask, NULL);
+  /* Synchronize debugging of the thread manager */
+  n = __libc_read(reqfd, (char *)&request, sizeof(request));
+  ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
   /* Enter server loop */
   while(1) {
     FD_ZERO(&readfds);
@@ -136,6 +150,11 @@
           return 0;
         }
         break;
+      case REQ_DEBUG:
+	if (__pthread_threads_debug)
+	  raise(PTHREAD_SIG_CANCEL); /* Make debugger aware of new thread */
+        restart(request.req_thread);
+        break;
       }
     }
   }
@@ -147,6 +166,7 @@
 {
   pthread_descr self = (pthread_descr) arg;
   void * outcome;
+  struct pthread_request request;
   /* Initialize special thread_self processing, if any.  */
 #ifdef INIT_THREAD_SELF
   INIT_THREAD_SELF(self);
@@ -161,6 +181,13 @@
   if (self->p_start_args.schedpolicy != SCHED_OTHER)
     __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy,
                          &self->p_start_args.schedparam);
+  /* Make debugger aware of new threads */
+  if (__pthread_threads_debug) {
+    request.req_thread = self;
+    request.req_kind = REQ_DEBUG;
+    __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
+    suspend(self);
+  }
   /* Run the thread code */
   outcome = self->p_start_args.start_routine(self->p_start_args.arg);
   /* Exit with the given return value */
@@ -191,6 +218,7 @@
     /* It seems part of this segment is already mapped. Try the next. */
   }
   /* Allocate new thread identifier */
+  __pthread_handles_num++;
   pthread_threads_counter += PTHREAD_THREADS_MAX;
   new_thread_id = sseg + pthread_threads_counter;
   /* Initialize the thread descriptor */
@@ -248,6 +276,7 @@
     munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
            INITIAL_STACK_SIZE);
     __pthread_handles[sseg].h_descr = NULL;
+    __pthread_handles_num--;
     return errno;
   }
   /* Insert new thread in doubly linked list of active threads */
@@ -274,6 +303,7 @@
   acquire(&handle->h_spinlock);
   handle->h_descr = NULL;
   release(&handle->h_spinlock);
+  __pthread_handles_num--;
   /* If initial thread, nothing to free */
   if (th == &__pthread_initial_thread) return;
   /* Free the stack and thread descriptor area */
diff -ru glibc-2.0.6-ORIG/linuxthreads/pthread.c glibc-2.0.6/linuxthreads/pthread.c
--- glibc-2.0.6-ORIG/linuxthreads/pthread.c	Mon Dec  8 05:25:24 1997
+++ glibc-2.0.6/linuxthreads/pthread.c	Thu Apr 30 13:40:33 1998
@@ -120,6 +120,18 @@
 int __pthread_exit_requested = 0;
 int __pthread_exit_code = 0;
 
+/* Internal values for library debugging future compatibility */
+
+const int __pthread_threads_max = PTHREAD_THREADS_MAX;
+const int __pthread_sig_restart = PTHREAD_SIG_RESTART;
+const int __pthread_sig_cancel = PTHREAD_SIG_CANCEL;
+
+const int __pthread_sizeof_handle = sizeof (struct pthread_handle_struct);
+const int __pthread_offsetof_descr = offsetof (struct pthread_handle_struct,
+					       h_descr);
+const int __pthread_offsetof_pid = offsetof (struct _pthread_descr_struct,
+					     p_pid);
+
 /* Forward declarations */
 
 static void pthread_exit_process(int retcode, void *arg);
@@ -206,6 +218,8 @@
     __pthread_manager_request = -1;
     return -1;
   }
+  /* Set pid field of the thread manager. */
+  __pthread_manager_thread.p_pid = __pthread_manager_pid;
   return 0;
 }
 
@@ -217,7 +231,14 @@
   pthread_descr self = thread_self();
   struct pthread_request request;
   if (__pthread_manager_request < 0) {
-    if (pthread_initialize_manager() < 0) return EAGAIN;
+    if (pthread_initialize_manager() < 0)
+      return EAGAIN;
+    if (__pthread_threads_debug)
+      raise(PTHREAD_SIG_CANCEL); /* Make debugger aware of new thread manager */
+    /* Synchronize debugging of the thread manager */
+    request.req_thread = self;
+    request.req_kind = REQ_DEBUG;
+    __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
   }
   request.req_thread = self;
   request.req_kind = REQ_CREATE;
@@ -327,13 +348,24 @@
 }
 
 /* The handler for the CANCEL signal checks for cancellation
-   (in asynchronous mode) and for process-wide exit and exec requests. */
+   (in asynchronous mode), for process-wide exit, exec requests
+   and for new thread debugging. */
 
 static void pthread_handle_sigcancel(int sig)
 {
   pthread_descr self = thread_self();
   sigjmp_buf * jmpbuf;
 
+  if (self == &__pthread_manager_thread) {
+    /* On reception of a REQ_DEBUG request (sent by new threads created to
+       the thread manager under debugging mode), the thread manager throws
+       PTHREAD_SIG_CANCEL to itself. The debugger (if active) intercepts
+       this signal, takes into account new threads and continue execution
+       of the thread manager by propagating the signal because it doesn't
+       know what it is specifically done for. In the current implementation,
+       the thread manager simply discards it. */
+    return;
+  }
   if (__pthread_exit_requested) {
     /* Main thread should accumulate times for thread manager and its
        children, so that timings for main thread account for all threads. */



Reply to: