2008-03-25 Pedro Alves <pedro@codesourcery.com>
authorPedro Alves <palves@redhat.com>
Tue, 25 Mar 2008 12:20:10 +0000 (12:20 +0000)
committerPedro Alves <palves@redhat.com>
Tue, 25 Mar 2008 12:20:10 +0000 (12:20 +0000)
* linux-nat.c (drain_queued_events): Fix comment typo.
(linux_nat_attach): In async mode, don't rely on storing a pending
status.  Instead place the wait status on the pipe.
(linux_nat_resume): Remove unreacheable shortcut code in async
mode.
(stop_wait_callback): In async mode, don't store pending status.
Instead, cancel breakpoints or resend the signal appropriatelly.
(cancel_breakpoint): New, refactored from
cancel_breakpoints_callback.
(cancel_breakpoints_callback): Call cancel_breakpoint.
(pipe_to_local_event_queue): Remove special token processing.
(linux_nat_wait): Issue an internal error if a pending status is
found in async mode.

gdb/ChangeLog
gdb/linux-nat.c

index 971ac43b00a2a9c2531a0eb778b1c48a42b383d6..04792dfdd93d00cdad1f40b54cdfc4e4b8c69a90 100644 (file)
@@ -1,3 +1,19 @@
+2008-03-25  Pedro Alves  <pedro@codesourcery.com>
+
+       * linux-nat.c (drain_queued_events): Fix comment typo.
+       (linux_nat_attach): In async mode, don't rely on storing a pending
+       status.  Instead place the wait status on the pipe.
+       (linux_nat_resume): Remove unreacheable shortcut code in async
+       mode.
+       (stop_wait_callback): In async mode, don't store pending status.
+       Instead, cancel breakpoints or resend the signal appropriatelly.
+       (cancel_breakpoint): New, refactored from
+       cancel_breakpoints_callback.
+       (cancel_breakpoints_callback): Call cancel_breakpoint.
+       (pipe_to_local_event_queue): Remove special token processing.
+       (linux_nat_wait): Issue an internal error if a pending status is
+       found in async mode.
+
 2008-03-24  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * inflow.c (gdb_has_a_terminal): Guard access to our_process_group.
index b097408a900b53225fa6015a17acb824ddb7f3f4..e2ef962e125e4316a044730c06e9640268dcde5c 100644 (file)
@@ -288,7 +288,7 @@ push_waitpid (int pid, int status, int options)
     waitpid_queue = new_event;
 }
 
-/* Drain all queued event of PID.  If PID is -1, the effect is of
+/* Drain all queued events of PID.  If PID is -1, the effect is of
    draining all events.  */
 static void
 drain_queued_events (int pid)
@@ -799,6 +799,8 @@ static struct sigaction async_sigchld_action;
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
 static char *linux_child_pid_to_exec_file (int pid);
+static int cancel_breakpoint (struct lwp_info *lp);
+
 \f
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
@@ -1134,6 +1136,7 @@ linux_nat_attach (char *args, int from_tty)
   pid_t pid;
   int status;
   int cloned = 0;
+  int options = 0;
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
@@ -1151,13 +1154,14 @@ linux_nat_attach (char *args, int from_tty)
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
      work if things haven't stabilized yet.  */
-  pid = my_waitpid (GET_PID (inferior_ptid), &status, 0);
+  pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
   if (pid == -1 && errno == ECHILD)
     {
       warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
 
       /* Try again with __WCLONE to check cloned processes.  */
-      pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
+      options = __WCLONE;
+      pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
       cloned = 1;
     }
 
@@ -1170,17 +1174,22 @@ linux_nat_attach (char *args, int from_tty)
   lp->cloned = cloned;
 
   lp->stopped = 1;
-
-  /* Fake the SIGSTOP that core GDB expects.  */
-  lp->status = W_STOPCODE (SIGSTOP);
   lp->resumed = 1;
-  if (debug_linux_nat)
-    fprintf_unfiltered (gdb_stdlog,
-                       "LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
-  if (target_can_async_p ())
+
+  if (!target_can_async_p ())
     {
-      /* Wake event loop with special token, to get to WFI.  */
-      linux_nat_event_pipe_push (-1, -1, -1);
+      /* Fake the SIGSTOP that core GDB expects.  */
+      lp->status = W_STOPCODE (SIGSTOP);
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+    }
+  else
+    {
+      /* We already waited for this LWP, so put the wait result on the
+        pipe.  The event loop will wake up and gets us to handling
+        this event.  */
+      linux_nat_event_pipe_push (pid, status, options);
       /* Register in the event loop.  */
       target_async (inferior_event_handler, 0);
     }
@@ -1358,6 +1367,10 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
      other threads.  This bit of code needs to be synchronized
      with linux_nat_wait.  */
 
+  /* In async mode, we never have pending wait status.  */
+  if (target_can_async_p () && lp->status)
+    internal_error (__FILE__, __LINE__, "Pending status in async mode");
+
   if (lp->status && WIFSTOPPED (lp->status))
     {
       int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
@@ -1390,13 +1403,6 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
                            "LLR: Short circuiting for status 0x%x\n",
                            lp->status);
 
-      if (target_can_async_p ())
-       {
-         /* Wake event loop with special token, to get to WFI.  */
-         linux_nat_event_pipe_push (-1, -1, -1);
-
-         target_async (inferior_event_handler, 0);
-       }
       return;
     }
 
