This is the mail archive of the gdb-patches@sourceware.org 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]
Other format: [Raw text]

Re: RFA: non-stop/linux, thread stopping


Hi,

I ended up making a tiny adjustment to make this mostly affect non-stop
mode only, hence making it much less likely to cause allround breakage.

I then re-tested on x86-64-unknown-linux-gnu (-m64/-m32), and checked
it in.  Please find attached what went in.

-- 
Pedro Alves

On Thursday 16 October 2008 03:54:38, Pedro Alves wrote:
> Hi all,
> 
> [ Yet another patch preparing for remote non-stop.  ]
> 
> While designing the remote non-stop protocol, and the
> "interrupt", "interrupt -a" support, we came up with a new vCont
> extension, `vCont;t', or applied to a thread, `vCont;t:TID',
> meaning, roughly:
> 
> "stop/suspend the target thread TID, however you can and feel like.
> If nothing interesting happens to the thread while stopping it, then report
> back a TARGET_SIGNAL_0, because I don't care how the thread was
> suspended behind the scenes.  You take care of it."
> 
> This takes advantage of the fact that TARGET_SIGNAL_0 is defined as:
> 
>  src/include/gdb/signal.h:
> 
>     /* Used some places (e.g. stop_signal) to record the concept that
>        there is no signal.  */
>     TARGET_SIGNAL_0 = 0,
> 
> When implementing this on gdbserver (ptrace/linux), this effectivelly
> translated into stopping an LWP with SIGSTOP, nicelly moving away
> from SIGINT, process groups, shared or not-shared signal queues
> and the like.
> 
> Another propertly of `vCont;t', is that it is defined as doing
> nothing to already stopped threads.  This requirement (to not do
> anything to stopped threads), implies that threads that were
> already stopped due to internal events when an explicit stop
> is requested, most notably, threads that are stopped waiting for their
> turn in the displaced stepping queue (*), should remain stopped, and
> GDB should report that stop as if the target had done so
> itself.  That is, GDB should make the stop "public".
> 
> There are cases where this property is useful, and following
> patches will rely on it.
> 
> *) remember we only have one scratch space currently, so
> we can only ool-step one thread at a time.
> 
> This patch changes native linux non-stop to behave the same, and
> adds the necessary glue to the common code.
> 
> To make it nicer on the eye, I'm making an output change in
> the CLI:
> 
> New:
> 
>  [Thread 0xf7e306b0 (LWP 26335)] #1 stopped.
>  0xffffe410 in __kernel_vsyscall ()
> 
> Old:
> 
>  Program received signal 0, Signal 0.
>  0xffffe410 in __kernel_vsyscall ()
> 
> The old output is IMHO, very weird, as a program usually
> doesn't stop with a signal 0.  :-)  It also lacked information
> of which thread had stopped.
> 
> No MI changes are necessary.
> *stopped,reason="signal-received",signal-name="0" is still OK.
> 
> A frontend can then react accordingly to how the thread was stopped, and treat
> signal 0 specialy if it wants to:  Say, if it was a TARGET_SIGNAL_0, then just
> perhaps update the thread state icon in a thread tree view, by displaying
> a "pause" icon.  If it is was a SIGINT, SIGSEGV or some other signal, then
> popup a message box, for example.
> 
> How does this all sound?  I'm certain that handle_inferior_event will
> need a bit more tweaking here and there to acommodate corner cases, but
> I don't expect much.  The base principle is "if the thread had an
> explicit request to stop, then when we get a stop event, don't resume
> it automatically.".  That's all.
> 
> About the code changes themselves:
> 
>  - I'm using an observer to make two GDB components comunicate.
> 
>       thread.c -> infrun.c
> 
>  - ptid_is_pid: new function.  I must have written this function
>    5 times already, using 3 different idioms, across several files, but
>    I haven't contributed any of those.  Might as well make it to
>    common code, where it belongs.  It returns true if a ptid
>    represents a process.
> 
>  - This was the reason I had added mi_expect_interrupt instead of
>    reusing mi_expect_stop.  With this change, since no current target
>    will report a SIGINT on a -exec-interrupt, I can just make it only
>    recognize signal 0.
> 
> All-in-all, tested on x86-pc-linux-gnu.
> 
> Does it sound/look sane/OK ?
> 
gdb/
2008-10-23  Pedro Alves  <pedro@codesourcery.com>

	* defs.h: Mention ptid_is_pid.
	* inferior.h (ptid_is_pid): Declare.
	* gdbthread.h (struct thread_info) <stop_requested>: New field.
	(set_stop_requested): Declare.
	* infcmd.c (interrupt_target_1): Call set_stop_requested.
	* infrun.c (clear_proceed_status): Clear stop_requested.
	(infrun_thread_stop_requested_callback,
	infrun_thread_stop_requested): New.
	(handle_inferior_event): If a TARGET_SIGNAL_TRAP is reported on a
	thread that had an explicit stop request, pretend we got a
	TARGET_SIGNAL_0.  Always stop if the thread had an explicit stop
	request.
	(print_stop_reason): In the SIGNAL_RECEIVED case, if we're not
	outputting to MI, and we got a TARGET_SIGNAL_0, print "# Stopped",
	instead of mentioning signal 0.
	(ptid_is_pid): New.
	* thread.c (set_stop_requested): New.

	* linux-nat.c (queued_waitpid): Rename to ...
	(queued_waitpid_1): ... this.  Add `peek' argument.  Handle it.
	(queued_waitpid): New, as wrapper to queued_waitpid_1.
	(push_waitpid): Push the SIGTRAP to the local event queue, to the
	kernel's.
	(send_sigint_callback): Delete.
	(linux_nat_stop_lwp): New.
	(linux_nat_stop): Use it.

