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

Re: remote debugging a multi-threaded program with signal


On Fri, Mar 05, 2004 at 12:05:40AM +0900, Atsushi Nemoto wrote:
> >>>>> On Thu, 04 Mar 2004 01:06:24 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> said:
> 
> anemo> There is a program on remote-debugging a multi-threaded program
> anemo> which uses signals.  After receiving a signal (configured to
> anemo> "nostop"), the thread which receives it resumes normally but
> anemo> other threads leave stopped.
> 
> The last packet sent to gdbserver is "$vCont;C1e:402" (see gdb.output1).
> 
> gdb's info states:
> 
> `vCont'[;ACTION[`:'TID]]... -- extended resume
>      Resume the inferior.  Different actions may be specified for each
>      thread.  If an action is specified with no TID, then it is applied
>      to any threads that don't have a specific action specified; if no
>      default action is specified then other threads should remain
>      stopped.  ...
> 
> So the patcket means "continue thread 0x402 with signal 0x1e, others
> remain stopped".  Then current gdbserver's behavior is correct.  
> 
> Following the info statements, gdb should send "$vCont;C1e:402;c" to
> handle a "nostop" signal correctly?

I thought you said you got the same results without verbose-resume?
Oh, I suppose you would; without verbose-resume it's pot-luck which
thread gets the signal.

If I use a pre-vCont gdb client with the current gdbserver I see:

[sigtest:30016:16384]:main
[sigtest:30018:16386]:func
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1
[sigtest:30016:16384]:send SIGUSR1

This means that the signal is being delivered to the wrong thread,
since neither thread appears to be stopped.  Which is what I would
expect without vCont, since vCont was intended to solve this exact
problem.

GDB's behavior with threads is a little under-specified, but code to
generate the "correct" vCont packet is definitely there.  Unfortunately
it is not reached.  We get this:

Breakpoint 1, remote_vcont_resume (ptid={pid = 16386, lwp = 0, tid = 0}, step=0,
    siggnal=TARGET_SIGNAL_USR1) at /opt/src/gdb/src/gdb/remote.c:2461

i.e. the remote target was asked to resume only one thread.

Aha, here's the bug:
      /* If it's not SIGTRAP and not a signal we want to stop for, then
         continue the thread. */

      if (stop_signal != TARGET_SIGNAL_TRAP && !signal_stop[stop_signal])
        {
          if (printed)
            target_terminal_inferior ();

          /* Clear the signal if it should not be passed.  */
          if (signal_program[stop_signal] == 0)
            stop_signal = TARGET_SIGNAL_0;

          target_resume (ecs->ptid, 0, stop_signal);
          prepare_to_wait (ecs);
          return;
        }

That resumes only the thread in question.  This is in
target-indepenedent code and the only reason that lin-lwp native
execution does not show the same problem is that it shortcuts around
this code completely (see lin_lwp_wait).

Could you try this instead?

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2004-03-04  Daniel Jacobowitz  <drow@mvista.com>

	* infrun.c (handle_inferior_event): Pass nostop signals to the
	correct thread.

Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.137
diff -u -p -r1.137 infrun.c
--- infrun.c	16 Feb 2004 20:49:51 -0000	1.137
+++ infrun.c	4 Mar 2004 22:27:11 -0000
@@ -1918,32 +1918,29 @@ handle_inferior_event (struct execution_
 #endif
 	}
 
+      context_switch (ecs);
+
+      if (context_hook)
+	context_hook (pid_to_thread_id (ecs->ptid));
+
+      flush_cached_frames ();
+
       /* If it's not SIGTRAP and not a signal we want to stop for, then
          continue the thread. */
 
       if (stop_signal != TARGET_SIGNAL_TRAP && !signal_stop[stop_signal])
 	{
-	  if (printed)
-	    target_terminal_inferior ();
-
 	  /* Clear the signal if it should not be passed.  */
 	  if (signal_program[stop_signal] == 0)
 	    stop_signal = TARGET_SIGNAL_0;
 
-	  target_resume (ecs->ptid, 0, stop_signal);
+	  resume (currently_stepping (ecs), stop_signal);
 	  prepare_to_wait (ecs);
 	  return;
 	}
 
-      /* It's a SIGTRAP or a signal we're interested in.  Switch threads,
-         and fall into the rest of wait_for_inferior().  */
-
-      context_switch (ecs);
-
-      if (context_hook)
-	context_hook (pid_to_thread_id (ecs->ptid));
-
-      flush_cached_frames ();
+      /* It's a SIGTRAP or a signal we're interested in.  Fall into the
+         rest of wait_for_inferior().  */
     }
 
   if (SOFTWARE_SINGLE_STEP_P () && singlestep_breakpoints_inserted_p)


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