This is the mail archive of the gdb@sourceware.cygnus.com mailing list for the GDB project.


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

Re: uw-threads issues


>There are currently two failure cases that are interesting.

There've been several bug fixes in uw-thread.c since the version Jason
emailed you.  Those changes should show up in the gdb snapshot
shortly, but in the meantime, could you try the appended patch?

Nick Duffek
nsd@cygnus.com

--- uw-thread.c	2000/01/07 20:28:50
+++ uw-thread.c	2000/01/14 04:18:30
@@ -1,5 +1,5 @@
-/* Low level interface for debugging UnixWare threads for GDB, the GNU 
-   debugger.
+/* Low level interface for debugging UnixWare user-mode threads for
+   GDB, the GNU debugger.
 
    Copyright 1999, 2000 Free Software Foundation, Inc.
 
@@ -20,6 +20,82 @@
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+
+/* Like many systems, UnixWare implements two classes of threads:
+   kernel-mode threads, which are scheduled by the kernel; and
+   user-mode threads, which are scheduled by a library.  UnixWare
+   calls these two classes lightweight processes (LWPs) and threads,
+   respectively.
+
+   This module deals with user-mode threads.  It calls procfs_ops
+   functions to deal with LWPs and processes and core_ops functions to
+   deal with core files.
+
+   As of this writing, the user-mode thread debugging interface is not
+   documented beyond the comments in <thread.h>.  The following
+   description has been gleaned from experience and from information
+   provided by SCO.
+
+   libthread.so, against which all UnixWare user-mode thread programs
+   link, provides a global thread_debug structure named _thr_debug.
+   It has three fields:
+
+     (1) thr_map is a pointer to a pointer to an element of a
+	 thread_map ring.  A thread_map contains a single thread's id
+	 number, state, LWP pointer, recent register state, and other
+	 useful information.
+
+     (2) thr_brk is a pointer to a stub function that libthread.so
+	 calls when it changes a thread's state, e.g. by creating it,
+	 switching it to an LWP, or causing it to exit.
+
+     (3) thr_debug_on controls whether libthread.so calls thr_brk().
+
+   Debuggers are able to track thread activity by setting a private
+   breakpoint on thr_brk() and setting thr_debug_on to 1.
+
+   thr_brk() receives two arguments:
+
+     (1) a pointer to a thread_map describing the thread being
+	 changed; and
+
+     (2) an enum thread_change specifying one of the following
+	 changes:
+
+	 invalid		 unknown
+	 thread_create		 thread has just been created
+	 thread_exit		 thread has just exited
+	 switch_begin		 thread will be switched to an LWP
+	 switch_complete	 thread has been switched to an LWP
+	 cancel_complete	 thread wasn't switched to an LWP
+	 thread_suspend		 thread has been thr_suspend()ed
+	 thread_suspend_pending	 thread will be thr_suspend()ed
+	 thread_continue	 thread has been thr_continue()d
+
+   The thread_map argument to thr_brk() is NULL under the following
+   circumstances:
+
+     - The main thread is being acted upon.  The main thread always
+       has id 1, so its thread_map is easy to find by scanning through
+       _thr_debug.thr_map.
+
+     - A "switch_complete" change is occurring, which means that the
+       thread specified in the most recent "switch_begin" change has
+       moved to an LWP.
+
+     - A "cancel_complete" change is occurring, which means that the
+       thread specified in the most recent "switch_begin" change has
+       not moved to an LWP after all.
+
+     - A spurious "switch_begin" change is occurring after a
+       "thread_exit" change.
+
+   Between switch_begin and switch_complete or cancel_complete, the
+   affected thread's LWP pointer is not reliable.  It is possible that
+   other parts of the thread's thread_map are also unreliable during
+   that time. */
+
+
 #include "defs.h"
 #include "gdbthread.h"
 #include "target.h"
