* mmix.h (R_MMIX_PUSHJ_STUBBABLE): New reloc number.
[deliverable/binutils-gdb.git] / gdb / lin-lwp.c
index b168b054bc765c3b76a15cbe7a7a287466b20ee7..df91aa7696333b46d6cf7721cf1768bf235a0379 100644 (file)
@@ -417,7 +417,12 @@ detach_callback (struct lwp_info *lp, void *data)
       lp->stopped = 0;
       lp->signalled = 0;
       lp->status = 0;
-      stop_wait_callback (lp, NULL);
+      /* FIXME drow/2003-08-26: There was a call to stop_wait_callback
+        here.  But since lp->signalled was cleared above,
+        stop_wait_callback didn't do anything; the process was left
+        running.  Shouldn't we be waiting for it to stop?
+        I've removed the call, since stop_wait_callback now does do
+        something when called with lp->signalled == 0.  */
 
       gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
     }
@@ -585,6 +590,77 @@ kill_lwp (int lwpid, int signo)
   return kill (lwpid, signo);
 }
 
+/* Wait for LP to stop.  Returns the wait status, or 0 if the LWP has
+   exited.  */
+
+static int
+wait_lwp (struct lwp_info *lp)
+{
+  pid_t pid;
+  int status;
+  int thread_dead = 0;
+
+  gdb_assert (!lp->stopped);
+  gdb_assert (lp->status == 0);
+
+  pid = waitpid (GET_LWP (lp->ptid), &status, 0);
+  if (pid == -1 && errno == ECHILD)
+    {
+      pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
+      if (pid == -1 && errno == ECHILD)
+       {
+         /* The thread has previously exited.  We need to delete it now
+            because in the case of NPTL threads, there won't be an
+            exit event unless it is the main thread.  */
+         thread_dead = 1;
+         if (debug_lin_lwp)
+           fprintf_unfiltered (gdb_stdlog, "WL: %s vanished.\n",
+                               target_pid_to_str (lp->ptid));
+       }
+    }
+
+  if (!thread_dead)
+    {
+      gdb_assert (pid == GET_LWP (lp->ptid));
+
+      if (debug_lin_lwp)
+       {
+         fprintf_unfiltered (gdb_stdlog,
+                             "WL: waitpid %s received %s\n",
+                             target_pid_to_str (lp->ptid),
+                             status_to_str (status));
+       }
+    }
+
+  /* Check if the thread has exited.  */
+  if (WIFEXITED (status) || WIFSIGNALED (status))
+    {
+      thread_dead = 1;
+      if (debug_lin_lwp)
+       fprintf_unfiltered (gdb_stdlog, "WL: %s exited.\n",
+                           target_pid_to_str (lp->ptid));
+    }
+
+  if (thread_dead)
+    {
+      if (in_thread_list (lp->ptid))
+       {
+         /* Core GDB cannot deal with us deleting the current thread.  */
+         if (!ptid_equal (lp->ptid, inferior_ptid))
+           delete_thread (lp->ptid);
+         printf_unfiltered ("[%s exited]\n",
+                            target_pid_to_str (lp->ptid));
+       }
+
+      delete_lwp (lp->ptid);
+      return 0;
+    }
+
+  gdb_assert (WIFSTOPPED (status));
+
+  return status;
+}
+
 /* Send a SIGSTOP to LP.  */
 
 static int
