* ser-e7kpc.c (e7000pc_setstopbits): New function.
[deliverable/binutils-gdb.git] / gdb / linux-thread.c
index 9f0a80713b4517fd8fee5fcafcad41cbff005ec4..054188dc6b4659aaad5c5ac14d11c2a8397eda3e 100644 (file)
@@ -47,18 +47,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
    linuxthreads package heavily relies on wait() synchronization to keep
    them correct.  */
 
+#include "defs.h"
 #include <sys/types.h> /* for pid_t */
 #include <sys/ptrace.h> /* for PT_* flags */
-#include <sys/wait.h> /* for WUNTRACED and __WCLONE flags */
+#include "gdb_wait.h" /* for WUNTRACED and __WCLONE flags */
 #include <signal.h> /* for struct sigaction and NSIG */
 #include <sys/utsname.h>
 
-#include "defs.h"
 #include "target.h"
 #include "inferior.h"
 #include "gdbcore.h"
 #include "gdbthread.h"
-#include "wait.h"
 #include "gdbcmd.h"
 #include "breakpoint.h"
 
@@ -115,7 +114,7 @@ static int *linuxthreads_wait_status;       /* wait array of status */
 static int linuxthreads_wait_last;     /* index of last valid elt in
                                           linuxthreads_wait_{pid,status} */
 
-static sigset_t linuxthreads_wait_mask;        /* sigset with SIGCHLD */
+static sigset_t linuxthreads_block_mask;  /* sigset without SIGCHLD */
 
 static int linuxthreads_step_pid;      /* current stepped pid */
 static int linuxthreads_step_signo;    /* current stepped target signal */
@@ -161,15 +160,22 @@ struct linuxthreads_signal {
 };
 
 struct linuxthreads_signal linuxthreads_sig_restart = {
-  "__pthread_sig_restart", 1, 0, 0, 0
+  "__pthread_sig_restart", 1, 0, 0, 0, 0
 };
 struct linuxthreads_signal linuxthreads_sig_cancel = {
-  "__pthread_sig_cancel", 1, 0, 0, 0
+  "__pthread_sig_cancel", 1, 0, 0, 0, 0
 };
 struct linuxthreads_signal linuxthreads_sig_debug = {
-  "__pthread_sig_debug", 0, 0, 0, 0
+  "__pthread_sig_debug", 0, 0, 0, 0, 0
 };
 