@@ -38,22 +114,9 @@
 
 
 /*
- * Private thread data for the thread_info struct.
- */
-struct private_thread_info {
-  int stable;		/* 0 if libthread.so is modifying thread map */
-  int thrid;		/* thread id assigned by libthread.so */
-  int lwpid;		/* thread's lwp if .stable, 0 means no lwp */
-  CORE_ADDR mapp;	/* address of thread's map structure */
-};
-
-/* Tell procfs.c that we are taking over!  */
-extern int procfs_suppress_run;
-
-/*
  * Whether to emit debugging output.
  */
-#define DEBUG 1
+#define DEBUG 0
 
 /*
  * Default debugging output file, overridden by envvar UWTHR_DEBUG.
@@ -63,7 +126,7 @@
 /*
  * #if DEBUG, write string S to the debugging output channel.
  */
-#ifndef DEBUG
+#if !DEBUG
 # define DBG(fmt_and_args)
 # define DBG2(fmt_and_args)
 #else
@@ -89,11 +152,11 @@
  *
  * Otherwise, issue an error message and return nonlocally.
  */
-#define CALL_BASE(call)			\
-do {					\
-  if (!lwp_infpid())			\
-    error ("uw-thread: no lwp");	\
-  CALL_BASE_1 (call);			\
+#define CALL_BASE(call)					\
+do {							\
+  if (!lwp_infpid ())					\
+    error ("uw-thread: "__FUNCTION__": no lwp");	\
+  CALL_BASE_1 (call);					\
 } while (0)
 
 /*
@@ -102,7 +165,7 @@
  */
 #define TRY_BASE(call, called)		\
 do {					\
-  if ((*(called) = lwp_infpid()))	\
+  if ((*(called) = lwp_infpid ()))	\
     CALL_BASE_1 (call);			\
 } while (0)
 
@@ -115,10 +178,23 @@
   CORE_ADDR mapp;
 } iter_t;
 
+/*
+ * Private thread data for the thread_info struct.
+ */
+struct private_thread_info {
+  int stable;		/* 0 if libthread.so is modifying thread map */
+  int thrid;		/* thread id assigned by libthread.so */
+  int lwpid;		/* thread's lwp if .stable, 0 means no lwp */
+  CORE_ADDR mapp;	/* address of thread's map structure */
+};
+
 
 /* procfs.c's target-specific operations. */
 extern struct target_ops procfs_ops;
 
+/* Flag to prevent procfs.c from starting inferior processes. */
+extern int procfs_suppress_run;
+
 /* This module's target-specific operations. */
 static struct target_ops uw_thread_ops;
 
@@ -334,8 +410,8 @@
 static void
 deactivate_uw_thread (void)
 {
-  unpush_target (&uw_thread_ops);
   uw_thread_active = 0;
+  unpush_target (&uw_thread_ops);
 }
 
 /*
@@ -362,15 +438,13 @@
 }
 
 /*
- * If a thread is associated with lwp id LWPID, return the corresponding
- * member of the global thread list; otherwise, return null.
+ * find_thread_lwp() callback: return whether TP describes a thread
+ * associated with lwp id DATA.
  */
-
-/* Iterator callback function, returns true if match.  */
 static int
 find_thread_lwp_callback (struct thread_info *tp, void *data)
 {
-  int lwpid = (int) data;
+  int lwpid = (int)data;
 
   if (!ISTID (tp->pid))
     return 0;
@@ -383,13 +457,14 @@
   return 1;
 }
 