gdb/doc/
2008-10-23  Pedro Alves  <pedro@codesourcery.com>

	* observer.texi (thread_stop_requested): New.

gdb/testsuite/
2008-10-23  Pedro Alves  <pedro@codesourcery.com>

	* lib/mi-support.exp (mi_expect_interrupt): Expect signal 0
	instead of SIGINT.

---
 gdb/defs.h                       |    1 
 gdb/doc/observer.texi            |    8 +
 gdb/gdbthread.h                  |   10 ++
 gdb/infcmd.c                     |    9 +
 gdb/inferior.h                   |    3 
 gdb/infrun.c                     |  177 ++++++++++++++++++++++++++++++++++-----
 gdb/linux-nat.c                  |  128 ++++++++++++++++++++++------
 gdb/testsuite/lib/mi-support.exp |    2 
 gdb/thread.c                     |   25 +++++
 9 files changed, 313 insertions(+), 50 deletions(-)

Index: src/gdb/defs.h
===================================================================
--- src.orig/gdb/defs.h	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/defs.h	2008-10-24 00:07:12.000000000 +0100
@@ -752,6 +752,7 @@ enum val_prettyprint
       ptid_get_lwp	- Fetch the lwp component of a ptid.
       ptid_get_tid	- Fetch the tid component of a ptid.
       ptid_equal	- Test to see if two ptids are equal.
+      ptid_is_pid	- Test to see if this ptid represents a process id.
 
    Please do NOT access the struct ptid members directly (except, of
    course, in the implementation of the above ptid manipulation
Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/inferior.h	2008-10-24 00:07:12.000000000 +0100
@@ -89,6 +89,9 @@ long ptid_get_tid (ptid_t ptid);
 /* Compare two ptids to see if they are equal */
 extern int ptid_equal (ptid_t p1, ptid_t p2);
 
+/* Return true if PTID represents a process id.  */
+extern int ptid_is_pid (ptid_t ptid);
+
 /* Save value of inferior_ptid so that it may be restored by
    a later call to do_cleanups().  Returns the struct cleanup
    pointer needed for later doing the cleanup.  */
Index: src/gdb/gdbthread.h
===================================================================
--- src.orig/gdb/gdbthread.h	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/gdbthread.h	2008-10-24 00:07:12.000000000 +0100
@@ -168,6 +168,9 @@ struct thread_info
      at.  */
   bpstat stop_bpstat;
 
+  /* True if this thread has been explicitly requested to stop.  */
+  int stop_requested;
+
   /* Private data used by the target vector implementation.  */
   struct private_thread_info *private;
 };