@@ -1752,22 +1758,44 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                                      "SWC: Candidate SIGTRAP event in %s\n",
                                      target_pid_to_str (lp->ptid));
                }
-             /* Hold the SIGTRAP for handling by linux_nat_wait. */
+             /* Hold this event/waitstatus while we check to see if
+                there are any more (we still want to get that SIGSTOP). */
              stop_wait_callback (lp, data);
-             /* If there's another event, throw it back into the queue. */
-             if (lp->status)
+
+             if (target_can_async_p ())
                {
-                 if (debug_linux_nat)
+                 /* Don't leave a pending wait status in async mode.
+                    Retrigger the breakpoint.  */
+                 if (!cancel_breakpoint (lp))
                    {
-                     fprintf_unfiltered (gdb_stdlog,
-                                         "SWC: kill %s, %s\n",
-                                         target_pid_to_str (lp->ptid),
-                                         status_to_str ((int) status));
+                     /* There was no gdb breakpoint set at pc.  Put
+                        the event back in the queue.  */
+                     if (debug_linux_nat)
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "SWC: kill %s, %s\n",
+                                           target_pid_to_str (lp->ptid),
+                                           status_to_str ((int) status));
+                     kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
                    }
-                 kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
                }
-             /* Save the sigtrap event. */
-             lp->status = status;
+             else
+               {
+                 /* Hold the SIGTRAP for handling by
+                    linux_nat_wait. */
+                 /* If there's another event, throw it back into the
+                    queue. */
+                 if (lp->status)
+                   {
+                     if (debug_linux_nat)
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "SWC: kill %s, %s\n",
+                                           target_pid_to_str (lp->ptid),
+                                           status_to_str ((int) status));
+                     kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
+                   }
+                 /* Save the sigtrap event. */
+                 lp->status = status;
+               }
              return 0;
            }
          else
@@ -1794,12 +1822,11 @@ stop_wait_callback (struct lwp_info *lp, void *data)
              /* Hold this event/waitstatus while we check to see if
                 there are any more (we still want to get that SIGSTOP). */
              stop_wait_callback (lp, data);
-             /* If the lp->status field is still empty, use it to hold
-                this event.  If not, then this event must be returned
-                to the event queue of the LWP.  */
-             if (lp->status == 0)
-               lp->status = status;
-             else
+
+             /* If the lp->status field is still empty, use it to
+                hold this event.  If not, then this event must be
+                returned to the event queue of the LWP.  */
+             if (lp->status || target_can_async_p ())
                {
                  if (debug_linux_nat)
                    {
@@ -1810,6 +1837,8 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                    }
                  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
                }
+             else
+               lp->status = status;
              return 0;
            }
        }
@@ -1979,6 +2008,37 @@ select_event_lwp_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+static int
+cancel_breakpoint (struct lwp_info *lp)
+{
+  /* Arrange for a breakpoint to be hit again later.  We don't keep
+     the SIGTRAP status and don't forward the SIGTRAP signal to the
+     LWP.  We will handle the current event, eventually we will resume
+     this LWP, and this breakpoint will trap again.
+
+     If we do not do this, then we run the risk that the user will
+     delete or disable the breakpoint, but the LWP will have already
+     tripped on it.  */
+
+  if (breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
+                                 gdbarch_decr_pc_after_break
+                                 (current_gdbarch)))
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "CB: Push back breakpoint for %s\n",
+                           target_pid_to_str (lp->ptid));
+
+      /* Back up the PC if necessary.  */
+      if (gdbarch_decr_pc_after_break (current_gdbarch))
+       write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
+                     (current_gdbarch),
+                     lp->ptid);
+      return 1;
+    }
+  return 0;
+}
+
 static int
 cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 {
@@ -2001,24 +2061,9 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 
   if (lp->status != 0
       && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
-      && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
-                                    gdbarch_decr_pc_after_break
-                                      (current_gdbarch)))
-    {
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog,
-                           "CBC: Push back breakpoint for %s\n",
-                           target_pid_to_str (lp->ptid));
-
-      /* Back up the PC if necessary.  */
-      if (gdbarch_decr_pc_after_break (current_gdbarch))
-       write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
-                                                (current_gdbarch),
-                     lp->ptid);
-
-      /* Throw away the SIGTRAP.  */
-      lp->status = 0;
-    }
+      && cancel_breakpoint (lp))
+    /* Throw away the SIGTRAP.  */
+    lp->status = 0;
 
   return 0;
 }
@@ -2288,12 +2333,7 @@ pipe_to_local_event_queue (void)
   while (linux_nat_num_queued_events)
     {
       int lwpid, status, options;
-
       lwpid = linux_nat_event_pipe_pop (&status, &options);
-      if (lwpid == -1 && status == -1 && options == -1)
-       /* Special wake up event loop token.  */
-       continue;
-
       gdb_assert (lwpid > 0);
       push_waitpid (lwpid, status, options);
     }
@@ -2367,6 +2407,10 @@ retry:
       lp = iterate_over_lwps (status_callback, NULL);
       if (lp)
        {
+         if (target_can_async_p ())
+           internal_error (__FILE__, __LINE__,
+                           "Found an LWP with a pending status in async mode.");
+
          status = lp->status;
          lp->status = 0;