@@ -625,92 +701,23 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 {
   sigset_t *flush_mask = data;
 
-  if (!lp->stopped && lp->signalled)
+  if (!lp->stopped)
     {
-      pid_t pid;
       int status;
 
-      gdb_assert (lp->status == 0);
+      status = wait_lwp (lp);
+      if (status == 0)
+       return 0;
 
-      pid = waitpid (GET_LWP (lp->ptid), &status, 0);
-      if (pid == -1 && errno == ECHILD)
+      /* Ignore any signals in FLUSH_MASK.  */
+      if (flush_mask && sigismember (flush_mask, WSTOPSIG (status)))
        {
-         pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
-         if (pid == -1 && errno == ECHILD)
+         if (!lp->signalled)
            {
-             /* The thread has previously exited.  We need to delete it now
-                because in the case of nptl threads, there won't be an
-                exit event unless it is the main thread.  */
-             if (debug_lin_lwp)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "SWC: %s exited.\n",
-                                   target_pid_to_str (lp->ptid));
-             delete_lwp (lp->ptid);
+             lp->stopped = 1;
              return 0;
            }
-       }
-
-      gdb_assert (pid == GET_LWP (lp->ptid));
-
-      if (debug_lin_lwp)
-       {
-         fprintf_unfiltered (gdb_stdlog,
-                             "SWC: waitpid %s received %s\n",
-                             target_pid_to_str (lp->ptid),
-                             status_to_str (status));
-       }
-
-      /* Check if the thread has exited.  */
-      if (WIFEXITED (status) || WIFSIGNALED (status))
-       {
-         gdb_assert (num_lwps > 1);
-
-         if (in_thread_list (lp->ptid))
-           {
-             /* Core GDB cannot deal with us deleting the current
-                thread.  */
-             if (!ptid_equal (lp->ptid, inferior_ptid))
-               delete_thread (lp->ptid);
-             printf_unfiltered ("[%s exited]\n",
-                                target_pid_to_str (lp->ptid));
-           }
-         if (debug_lin_lwp)
-           fprintf_unfiltered (gdb_stdlog,
-                               "SWC: %s exited.\n",
-                               target_pid_to_str (lp->ptid));
-
-         delete_lwp (lp->ptid);
-         return 0;
-       }
-
-      /* Check if the current LWP has previously exited.  For nptl threads,
-         there is no exit signal issued for LWPs that are not the
-         main thread so we should check whenever the thread is stopped.  */
-      if (!lin_lwp_thread_alive (lp->ptid))
-       {
-         if (in_thread_list (lp->ptid))
-           {
-             /* Core GDB cannot deal with us deleting the current
-                thread.  */
-             if (!ptid_equal (lp->ptid, inferior_ptid))
-               delete_thread (lp->ptid);
-             printf_unfiltered ("[%s exited]\n",
-                                target_pid_to_str (lp->ptid));
-           }
-         if (debug_lin_lwp)
-           fprintf_unfiltered (gdb_stdlog,
-                               "SWC: %s already exited.\n",
-                               target_pid_to_str (lp->ptid));
-
-         delete_lwp (lp->ptid);
-         return 0;
-       }
-
-      gdb_assert (WIFSTOPPED (status));
 
-      /* Ignore any signals in FLUSH_MASK.  */
-      if (flush_mask && sigismember (flush_mask, WSTOPSIG (status)))
-       {
          errno = 0;
          ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
          if (debug_lin_lwp)
@@ -826,6 +833,88 @@ stop_wait_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+/* Check whether PID has any pending signals in FLUSH_MASK.  If so set
+   the appropriate bits in PENDING, and return 1 - otherwise return 0.  */
+
+static int
+lin_lwp_has_pending (int pid, sigset_t *pending, sigset_t *flush_mask)
+{
+  sigset_t blocked, ignored;
+  int i;
+
+  linux_proc_pending_signals (pid, pending, &blocked, &ignored);
+
+  if (!flush_mask)
+    return 0;
+
+  for (i = 1; i < NSIG; i++)
+    if (sigismember (pending, i))
+      if (!sigismember (flush_mask, i)
+         || sigismember (&blocked, i)
+         || sigismember (&ignored, i))
+       sigdelset (pending, i);
+
+  if (sigisemptyset (pending))
+    return 0;
+
+  return 1;
+}
+
+/* DATA is interpreted as a mask of signals to flush.  If LP has
+   signals pending, and they are all in the flush mask, then arrange
+   to flush them.  LP should be stopped, as should all other threads
+   it might share a signal queue with.  */
+
+static int
+flush_callback (struct lwp_info *lp, void *data)
+{
+  sigset_t *flush_mask = data;
+  sigset_t pending, intersection, blocked, ignored;
+  int pid, status;
+
+  /* Normally, when an LWP exits, it is removed from the LWP list.  The
+     last LWP isn't removed till later, however.  So if there is only
+     one LWP on the list, make sure it's alive.  */
+  if (lwp_list == lp && lp->next == NULL)
+    if (!lin_lwp_thread_alive (lp->ptid))
+      return 0;
+
+  /* Just because the LWP is stopped doesn't mean that new signals
+     can't arrive from outside, so this function must be careful of
+     race conditions.  However, because all threads are stopped, we
+     can assume that the pending mask will not shrink unless we resume
+     the LWP, and that it will then get another signal.  We can't
+     control which one, however.  */
+
+  if (lp->status)
+    {
+      if (debug_lin_lwp)
+       printf_unfiltered ("FC: LP has pending status %06x\n", lp->status);
+      if (WIFSTOPPED (lp->status) && sigismember (flush_mask, WSTOPSIG (lp->status)))
+       lp->status = 0;
+    }
+
+  while (lin_lwp_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
+    {
+      int ret;
+      
+      errno = 0;
+      ret = ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+      if (debug_lin_lwp)
+       fprintf_unfiltered (gdb_stderr,
+                           "FC: Sent PTRACE_CONT, ret %d %d\n", ret, errno);
+
+      lp->stopped = 0;
+      stop_wait_callback (lp, flush_mask);
+      if (debug_lin_lwp)
+       fprintf_unfiltered (gdb_stderr,
+                           "FC: Wait finished; saved status is %d\n",
+                           lp->status);
+    }
+
+  return 0;
+}
+
 /* Return non-zero if LP has a wait status pending.  */
 
 static int
@@ -841,7 +930,7 @@ status_callback (struct lwp_info *lp, void *data)
 static int
 running_callback (struct lwp_info *lp, void *data)
 {
-  return (lp->stopped == 0);
+  return (lp->stopped == 0 || (lp->status != 0 && lp->resumed));
 }
 
 /* Count the LWP's that have had events.  */
@@ -1049,6 +1138,7 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
       if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP
          && pid != GET_PID (inferior_ptid))
        {
+         linux_record_stopped_pid (pid);
          pid = -1;
          save_errno = EINTR;
        }
@@ -1093,7 +1183,10 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
       /* Resume if the lwp still exists.  */
       for (ptr = lwp_list; ptr; ptr = ptr->next)
        if (lp == ptr)
-         resume_callback (lp, NULL);
+         {
+           resume_callback (lp, NULL);
+           resume_set_callback (lp, NULL);
+         }
     }
   return 0;
 }
@@ -1468,6 +1561,7 @@ retry:
   /* ... and wait until all of them have reported back that they're no
      longer running.  */
   iterate_over_lwps (stop_wait_callback, &flush_mask);
+  iterate_over_lwps (flush_callback, &flush_mask);
 
   /* If we're not waiting for a specific LWP, choose an event LWP from
      among those that have had events.  Giving equal priority to all
This page took 0.027342 seconds and 4 git commands to generate.