@@ -239,6 +242,13 @@ extern void switch_to_thread (ptid_t pti
    If PIDGET (PTID) is -1, marks all threads.  */
 extern void set_running (ptid_t ptid, int running);
 
+/* Marks or clears thread(s) PTID as having been requested to stop.
+   If PTID is MINUS_ONE_PTID, applies to all threads.  If
+   ptid_is_pid(PTID) is true, applies to all threads of the process
+   pointed at by PTID.  If STOP, then the THREAD_STOP_REQUESTED
+   observer is called with PTID as argument.  */
+extern void set_stop_requested (ptid_t ptid, int stop);
+
 /* NOTE: Since the thread state is not a boolean, most times, you do
    not want to check it with negation.  If you really want to check if
    the thread is stopped,
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/infcmd.c	2008-10-24 00:07:12.000000000 +0100
@@ -2245,6 +2245,15 @@ interrupt_target_1 (int all_threads)
   else
     ptid = inferior_ptid;
   target_stop (ptid);
+
+  /* Tag the thread as having been explicitly requested to stop, so
+     other parts of gdb know not to resume this thread automatically,
+     if it was stopped due to an internal event.  Limit this to
+     non-stop mode, as when debugging a multi-threaded application in
+     all-stop mode, we will only get one stop event --- it's undefined
+     which thread will report the event.  */
+  if (non_stop)
+    set_stop_requested (ptid, 1);
 }
 
 /* Stop the execution of the target while running in async mode, in
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2008-10-24 00:06:17.000000000 +0100
+++ src/gdb/infrun.c	2008-10-24 00:07:12.000000000 +0100
@@ -1147,6 +1147,7 @@ clear_proceed_status (void)
       tp->step_range_end = 0;
       tp->step_frame_id = null_frame_id;
       tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
+      tp->stop_requested = 0;
 
       tp->stop_step = 0;
 
@@ -1528,6 +1529,100 @@ static void keep_going (struct execution
 static void print_stop_reason (enum inferior_stop_reason stop_reason,
 			       int stop_info);
 
+/* Callback for iterate over threads.  If the thread is stopped, but
+   the user/frontend doesn't know about that yet, go through
+   normal_stop, as if the thread had just stopped now.  ARG points at
+   a ptid.  If PTID is MINUS_ONE_PTID, applies to all threads.  If
+   ptid_is_pid(PTID) is true, applies to all threads of the process
+   pointed at by PTID.  Otherwise, apply only to the thread pointed by
+   PTID.  */
+
+static int
+infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
+{
+  ptid_t ptid = * (ptid_t *) arg;
+
+  if ((ptid_equal (info->ptid, ptid)
+       || ptid_equal (minus_one_ptid, ptid)
+       || (ptid_is_pid (ptid)
+	   && ptid_get_pid (ptid) == ptid_get_pid (info->ptid)))
+      && is_running (info->ptid)
+      && !is_executing (info->ptid))
+    {
+      struct cleanup *old_chain;
+      struct execution_control_state ecss;
+      struct execution_control_state *ecs = &ecss;
+
+      memset (ecs, 0, sizeof (*ecs));
+
+      old_chain = make_cleanup_restore_current_thread ();
+
+      switch_to_thread (info->ptid);
+
+      /* Go through handle_inferior_event/normal_stop, so we always
+	 have consistent output as if the stop event had been
+	 reported.  */
+      ecs->ptid = info->ptid;
+      ecs->event_thread = find_thread_pid (info->ptid);
+      ecs->ws.kind = TARGET_WAITKIND_STOPPED;
+      ecs->ws.value.sig = TARGET_SIGNAL_0;
+
+      handle_inferior_event (ecs);
+
+      if (!ecs->wait_some_more)
+	{
+	  struct thread_info *tp;
+
+	  normal_stop ();
+
+	  /* Finish off the continuations.  The continations
+	     themselves are responsible for realising the thread
+	     didn't finish what it was supposed to do.  */
+	  tp = inferior_thread ();
+	  do_all_intermediate_continuations_thread (tp);
+	  do_all_continuations_thread (tp);
+	}
+
+      do_cleanups (old_chain);
+    }
+
+  return 0;
+}
+
+/* This function is attached as a "thread_stop_requested" observer.
+   Cleanup local state that assumed the PTID was to be resumed, and
+   report the stop to the frontend.  */
+
+void
+infrun_thread_stop_requested (ptid_t ptid)
+{
+  struct displaced_step_request *it, *next, *prev = NULL;
+
+  /* PTID was requested to stop.  Remove it from the displaced
+     stepping queue, so we don't try to resume it automatically.  */
+  for (it = displaced_step_request_queue; it; it = next)
+    {
+      next = it->next;
+
+      if (ptid_equal (it->ptid, ptid)
+	  || ptid_equal (minus_one_ptid, ptid)
+	  || (ptid_is_pid (ptid)
+	      && ptid_get_pid (ptid) == ptid_get_pid (it->ptid)))
+	{
+	  if (displaced_step_request_queue == it)
+	    displaced_step_request_queue = it->next;
+	  else
+	    prev->next = it->next;
+
+	  xfree (it);
+	}
+      else
+	prev = it;
+    }
+
+  iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
+}
+
 /* Callback for iterate_over_threads.  */
 
 static int