+/*
+ * If a thread is associated with lwp id LWPID, return the corresponding
+ * member of the global thread list; otherwise, return null.
+ */
 static struct thread_info *
 find_thread_lwp (int lwpid)
 {
-  /* The thread iterator will return the first thread_info 
-     for which the callback returns true.  */
-  return iterate_over_threads (find_thread_lwp_callback, 
-			       (void *) lwpid);
+  return iterate_over_threads (find_thread_lwp_callback, (void *)lwpid);
 }
 
 /*
@@ -460,17 +535,10 @@
     error ("failed to create new thread structure");
 
   newthread->private = xmalloc (sizeof (struct private_thread_info));
-  /*
-   * newthread has been added to the global thread list by add_thread().
-   * Set fields private to this module.
-   */
-  if (ISTID (pid))
-    {
-      newthread->private->stable = 1;
-      newthread->private->thrid  = thrid;
-      newthread->private->lwpid  = lwpid;
-      newthread->private->mapp   = mapp;
-    }
+  newthread->private->stable = 1;
+  newthread->private->thrid = thrid;
+  newthread->private->lwpid = lwpid;
+  newthread->private->mapp = mapp;
 
   if (target_has_execution)
     printf_unfiltered ("[New %s]\n", target_pid_to_str (pid));
@@ -539,7 +607,7 @@
 static void
 uw_thread_detach (char *args, int from_tty)
 {
-  deactivate_uw_thread();
+  deactivate_uw_thread ();
   base_ops.to_detach (args, from_tty);
 }
 
@@ -557,9 +625,9 @@
 }
 
 /*
- * Return whether the trap we just received from lwp PID was due to a
- * breakpoint on the libthread.so debugging stub, updating data
- * structures accordingly if so.
+ * If the trap we just received from lwp PID was due to a breakpoint
+ * on the libthread.so debugging stub, update this module's state
+ * accordingly.
  */
 static void
 libthread_stub (int pid)
@@ -578,20 +646,20 @@
   /* Retrieve stub args. */
   sp = read_register_pid (SP_REGNUM, pid);
   if (!base_ops.to_xfer_memory (sp + SP_ARG0, (char *)&mapp,
-				 sizeof (mapp), 0, &base_ops))
+				sizeof (mapp), 0, &base_ops))
     goto err;
   if (!base_ops.to_xfer_memory (sp + SP_ARG0 + sizeof (mapp), (char *)&change,
-				 sizeof (change), 0, &base_ops))
+				sizeof (change), 0, &base_ops))
     goto err;
 
   /* create_inferior() may not have finished yet, so notice the main
      thread to ensure that it's displayed first by add_thread(). */
-  mapp_main = find_main();
+  mapp_main = find_main ();
 
   /* Notice thread creation, deletion, or stability change. */
   switch (change) {
   case tc_switch_begin:
-    if (!mapp)				/* null means main thread */
+    if (!mapp)				/* usually means main thread */
       mapp = mapp_main;
     /* fall through */
 
@@ -617,6 +685,8 @@
     case tc_thread_exit:		/* thread has exited */
       printf_unfiltered ("[Exited %s]\n", target_pid_to_str (tid));
       delete_thread (tid);
+      if (tid == inferior_pid)
+	inferior_pid = pid;
       break;
 
     case tc_switch_begin:		/* lwp is switching threads */
@@ -733,7 +803,7 @@
 static void
 uw_thread_prepare_to_store (void)
 {
-  CALL_BASE (base_ops.to_prepare_to_store());
+  CALL_BASE (base_ops.to_prepare_to_store ());
 }
 
 /*
@@ -744,10 +814,13 @@
 static void
 uw_thread_create_inferior (char *exec_file, char *allargs, char **env)
 {
+  if (uw_thread_active)
+    deactivate_uw_thread ();
+
   procfs_ops.to_create_inferior (exec_file, allargs, env);
   if (uw_thread_active)
     {
-      find_main();
+      find_main ();
       thr_infpid (NULL);
     }
 }
@@ -758,7 +831,7 @@
 static void
 uw_thread_kill (void)
 {
-  base_ops.to_kill();
+  base_ops.to_kill ();
 }
 
 /*
@@ -767,9 +840,9 @@
 static void
 uw_thread_mourn_inferior (void)
 {
-  remove_thread_event_breakpoints();
-  deactivate_uw_thread();
-  base_ops.to_mourn_inferior();
+  remove_thread_event_breakpoints ();
+  deactivate_uw_thread ();
+  base_ops.to_mourn_inferior ();
 }
 
 /*
@@ -799,17 +872,13 @@
 
 /*
  * Add to the thread list any threads and lwps it doesn't already contain.
- *
- * This is useful for a program's first thread, which doesn't generate a
- * tc_thread_create stub call, and for core file debugging.
  */
 static void
 uw_thread_find_new_threads (void)
 {
   CALL_BASE (if (base_ops.to_find_new_threads)
-	       base_ops.to_find_new_threads());
-  if (procfs_suppress_run)
-    notice_threads();
+	       base_ops.to_find_new_threads ());
+  notice_threads ();
 }
 
 /*
@@ -820,18 +889,15 @@
 uw_thread_pid_to_str (int pid)
 {
 #define FMT "Thread %d"
-  static char buf[sizeof(FMT) + 3 * sizeof(pid)];
-
-  if (!procfs_suppress_run)
-    return procfs_ops.to_pid_to_str (pid);
+  static char buf[sizeof (FMT) + 3 * sizeof (pid)];
 
   if (!ISTID (pid))
     /* core_ops says "process foo", so call procfs_ops explicitly. */
     return procfs_ops.to_pid_to_str (pid);
 
   sprintf (buf, FMT, TIDGET (pid));