+/* Set by thread_db module when it takes over the thread_stratum. 
+   In that case we must:
+   a) refrain from turning on the debug signal, and
+   b) refrain from calling add_thread.  */
+
+int using_thread_db = 0;
+
 /* A table of breakpoint locations, one per PID.  */
 static struct linuxthreads_breakpoint {
   CORE_ADDR    pc;     /* PC of breakpoint */
@@ -199,8 +205,7 @@ static CORE_ADDR linuxthreads_breakpoint_addr;
 #endif
 /* Check to see if the given thread is alive.  */
 static int
-linuxthreads_thread_alive (pid)
-     int pid;
+linuxthreads_thread_alive (int pid)
 {
   errno = 0;
   return ptrace (PT_READ_U, pid, (PTRACE_ARG3_TYPE)0, 0) >= 0 || errno == 0;
@@ -224,9 +229,7 @@ linuxthreads_thread_alive (pid)
    our efforts to debug it, accept them with wait, but don't pass them
    through to PID.  Do pass all other signals through.  */   
 static int
-linuxthreads_find_trap (pid, stop)
-    int pid;
-    int stop;
+linuxthreads_find_trap (int pid, int stop)
 {
   int i;
   int rpid;
@@ -292,23 +295,37 @@ linuxthreads_find_trap (pid, stop)
     {
       /* Make sure that we'll find what we're looking for.  */
       if (!found_trap)
-       kill (pid, SIGTRAP);
+       {
+         kill (pid, SIGTRAP);
+       }
       if (!found_stop)
-       kill (pid, SIGSTOP);
+       {
+         kill (pid, SIGSTOP);
+       }
     }
                      
   /* Catch all status until SIGTRAP and optionally SIGSTOP show up.  */
   for (;;)
     {
+      /* resume the child every time... */
       child_resume (pid, 1, TARGET_SIGNAL_0);
 
+      /* loop as long as errno == EINTR:
+        waitpid syscall may be aborted due to GDB receiving a signal. 
+        FIXME: EINTR handling should no longer be necessary here, since
+        we now block SIGCHLD except in an explicit sigsuspend call.  */
+      
       for (;;)
        {
          rpid = waitpid (pid, &status, __WCLONE);
          if (rpid > 0)
-           break;
+           {
+             break;
+           }
          if (errno == EINTR)
-           continue;
+           {
+             continue;
+           }
 
          /* There are a few reasons the wait call above may have
             failed.  If the thread manager dies, its children get
@@ -320,9 +337,11 @@ linuxthreads_find_trap (pid, stop)
             2.0.36.  */
          rpid = waitpid (pid, &status, 0);
          if (rpid > 0)
-           break;
+           {
+             break;
+           }
          if (errno != EINTR)
-           perror_with_name ("waitpid");
+           perror_with_name ("find_trap/waitpid");
        }
 
       if (!WIFSTOPPED(status)) /* Thread has died */
@@ -336,39 +355,46 @@ linuxthreads_find_trap (pid, stop)
       else if (WSTOPSIG(status) != SIGSTOP)
        wstatus[last++] = status;
       else if (stop)
-       if (found_trap)
-         break;
-       else
-         found_stop = 1;
+       {
+         if (found_trap)
+           break;
+         else
+           found_stop = 1;
+       }
     }
 
   /* Resend any other signals we noticed to the thread, to be received
      when we continue it.  */
   while (--last >= 0)
-    kill (pid, WSTOPSIG(wstatus[last]));
+    {
+      kill (pid, WSTOPSIG(wstatus[last]));
+    }
 
   return 1;
 }
 
 /* Cleanup stub for save_inferior_pid.  */
 static void
-restore_inferior_pid (arg)
-    void *arg;
+restore_inferior_pid (void *arg)
 {
-  int pid = (int) arg;
-  inferior_pid = pid;
+  int *saved_pid_ptr = arg;
+  inferior_pid = *saved_pid_ptr;
+  free (arg);
 }
 
 /* Register a cleanup to restore the value of inferior_pid.  */
 static struct cleanup *
-save_inferior_pid ()
+save_inferior_pid (void)
 {
-  return make_cleanup (restore_inferior_pid, (void *) inferior_pid);
+  int *saved_pid_ptr;
+  
+  saved_pid_ptr = xmalloc (sizeof (int));
+  *saved_pid_ptr = inferior_pid;
+  return make_cleanup (restore_inferior_pid, saved_pid_ptr);
 }
 
 static void
-sigchld_handler (signo)
-    int signo;
+sigchld_handler (int signo)
 {
   /* This handler is used to get an EINTR while doing waitpid()
      when an event is received */
@@ -377,8 +403,7 @@ sigchld_handler (signo)
 /* Have we already collected a wait status for PID in the
    linuxthreads_wait bag?  */
 static int
-linuxthreads_pending_status (pid)
-    int pid;
+linuxthreads_pending_status (int pid)
 {
   int i;
   for (i = linuxthreads_wait_last; i >= 0; i--)
@@ -395,9 +420,7 @@ linuxthreads_pending_status (pid)
    in OBJFILE, so we complain if it's required, but not there.
    Return true iff things are okay.  */
 static int
-find_signal_var (sig, objfile)
-     struct linuxthreads_signal *sig;
-     struct objfile *objfile;
+find_signal_var (struct linuxthreads_signal *sig, struct objfile *objfile)
 {
   struct minimal_symbol *ms = lookup_minimal_symbol (sig->var, NULL, objfile);
 
@@ -423,8 +446,7 @@ find_signal_var (sig, objfile)
 }
 
 static int
-find_all_signal_vars (objfile)
-     struct objfile *objfile;
+find_all_signal_vars (struct objfile *objfile)
 {
   return (   find_signal_var (&linuxthreads_sig_restart, objfile)
          && find_signal_var (&linuxthreads_sig_cancel,  objfile)
@@ -438,8 +460,7 @@ static int complained_cannot_determine_thread_signal_number = 0;
    been initialized yet.  If it has, tell GDB to pass that signal
    through to the inferior silently.  */
 static void
-check_signal_number (sig)
-     struct linuxthreads_signal *sig;
+check_signal_number (struct linuxthreads_signal *sig)
 {
   int num;
 
@@ -474,9 +495,8 @@ check_signal_number (sig)
   sig->print = signal_print_update (target_signal_from_host (num), 0);
 }
 
-
-static void
-check_all_signal_numbers ()
+void
+check_all_signal_numbers (void)
 {
   /* If this isn't a LinuxThreads program, quit early.  */
   if (! linuxthreads_max)
@@ -495,6 +515,7 @@ check_all_signal_numbers ()
       sact.sa_handler = sigchld_handler;
       sigemptyset(&sact.sa_mask);
       sact.sa_flags = 0;
+
       if (linuxthreads_sig_debug.signal > 0)
        sigaction(linuxthreads_sig_cancel.signal, &sact, NULL);
       else
@@ -508,8 +529,7 @@ check_all_signal_numbers ()
    talking to an executable that uses LinuxThreads, so we clear the
    signal number and variable address too.  */
 static void
-restore_signal (sig)
-     struct linuxthreads_signal *sig;
+restore_signal (struct linuxthreads_signal *sig)
 {
   if (! sig->signal)
     return;
@@ -529,7 +549,7 @@ restore_signal (sig)
    talking to an executable that uses LinuxThreads, so we clear the
    signal number and variable address too.  */
 static void
-restore_all_signals ()
+restore_all_signals (void)
 {
   restore_signal (&linuxthreads_sig_restart);
   restore_signal (&linuxthreads_sig_cancel);
@@ -548,9 +568,7 @@ restore_all_signals ()
    If ALL is non-zero, process all threads.
    If ALL is zero, skip threads with pending status.  */
 static void
-iterate_active_threads (func, all)
-    void (*func)(int);
-    int all;
+iterate_active_threads (void (*func) (int), int all)
 {
   CORE_ADDR descr;
   int pid;
@@ -574,15 +592,13 @@ iterate_active_threads (func, all)
            (*func)(pid);
        }
     }
-
 }
 
 /* Insert a thread breakpoint at linuxthreads_breakpoint_addr.
    This is the worker function for linuxthreads_insert_breakpoint,
    which passes it to iterate_active_threads.  */
 static void
-insert_breakpoint (pid)
-    int pid;
+insert_breakpoint (int pid)
 {
   int j;
 
@@ -608,8 +624,7 @@ insert_breakpoint (pid)
    breakpoint if the thread's PC is pointing at the breakpoint being
    removed.  */
 static void
-remove_breakpoint (pid)
-    int pid;
+remove_breakpoint (int pid)
 {
   int j;
 
@@ -634,33 +649,40 @@ remove_breakpoint (pid)
 
 /* Kill a thread */
 static void
-kill_thread (pid)
-    int pid;
+kill_thread (int pid)
 {
   if (in_thread_list (pid))
-    ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0);
+    {
+      ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0);
+    }
   else
-    kill (pid, SIGKILL);
+    {
+      kill (pid, SIGKILL);
+    }
 }
 
 /* Resume a thread */
 static void
-resume_thread (pid)
-    int pid;
+resume_thread (int pid)
 {
   if (pid != inferior_pid
       && in_thread_list (pid)
       && linuxthreads_thread_alive (pid))
-    if (pid == linuxthreads_step_pid)
-      child_resume (pid, 1, linuxthreads_step_signo);
-    else
-      child_resume (pid, 0, TARGET_SIGNAL_0);
+    {
+      if (pid == linuxthreads_step_pid)
+       {
+         child_resume (pid, 1, linuxthreads_step_signo);
+       }
+      else
+       {
+         child_resume (pid, 0, TARGET_SIGNAL_0);
+       }
+    }
 }
 
 /* Detach a thread */
 static void
-detach_thread (pid)
-    int pid;
+detach_thread (int pid)
 {
   if (in_thread_list (pid) && linuxthreads_thread_alive (pid))
     {
@@ -673,47 +695,67 @@ detach_thread (pid)
     }
 }
 
+/* Attach a thread */
+void
+attach_thread (int pid)
+{
+  if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) != 0)
+    perror_with_name ("attach_thread");
+}
+
 /* Stop a thread */
 static void
-stop_thread (pid)
-    int pid;
+stop_thread (int pid)
 {
   if (pid != inferior_pid)
-    if (in_thread_list (pid))
-      kill (pid, SIGSTOP);
-    else if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) == 0)
-      {
-       if (!linuxthreads_attach_pending)
-         printf_unfiltered ("[New %s]\n", target_pid_to_str (pid));
-       add_thread (pid);
-       if (linuxthreads_sig_debug.signal)
-         /* After a new thread in glibc 2.1 signals gdb its existence,
-            it suspends itself and wait for linuxthreads_sig_restart,
-            now we can wake up it. */
-         kill (pid, linuxthreads_sig_restart.signal);
-      }
-    else
-      perror_with_name ("ptrace in stop_thread");
+    {
+      if (in_thread_list (pid))
+       {
+         kill (pid, SIGSTOP);
+       }
+      else if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) == 0)
+       {
+         if (!linuxthreads_attach_pending)
+           printf_filtered ("[New %s]\n", target_pid_to_str (pid));
+         add_thread (pid);
+         if (linuxthreads_sig_debug.signal)
+           {
+             /* After a new thread in glibc 2.1 signals gdb its existence,
+                it suspends itself and wait for linuxthreads_sig_restart,
+                now we can wake it up. */
+             kill (pid, linuxthreads_sig_restart.signal);
+           }
+       }
+      else
+       perror_with_name ("ptrace in stop_thread");
+    }
 }
 
 /* Wait for a thread */
 static void
-wait_thread (pid)
-    int pid;
+wait_thread (int pid)
 {
   int status;
   int rpid;
 
   if (pid != inferior_pid && in_thread_list (pid))
     {
+      /* loop as long as errno == EINTR:
+        waitpid syscall may be aborted if GDB receives a signal. 
+        FIXME: EINTR handling should no longer be necessary here, since
+        we now block SIGCHLD except during an explicit sigsuspend call. */
       for (;;)
        {
          /* Get first pid status.  */
          rpid = waitpid(pid, &status, __WCLONE);
          if (rpid > 0)
-           break;
+           {
+             break;
+           }
          if (errno == EINTR)
-           continue;
+           {
+             continue;
+           }
 
          /* There are two reasons this might have failed:
 
@@ -733,9 +775,11 @@ wait_thread (pid)
             didn't work.  */
          rpid = waitpid(pid, &status, 0);
          if (rpid > 0)
-           break;
+           {
+             break;
+           }
          if (errno != EINTR && linuxthreads_thread_alive (pid))
-           perror_with_name ("waitpid");
+           perror_with_name ("wait_thread/waitpid");
 
          /* the thread is dead.  */
          return;
@@ -751,8 +795,7 @@ wait_thread (pid)
 /* Walk through the linuxthreads handles in order to detect all
    threads and stop them */
 static void
-update_stop_threads (test_pid)
-    int test_pid;
+update_stop_threads (int test_pid)
 {
   struct cleanup *old_chain = NULL;
 
@@ -804,16 +847,17 @@ update_stop_threads (test_pid)
              if (!in_thread_list (test_pid))
                {
                  if (!linuxthreads_attach_pending)
-                   printf_unfiltered ("[New %s]\n",
-                                      target_pid_to_str (test_pid));
+                   printf_filtered ("[New %s]\n",
+                                    target_pid_to_str (test_pid));
                  add_thread (test_pid);
                  if (linuxthreads_sig_debug.signal
                      && inferior_pid == test_pid)
-                   /* After a new thread in glibc 2.1 signals gdb its
-                      existence, it suspends itself and wait for
-                      linuxthreads_sig_restart, now we can wake up
-                      it. */
-                   kill (test_pid, linuxthreads_sig_restart.signal);
+                   {
+                     /* After a new thread in glibc 2.1 signals gdb its
+                        existence, it suspends itself and wait for
+                        linuxthreads_sig_restart, now we can wake it up. */
+                     kill (test_pid, linuxthreads_sig_restart.signal);
+                   }
                }
            }
          iterate_active_threads (stop_thread, 0);
@@ -825,18 +869,32 @@ update_stop_threads (test_pid)
     do_cleanups (old_chain);
 }
 
-/* This routine is called whenever a new symbol table is read in, or when all
-   symbol tables are removed.  libpthread can only be initialized when it
-   finds the right variables in libpthread.so.  Since it's a shared library,
-   those variables don't show up until the library gets mapped and the symbol
-   table is read in.  */
+/* This routine is called whenever a new symbol table is read in, or
+   when all symbol tables are removed.  linux-thread event handling
+   can only be initialized when we find the right variables in
+   libpthread.so.  Since it's a shared library, those variables don't
+   show up until the library gets mapped and the symbol table is read
+   in.  */
+
+/* This new_objfile event is now managed by a chained function pointer. 
+ * It is the callee's responsability to call the next client on the chain.
+ */
+
+/* Saved pointer to previous owner of the new_objfile event. */
+static void (*target_new_objfile_chain) (struct objfile *);
 
 void
-linuxthreads_new_objfile (objfile)
-    struct objfile *objfile;
+linuxthreads_new_objfile (struct objfile *objfile)
 {
   struct minimal_symbol *ms;
 
+  /* Call predecessor on chain, if any.
+     Calling the new module first allows it to dominate, 
+     if it finds its compatible libraries.  */
+
+  if (target_new_objfile_chain)
+    target_new_objfile_chain (objfile);
+
   if (!objfile)
     {
       /* We're starting an entirely new executable, so we can no
@@ -847,17 +905,17 @@ linuxthreads_new_objfile (objfile)
       /* Indicate that we don't know anything's address any more.  */
       linuxthreads_max = 0;
 
-      return;
+      goto quit;
     }
 
   /* If we've already found our variables in another objfile, don't
      bother looking for them again.  */
   if (linuxthreads_max)
-    return;
+    goto quit;
 
   if (! lookup_minimal_symbol ("__pthread_initial_thread", NULL, objfile))
     /* This object file isn't the pthreads library.  */
-    return;
+    goto quit;
 
   if ((ms = lookup_minimal_symbol ("__pthread_threads_debug",
                                   NULL, objfile)) == NULL)
@@ -868,7 +926,7 @@ This program seems to use POSIX threads, but the thread library used\n\
 does not support debugging.  This may make using GDB difficult.  Don't\n\
 set breakpoints or single-step through code that might be executed by\n\
 any thread other than the main thread.");
-      return;
+      goto quit;
     }
   linuxthreads_debug = SYMBOL_VALUE_ADDRESS (ms);
 
@@ -882,7 +940,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_sizeof_handle");
-      return;
+      goto quit;
     }
 
   if ((ms = lookup_minimal_symbol ("__pthread_offsetof_descr",
@@ -894,7 +952,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_offsetof_descr");
-      return;
+      goto quit;
     }
         
   if ((ms = lookup_minimal_symbol ("__pthread_offsetof_pid",
@@ -906,11 +964,11 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_offsetof_pid");
-      return;
+      goto quit;
     }
 
   if (! find_all_signal_vars (objfile))
-    return;
+    goto quit;
 
   /* Read adresses of internal structures to access */
   if ((ms = lookup_minimal_symbol ("__pthread_handles",
@@ -919,7 +977,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_handles");
-      return;
+      goto quit;
     }
   linuxthreads_handles = SYMBOL_VALUE_ADDRESS (ms);
 
@@ -929,7 +987,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_handles_num");
-      return;
+      goto quit;
     }
   linuxthreads_num = SYMBOL_VALUE_ADDRESS (ms);
 
@@ -939,7 +997,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_manager_thread");
-      return;
+      goto quit;
     }
   linuxthreads_manager = SYMBOL_VALUE_ADDRESS (ms) + linuxthreads_offset_pid;
 
@@ -949,7 +1007,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_initial_thread");
-      return;
+      goto quit;
     }
   linuxthreads_initial = SYMBOL_VALUE_ADDRESS (ms) + linuxthreads_offset_pid;
 
@@ -964,7 +1022,7 @@ any thread other than the main thread.");
       fprintf_unfiltered (gdb_stderr,
                          "Unable to find linuxthreads symbol \"%s\"\n",
                          "__pthread_threads_max");
-      return;
+      goto quit;
     }
 
   /* Allocate gdb internal structures */
@@ -975,22 +1033,28 @@ any thread other than the main thread.");
   linuxthreads_breakpoint_zombie = (struct linuxthreads_breakpoint *)
     xmalloc (sizeof (struct linuxthreads_breakpoint) * (linuxthreads_max + 1));
 
-  if (inferior_pid && !linuxthreads_attach_pending)
+  if (inferior_pid && 
+      !linuxthreads_attach_pending && 
+      !using_thread_db)                /* suppressed by thread_db module */
     {
       int on = 1;
+
       target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on));
       linuxthreads_attach_pending = 1;
       update_stop_threads (inferior_pid);
       linuxthreads_attach_pending = 0;
     }
+
+  check_all_signal_numbers ();
+
+quit:
 }
 
 /* If we have switched threads from a one that stopped at breakpoint,
    return 1 otherwise 0.  */
 
 int
-linuxthreads_prepare_to_proceed (step)
-    int step;
+linuxthreads_prepare_to_proceed (int step)
 {
   if (!linuxthreads_max
       || !linuxthreads_manager_pid
@@ -1011,8 +1075,7 @@ linuxthreads_prepare_to_proceed (step)
 /* Convert a pid to printable form. */
 
 char *
-linuxthreads_pid_to_str (pid)
-    int pid;
+linuxthreads_pid_to_str (int pid)
 {
   static char buf[100];
 
@@ -1028,9 +1091,7 @@ linuxthreads_pid_to_str (pid)
    and wait for the trace-trap that results from attaching.  */
 
 static void
-linuxthreads_attach (args, from_tty)
-    char *args;
-    int from_tty;
+linuxthreads_attach (char *args, int from_tty)
 {
   if (!args)
     error_no_arg ("process-id to attach");
@@ -1039,7 +1100,7 @@ linuxthreads_attach (args, from_tty)
   linuxthreads_breakpoints_inserted = 1;
   linuxthreads_breakpoint_last = -1;
   linuxthreads_wait_last = -1;
-  linuxthreads_exit_status = __W_STOPCODE(0);
+  WSETSTOP (linuxthreads_exit_status, 0);
 
   child_ops.to_attach (args, from_tty);
 
@@ -1056,9 +1117,7 @@ linuxthreads_attach (args, from_tty)
    started via the normal ptrace (PTRACE_TRACEME).  */
 
 static void
-linuxthreads_detach (args, from_tty)
-    char *args;
-    int from_tty;
+linuxthreads_detach (char *args, int from_tty)
 {
   if (linuxthreads_max)
     {
@@ -1099,7 +1158,7 @@ linuxthreads_detach (args, from_tty)
          linuxthreads_find_trap (inferior_pid, 1);
 
          linuxthreads_wait_last = -1;
-         linuxthreads_exit_status = __W_STOPCODE(0);
+         WSETSTOP (linuxthreads_exit_status, 0);
        }
 
       linuxthreads_inferior_pid = 0;
@@ -1122,13 +1181,12 @@ linuxthreads_detach (args, from_tty)
    signal activated.  */
 
 static void
-linuxthreads_resume (pid, step, signo)
-    int pid;
-    int step;
-    enum target_signal signo;
+linuxthreads_resume (int pid, int step, enum target_signal signo)
 {
   if (!linuxthreads_max || stop_soon_quietly || linuxthreads_manager_pid == 0)
-    child_ops.to_resume (pid, step, signo);
+    {
+      child_ops.to_resume (pid, step, signo);
+    }
   else
     {
       int rpid;
@@ -1189,18 +1247,71 @@ linuxthreads_resume (pid, step, signo)
        }
 
       /* Resume initial thread. */
+      /* [unles it has a wait event pending] */
       if (!linuxthreads_pending_status (rpid))
-       child_ops.to_resume (rpid, step, signo);
+       {
+         child_ops.to_resume (rpid, step, signo);
+       }
+    }
+}
+
+/* Abstract out the child_wait functionality.  */
+int
+linux_child_wait (int pid, int *rpid, int *status)
+{
+  int save_errno;
+
+  /* Note: inftarg has these inside the loop. */
+  set_sigint_trap ();  /* Causes SIGINT to be passed on to the
+                          attached process. */
+  set_sigio_trap  ();
+
+  errno = save_errno = 0;
+  for (;;)
+    {
+      errno = 0;
+      *rpid = waitpid (pid, status, __WCLONE | WNOHANG);
+      save_errno = errno;
+
+      if (*rpid > 0)
+       {
+         /* Got an event -- break out */
+         break;
+       }
+      if (errno == EINTR)      /* interrupted by signal, try again */
+       {
+         continue;
+       }
+
+      errno = 0;
+      *rpid = waitpid (pid, status, WNOHANG);
+      if (*rpid > 0)
+       {
+         /* Got an event -- break out */
+         break;
+       }
+      if (errno == EINTR)
+       {
+         continue;
+       }
+      if (errno != 0 && save_errno != 0)
+       {
+         break;
+       }
+      sigsuspend(&linuxthreads_block_mask);
     }
+  clear_sigio_trap  ();
+  clear_sigint_trap ();
+
+  return errno ? errno : save_errno;
 }
 
+
 /* Wait for any threads to stop.  We may have to convert PID from a thread id
    to a LWP id, and vice versa on the way out.  */
 
 static int
-linuxthreads_wait (pid, ourstatus)
-     int pid;
-     struct target_waitstatus *ourstatus;
+linuxthreads_wait (int pid, struct target_waitstatus *ourstatus)
 {
   int status;
   int rpid;
@@ -1261,42 +1372,8 @@ linuxthreads_wait (pid, ourstatus)
       if (rpid == 0)
        {
          int save_errno;
-         sigset_t omask;
-
-         set_sigint_trap();    /* Causes SIGINT to be passed on to the
-                                  attached process. */
-         set_sigio_trap ();
-
-         sigprocmask(SIG_BLOCK, &linuxthreads_wait_mask, &omask);
-         for (;;)
-           {
-             rpid = waitpid (pid, &status, __WCLONE | WNOHANG);
-             if (rpid > 0)
-               break;
-             if (rpid == 0)
-               save_errno = 0;
-             else if (errno != EINTR)
-               save_errno = errno;
-             else
-               continue;
-
-             rpid = waitpid (pid, &status, WNOHANG);
-             if (rpid > 0)
-               break;
-             if (rpid < 0)
-               if (errno == EINTR)
-                 continue;
-               else if (save_errno != 0)
-                 break;
 
-             sigsuspend(&omask);
-           }
-         sigprocmask(SIG_SETMASK, &omask, NULL);
-
-         save_errno = errno;
-         clear_sigio_trap ();
-
-         clear_sigint_trap();
+         save_errno = linux_child_wait (pid, &rpid, &status);
 
          if (rpid == -1)
            {
@@ -1317,15 +1394,19 @@ linuxthreads_wait (pid, ourstatus)
                }
            }
 
-         /* Signals arrive in any order.  So get all signals until SIGTRAP
-            and resend previous ones to be held after.  */
+         /* We have now gotten a new event from waitpid above. */
+
+         /* Signals arrive in any order.  So get all signals until
+            SIGTRAP and resend previous ones to be held after.  */
          if (linuxthreads_max
              && !linuxthreads_breakpoints_inserted
              && WIFSTOPPED(status))
            if (WSTOPSIG(status) == SIGTRAP)
              {
                while (--last >= 0)
-                 kill (rpid, WSTOPSIG(wstatus[last]));
+                 {
+                   kill (rpid, WSTOPSIG(wstatus[last]));
+                 }
 
                /* insert negative zombie breakpoint */
                for (i = 0; i <= linuxthreads_breakpoint_last; i++)
@@ -1347,7 +1428,9 @@ linuxthreads_wait (pid, ourstatus)
                      if (wstatus[i] == status)
                        break;
                    if (i >= last)
-                     wstatus[last++] = status;
+                     {
+                       wstatus[last++] = status;
+                     }
                  }
                child_resume (rpid, 1, TARGET_SIGNAL_0);
                continue;
@@ -1364,10 +1447,16 @@ linuxthreads_wait (pid, ourstatus)
            {
              /* Skip SIGSTOP signals.  */
              if (!linuxthreads_pending_status (rpid))
-               if (linuxthreads_step_pid == rpid)
-                 child_resume (rpid, 1, linuxthreads_step_signo);
-               else
-                 child_resume (rpid, 0, TARGET_SIGNAL_0);
+               {
+                 if (linuxthreads_step_pid == rpid)
+                   {
+                     child_resume (rpid, 1, linuxthreads_step_signo);
+                   }
+                 else
+                   {
+                     child_resume (rpid, 0, TARGET_SIGNAL_0);
+                   }
+               }
              continue;
            }
 
@@ -1410,9 +1499,13 @@ linuxthreads_wait (pid, ourstatus)
                  write_pc_pid (linuxthreads_breakpoint_zombie[i].pc
                                - DECR_PC_AFTER_BREAK, rpid);
                  if (linuxthreads_step_pid == rpid)
-                   child_resume (rpid, 1, linuxthreads_step_signo);
+                   {
+                     child_resume (rpid, 1, linuxthreads_step_signo);
+                   }
                  else
-                   child_resume (rpid, 0, TARGET_SIGNAL_0);
+                   {
+                     child_resume (rpid, 0, TARGET_SIGNAL_0);
+                   }
                  continue;
                }
            }
@@ -1430,8 +1523,12 @@ linuxthreads_wait (pid, ourstatus)
       if (linuxthreads_attach_pending && !stop_soon_quietly)
         {
          int on = 1;
-         target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on));
-         update_stop_threads (rpid);
+         if (!using_thread_db)
+           {
+             target_write_memory (linuxthreads_debug, 
+                                  (char *) &on, sizeof (on));
+             update_stop_threads (rpid);
+           }
          linuxthreads_attach_pending = 0;
         }
 
@@ -1449,10 +1546,7 @@ linuxthreads_wait (pid, ourstatus)
 /* Fork an inferior process, and start debugging it with ptrace.  */
 
 static void
-linuxthreads_create_inferior (exec_file, allargs, env)
-    char *exec_file;
-    char *allargs;
-    char **env;
+linuxthreads_create_inferior (char *exec_file, char *allargs, char **env)
 {
   if (!exec_file && !exec_bfd)
     {
@@ -1465,7 +1559,7 @@ Use the \"file\" or \"exec-file\" command.");
   linuxthreads_breakpoints_inserted = 1;
   linuxthreads_breakpoint_last = -1;
   linuxthreads_wait_last = -1;
-  linuxthreads_exit_status = __W_STOPCODE(0);
+  WSETSTOP (linuxthreads_exit_status, 0);
   
   if (linuxthreads_max)
     linuxthreads_attach_pending = 1;
@@ -1473,23 +1567,30 @@ Use the \"file\" or \"exec-file\" command.");
   child_ops.to_create_inferior (exec_file, allargs, env);
 }
 
+void
+linuxthreads_discard_global_state (void)
+{
+  linuxthreads_inferior_pid = 0;
+  linuxthreads_breakpoint_pid = 0;
+  linuxthreads_step_pid = 0;
+  linuxthreads_step_signo = TARGET_SIGNAL_0;
+  linuxthreads_manager_pid = 0;
+  linuxthreads_initial_pid = 0;
+  linuxthreads_attach_pending = 0;
+  linuxthreads_max = 0;
+}
+
 /* Clean up after the inferior dies.  */
 
 static void
-linuxthreads_mourn_inferior ()
+linuxthreads_mourn_inferior (void)
 {
   if (linuxthreads_max)
     {
       int off = 0;
       target_write_memory (linuxthreads_debug, (char *)&off, sizeof (off));
 
-      linuxthreads_inferior_pid = 0;
-      linuxthreads_breakpoint_pid = 0;
-      linuxthreads_step_pid = 0;
-      linuxthreads_step_signo = TARGET_SIGNAL_0;
-      linuxthreads_manager_pid = 0;
-      linuxthreads_initial_pid = 0;
-      linuxthreads_attach_pending = 0;
+      linuxthreads_discard_global_state ();
       init_thread_list();           /* Destroy thread info */
     }
 
@@ -1501,7 +1602,7 @@ linuxthreads_mourn_inferior ()
 /* Kill the inferior process */
 
 static void
-linuxthreads_kill ()
+linuxthreads_kill (void)
 {
   int rpid;
   int status;
@@ -1543,12 +1644,18 @@ linuxthreads_kill ()
 
   /* Wait for all threads. */
   do
-    rpid = waitpid (-1, &status, __WCLONE | WNOHANG);
+    {
+      rpid = waitpid (-1, &status, __WCLONE | WNOHANG);
+    }
   while (rpid > 0 || errno == EINTR);
+  /* FIXME: should no longer need to handle EINTR here. */
 
   do
-    rpid = waitpid (-1, &status, WNOHANG);
+    {
+      rpid = waitpid (-1, &status, WNOHANG);
+    }
   while (rpid > 0 || errno == EINTR);
+  /* FIXME: should no longer need to handle EINTR here. */
 
   linuxthreads_mourn_inferior ();
 }
@@ -1556,9 +1663,7 @@ linuxthreads_kill ()
 /* Insert a breakpoint */
 
 static int
-linuxthreads_insert_breakpoint (addr, contents_cache)
-    CORE_ADDR addr;
-    char *contents_cache;
+linuxthreads_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
 {
   if (linuxthreads_max && linuxthreads_manager_pid != 0)
     {
@@ -1573,9 +1678,7 @@ linuxthreads_insert_breakpoint (addr, contents_cache)
 /* Remove a breakpoint */
 
 static int
-linuxthreads_remove_breakpoint (addr, contents_cache)
-    CORE_ADDR addr;
-    char *contents_cache;
+linuxthreads_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
 {
   if (linuxthreads_max && linuxthreads_manager_pid != 0)
     {
@@ -1590,13 +1693,14 @@ linuxthreads_remove_breakpoint (addr, contents_cache)
 /* Mark our target-struct as eligible for stray "run" and "attach" commands.  */
 
 static int
-linuxthreads_can_run ()
+linuxthreads_can_run (void)
 {
   return child_suppress_run;
 }
+
 \f
 static void
-init_linuxthreads_ops ()
+init_linuxthreads_ops (void)
 {
   linuxthreads_ops.to_shortname = "linuxthreads";
   linuxthreads_ops.to_longname  = "LINUX threads and pthread.";
@@ -1613,18 +1717,27 @@ init_linuxthreads_ops ()
   linuxthreads_ops.to_create_inferior   = linuxthreads_create_inferior;
   linuxthreads_ops.to_mourn_inferior    = linuxthreads_mourn_inferior;
   linuxthreads_ops.to_thread_alive      = linuxthreads_thread_alive;
+  linuxthreads_ops.to_pid_to_str        = linuxthreads_pid_to_str;
   linuxthreads_ops.to_magic             = OPS_MAGIC;
 }
 
 void
-_initialize_linuxthreads ()
+_initialize_linuxthreads (void)
 {
   struct sigaction sact;
+  sigset_t linuxthreads_wait_mask;       /* sigset with SIGCHLD */
 
   init_linuxthreads_ops ();
   add_target (&linuxthreads_ops);
   child_suppress_run = 1;
 
+  /* Hook onto the "new_objfile" event.
+   * If someone else is already hooked onto the event, 
+   * then make sure he will be called after we are.
+   */
+  target_new_objfile_chain = target_new_objfile_hook;
+  target_new_objfile_hook  = linuxthreads_new_objfile;
+
   /* Attach SIGCHLD handler */
   sact.sa_handler = sigchld_handler;
   sigemptyset (&sact.sa_mask);
@@ -1634,4 +1747,12 @@ _initialize_linuxthreads ()
   /* initialize SIGCHLD mask */
   sigemptyset (&linuxthreads_wait_mask);
   sigaddset (&linuxthreads_wait_mask, SIGCHLD);
+
+  /* Use SIG_BLOCK to block receipt of SIGCHLD.
+     The block_mask will allow us to wait for this signal explicitly.  */
+  sigprocmask(SIG_BLOCK, 
+             &linuxthreads_wait_mask, 
+             &linuxthreads_block_mask);
+  /* Make sure that linuxthreads_block_mask is not blocking SIGCHLD */
+  sigdelset (&linuxthreads_block_mask, SIGCHLD);
 }
This page took 0.035769 seconds and 4 git commands to generate.