@@ -2279,11 +2374,21 @@ targets should add new threads to the th
       return;
     }
 
-  /* Do we need to clean up the state of a thread that has completed a
-     displaced single-step?  (Doing so usually affects the PC, so do
-     it here, before we set stop_pc.)  */
   if (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
-    displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal);
+    {
+      /* Do we need to clean up the state of a thread that has
+	 completed a displaced single-step?  (Doing so usually affects
+	 the PC, so do it here, before we set stop_pc.)  */
+      displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal);
+
+      /* If we either finished a single-step or hit a breakpoint, but
+	 the user wanted this thread to be stopped, pretend we got a
+	 SIG0 (generic unsignaled stop).  */
+
+      if (ecs->event_thread->stop_requested
+	  && ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
+	ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+    }
 
   stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
 
@@ -2779,9 +2884,11 @@ process_event_stop_test:
 	  target_terminal_ours_for_output ();
 	  print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal);
 	}
-      /* Always stop on signals if we're just gaining control of the
-	 program.  */
+      /* Always stop on signals if we're either just gaining control
+	 of the program, or the user explicitly requested this thread
+	 to remain stopped.  */
       if (stop_soon != NO_STOP_QUIETLY
+	  || ecs->event_thread->stop_requested
 	  || signal_stop_state (ecs->event_thread->stop_signal))
 	{
 	  stop_stepping (ecs);
@@ -3891,22 +3998,36 @@ print_stop_reason (enum inferior_stop_re
       return_child_result_value = stop_info;
       break;
     case SIGNAL_RECEIVED:
-      /* Signal received. The signal table tells us to print about
-         it. */
+      /* Signal received.  The signal table tells us to print about
+	 it. */
       annotate_signal ();
-      ui_out_text (uiout, "\nProgram received signal ");
-      annotate_signal_name ();
-      if (ui_out_is_mi_like_p (uiout))
-	ui_out_field_string
-	  (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
-      ui_out_field_string (uiout, "signal-name",
-			   target_signal_to_name (stop_info));
-      annotate_signal_name_end ();
-      ui_out_text (uiout, ", ");
-      annotate_signal_string ();
-      ui_out_field_string (uiout, "signal-meaning",
-			   target_signal_to_string (stop_info));
-      annotate_signal_string_end ();
+
+      if (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
+	{
+	  struct thread_info *t = inferior_thread ();
+
+	  ui_out_text (uiout, "\n[");
+	  ui_out_field_string (uiout, "thread-name",
+			       target_pid_to_str (t->ptid));
+	  ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num);
+	  ui_out_text (uiout, " stopped");
+	}
+      else
+	{
+	  ui_out_text (uiout, "\nProgram received signal ");
+	  annotate_signal_name ();
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
+	  ui_out_field_string (uiout, "signal-name",
+			       target_signal_to_name (stop_info));
+	  annotate_signal_name_end ();
+	  ui_out_text (uiout, ", ");
+	  annotate_signal_string ();
+	  ui_out_field_string (uiout, "signal-meaning",
+			       target_signal_to_string (stop_info));
+	  annotate_signal_string_end ();
+	}
       ui_out_text (uiout, ".\n");
       break;
     case NO_HISTORY:
@@ -4817,6 +4938,19 @@ ptid_equal (ptid_t ptid1, ptid_t ptid2)
 	  && ptid1.tid == ptid2.tid);
 }
 
+/* Returns true if PTID represents a process.  */
+
+int
+ptid_is_pid (ptid_t ptid)
+{
+  if (ptid_equal (minus_one_ptid, ptid))
+    return 0;
+  if (ptid_equal (null_ptid, ptid))
+    return 0;
+
+  return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0);
+}
+
 /* restore_inferior_ptid() will be used by the cleanup machinery
    to restore the inferior_ptid value saved in a call to
    save_inferior_ptid().  */
@@ -5134,4 +5268,5 @@ Options are 'forward' or 'reverse'."),
   displaced_step_ptid = null_ptid;
 
   observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
+  observer_attach_thread_stop_requested (infrun_thread_stop_requested);
 }
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/thread.c	2008-10-24 00:07:12.000000000 +0100
@@ -606,6 +606,31 @@ set_executing (ptid_t ptid, int executin
     }
 }
 