-  return buf;
 #undef FMT
+  return buf;
 }
 
 /*
@@ -881,13 +947,13 @@
 }
 
 /*
- * Check whether libthread.so has been loaded, and if so, try to initialize
- * user-space thread debugging support.  Return success.
+ * Check whether libthread.so has just been loaded, and if so, try to
+ * initialize user-space thread debugging support.
  *
  * libthread.so loading happens while (a) an inferior process is being
  * started by procfs and (b) a core image is being loaded.
  *
- * This function may be called with uw_thread_active == 0.
+ * This function often gets called with uw_thread_active == 0.
  */
 static void
 libthread_init (void)
@@ -930,7 +996,7 @@
   if (!target_has_execution)
 
     /* Locate threads in core file. */
-    notice_threads();
+    notice_threads ();
 
   else
     {
@@ -942,7 +1008,7 @@
       /* Activate the stub function. */
       onp = (CORE_ADDR)&((struct thread_debug *)thr_debug_addr)->thr_debug_on;
       if (!base_ops.to_xfer_memory ((CORE_ADDR)onp, (char *)&one,
-				     sizeof (one), 1, &base_ops))
+				    sizeof (one), 1, &base_ops))
 	{
 	  delete_breakpoint (b);
 	  goto err;
@@ -955,8 +1021,8 @@
   return;
 
  err:
-  error ("uw-thread: error initializing thread debugging\n");
-  deactivate_uw_thread();
+  warning ("uw-thread: unable to initialize user-mode thread debugging\n");
+  deactivate_uw_thread ();
 }
 
 /*
@@ -968,19 +1034,17 @@
  * If OBJFILE is null, libthread.so has gone away, so stop debugging
  * user-mode threads.
  *
- * This function may be called with uw_thread_active == 0.
+ * This function often gets called with uw_thread_active == 0.
  */
 static void
 uw_thread_new_objfile (struct objfile *objfile)
 {
-  if (procfs_suppress_run)
-    {
-      if (objfile)
-	libthread_init();
+  if (objfile)
+    libthread_init ();
 
-      else if (uw_thread_active)
-	deactivate_uw_thread();
-    }
+  else if (uw_thread_active)
+    deactivate_uw_thread ();
+
   if (target_new_objfile_chain)
     target_new_objfile_chain (objfile);
 }
@@ -1020,12 +1084,12 @@
 void
 _initialize_uw_thread (void)
 {
-  init_uw_thread_ops();
+  init_uw_thread_ops ();
   add_target (&uw_thread_ops);
 
   procfs_suppress_run = 1;
 
   /* Notice when libthread.so gets loaded. */
   target_new_objfile_chain = target_new_objfile_hook;
-  target_new_objfile_hook  = uw_thread_new_objfile;
+  target_new_objfile_hook = uw_thread_new_objfile;
 }

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