+void
+set_stop_requested (ptid_t ptid, int stop)
+{
+  struct thread_info *tp;
+  int all = ptid_equal (ptid, minus_one_ptid);
+
+  if (all || ptid_is_pid (ptid))
+    {
+      for (tp = thread_list; tp; tp = tp->next)
+	if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
+	  tp->stop_requested = stop;
+    }
+  else
+    {
+      tp = find_thread_pid (ptid);
+      gdb_assert (tp);
+      tp->stop_requested = stop;
+    }
+
+  /* Call the stop requested observer so other components of GDB can
+     react to this request.  */
+  if (stop)
+    observer_notify_thread_stop_requested (ptid);
+}
+
 /* Prints the list of threads and their details on UIOUT.
    This is a version of 'info_thread_command' suitable for
    use from MI.  
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/linux-nat.c	2008-10-24 00:07:12.000000000 +0100
@@ -316,7 +316,6 @@ static void linux_nat_async (void (*call
 static int linux_nat_async_mask (int mask);
 static int kill_lwp (int lwpid, int signo);
 
-static int send_sigint_callback (struct lwp_info *lp, void *data);
 static int stop_callback (struct lwp_info *lp, void *data);
 
 /* Captures the result of a successful waitpid call, along with the
@@ -333,8 +332,12 @@ struct waitpid_result
    in the async SIGCHLD handler.  */
 static struct waitpid_result *waitpid_queue = NULL;
 
+/* Similarly to `waitpid', but check the local event queue instead of
+   querying the kernel queue.  If PEEK, don't remove the event found
+   from the queue.  */
+
 static int
-queued_waitpid (int pid, int *status, int flags)
+queued_waitpid_1 (int pid, int *status, int flags, int peek)
 {
   struct waitpid_result *msg = waitpid_queue, *prev = NULL;
 
@@ -370,12 +373,6 @@ QWPID: linux_nat_async_events_state(%d),
     {
       int pid;
 
-      if (prev)
-	prev->next = msg->next;
-      else
-	waitpid_queue = msg->next;
-
-      msg->next = NULL;
       if (status)
 	*status = msg->status;
       pid = msg->pid;
@@ -383,7 +380,17 @@ QWPID: linux_nat_async_events_state(%d),
       if (debug_linux_nat_async)
 	fprintf_unfiltered (gdb_stdlog, "QWPID: pid(%d), status(%x)\n",
 			    pid, msg->status);
-      xfree (msg);
+
+      if (!peek)
+	{
+	  if (prev)
+	    prev->next = msg->next;
+	  else
+	    waitpid_queue = msg->next;
+
+	  msg->next = NULL;
+	  xfree (msg);
+	}
 
       return pid;
     }
@@ -396,6 +403,14 @@ QWPID: linux_nat_async_events_state(%d),
   return -1;
 }
 
+/* Similarly to `waitpid', but check the local event queue.  */
+
+static int
+queued_waitpid (int pid, int *status, int flags)
+{
+  return queued_waitpid_1 (pid, status, flags, 0);
+}
+
 static void
 push_waitpid (int pid, int status, int options)
 {
@@ -2200,11 +2215,11 @@ stop_wait_callback (struct lwp_info *lp,
 		      /* 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));
+			fprintf_unfiltered (gdb_stdlog, "\
+SWC: leaving SIGTRAP in local queue of %s\n", target_pid_to_str (lp->ptid));
+		      push_waitpid (GET_LWP (lp->ptid),
+				    W_STOPCODE (SIGTRAP),
+				    lp->cloned ? __WCLONE : 0);
 		    }
 		}
 	      else
@@ -4368,15 +4383,76 @@ linux_nat_async (void (*callback) (enum 
   return;
 }
 
+/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other
+   event came out.  */
+
 static int
-send_sigint_callback (struct lwp_info *lp, void *data)
+linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 {
-  /* Use is_running instead of !lp->stopped, because the lwp may be
-     stopped due to an internal event, and we want to interrupt it in
-     that case too.  What we want is to check if the thread is stopped
-     from the point of view of the user.  */
-  if (is_running (lp->ptid))
-    kill_lwp (GET_LWP (lp->ptid), SIGINT);
+  ptid_t ptid = * (ptid_t *) data;
+
+  if (ptid_equal (lwp->ptid, ptid)
+      || ptid_equal (minus_one_ptid, ptid)
+      || (ptid_is_pid (ptid)
+	  && ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid)))
+    {
+      if (!lwp->stopped)
+	{
+	  int pid, status;
+
+	  if (debug_linux_nat)
+	    fprintf_unfiltered (gdb_stdlog,
+				"LNSL: running -> suspending %s\n",
+				target_pid_to_str (lwp->ptid));
+
+	  /* Peek once, to check if we've already waited for this
+	     LWP.  */
+	  pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status,
+				  lwp->cloned ? __WCLONE : 0,  1 /* peek */);
+
+	  if (pid == -1)
+	    {
+	      ptid_t ptid = lwp->ptid;
+
+	      stop_callback (lwp, NULL);
+	      stop_wait_callback (lwp, NULL);
+
+	      /* If the lwp exits while we try to stop it, there's
+		 nothing else to do.  */
+	      lwp = find_lwp_pid (ptid);
+	      if (lwp == NULL)
+		return 0;
+
+	      pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status,
+				      lwp->cloned ? __WCLONE : 0,
+				      1 /* peek */);
+	    }
+
+	  /* If we didn't collect any signal other than SIGSTOP while
+	     stopping the LWP, push a SIGNAL_0 event.  In either case,
+	     the event-loop will end up calling target_wait which will
+	     collect these.  */
+	  if (pid == -1)
+	    push_waitpid (ptid_get_lwp (lwp->ptid), W_STOPCODE (0),
+			  lwp->cloned ? __WCLONE : 0);
+	}
+      else
+	{
+	  /* Already known to be stopped; do nothing.  */
+
+	  if (debug_linux_nat)
+	    {
+	      if (find_thread_pid (lwp->ptid)->stop_requested)
+		fprintf_unfiltered (gdb_stdlog, "\
+LNSL: already stopped/stop_requested %s\n",
+				    target_pid_to_str (lwp->ptid));
+	      else
+		fprintf_unfiltered (gdb_stdlog, "\
+LNSL: already stopped/no stop_requested yet %s\n",
+				    target_pid_to_str (lwp->ptid));
+	    }
+	}
+    }
   return 0;
 }
 
@@ -4385,13 +4461,9 @@ linux_nat_stop (ptid_t ptid)
 {
   if (non_stop)
     {
-      if (ptid_equal (ptid, minus_one_ptid))
-	iterate_over_lwps (send_sigint_callback, &ptid);
-      else
-	{
-	  struct lwp_info *lp = find_lwp_pid (ptid);
-	  send_sigint_callback (lp, NULL);
-	}
+      linux_nat_async_events (sigchld_sync);
+      iterate_over_lwps (linux_nat_stop_lwp, &ptid);
+      target_async (inferior_event_handler, 0);
     }
   else
     linux_ops->to_stop (ptid);
Index: src/gdb/doc/observer.texi
===================================================================
--- src.orig/gdb/doc/observer.texi	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/doc/observer.texi	2008-10-24 00:07:12.000000000 +0100
@@ -135,6 +135,14 @@ The thread specified by @var{t} has been
 The thread specified by @var{t} has exited.
 @end deftypefun
 
+@deftypefun void thread_stop_requested (ptid_t @var{ptid})
+An explicit stop request was issued to @var{ptid}.  If @var{ptid}
+equals @var{minus_one_ptid}, the request applied to all threads.  If
+@code{ptid_is_pid(ptid)} returns true, the request applied to all
+threads of the process pointed at by @var{ptid}.  Otherwise, the
+request applied to the single thread pointed at by @var{ptid}.
+@end deftypefun
+
 @deftypefun void target_resumed (ptid_t @var{ptid})
 The target was resumed.  The @var{ptid} parameter specifies which
 thread was resume, and may be RESUME_ALL if all threads are resumed.
Index: src/gdb/testsuite/lib/mi-support.exp
===================================================================
--- src.orig/gdb/testsuite/lib/mi-support.exp	2008-10-24 00:03:22.000000000 +0100
+++ src/gdb/testsuite/lib/mi-support.exp	2008-10-24 00:07:12.000000000 +0100
@@ -1050,7 +1050,7 @@ proc mi_expect_interrupt { test } {
 	set prompt_re "$mi_gdb_prompt$"
     }
 
-    set r "reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\""
+    set r "reason=\"signal-received\",signal-name=\"0\",signal-meaning=\"Signal 0\""
 
     set any "\[^\n\]*"
 

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