[v2] Always pass signals to the right thread.

Message ID 53A9648F.1030006@redhat.com
State Committed
Headers

Commit Message

Pedro Alves June 24, 2014, 11:44 a.m. UTC
  On 06/23/2014 03:28 AM, Yao Qi wrote:
> On 06/19/2014 09:09 PM, Pedro Alves wrote:
>>   (gdb) thread 1
>>   [Switching to thread 1 (Thread 10979)]
>>   (gdb) signal SIGUSR2
>>   Note:
>>     Thread 3 previously stopped with signal SIGUSR2, User defined signal 2.
>>     Thread 2 previously stopped with signal SIGUSR1, User defined signal 1.
>>   Continuing thread 1 (the current thread) with specified signal will
>>   still deliver the signals noted above to their respective threads.
>>   Continue anyway? (y or n)
> 
> This message isn't clear to me, because user has to read this sentence
> and think what GDB will do for these threads.

Well, stop and think is the point of the warning/query.  :-)

> IMO, it is better to say
> explicitly what GDB will do for each thread, like
> 
> (gdb) signal SIGUSR2
>   Continuing Thread 3 with signal SIGUSR2, User defined signal 2.
>   Continuing Thread 2 with signal SIGUSR1, User defined signal 1.
>   Continuing Thread 1 with signal SIGUSR2, User defined signal 2.
> Continue anyway? (y or n)

Thanks.  Even though it first appeared promising, I've been playing
with this since yesterday and in the end I can't seem to find it
really better.  :-/
(I had already contemplated lots of different options before
posting the original patch.)

That kind of reads to me like only those three threads
are continued.  With my user hat on, that then makes me wonder what
will happen to all the other threads not listed.  And why is GDB
really telling about these signal that I didn't specify?  And which
is the one that is getting the signal because I'm overriding
it?  Thread 3 or thread 1?  And that output would seem to make more
sense to me if we always asked for confirmation even if no thread
other than the current would get a signal, otherwise, the user has
no clue really why he's being asked for confirmation), but I'm not sure
that'd be a good idea.  (Also, I think the output should still
make sense if we ever find a need to add a cap on the number of
threads listed and say "many threads" instead of showing a list.)

In any case, I still tried this direction, by doing two passes
over the threads, to determine whether we need to ask for confirmation,
and added an intro text:

(gdb) signal SIGUSR1
Some of the threads other than the current that are also about to be resumed had previously stopped for signals.
If you proceed, those signals will be delivered to the respective threads.
  Continuing thread 3 with signal SIGUSR2.
  Continuing thread 1 with signal SIGUSR1.
Continue anyway? (y or n)

But, what about "signal 0" ?  That results in:

(gdb) signal 0
Some of the threads other than the current that are also about to be resumed had previously stopped for signals.
If you proceed, those signals will be delivered to the respective threads.
  Continuing thread 3 with signal SIGUSR2.
  Continuing thread 1 with no signal.
Continue anyway? (y or n)

And again, that makes me wonder why "no signal" is mentioned for only
one thread and not any other that will be resumed with no signal
either (because it hadn't stopped with one).

We could then list what will happen to _all_ threads that will be
resumed, with or without signal, but I _really_ don't think it's
a good idea -- that set will usually be _much_ larger than the
signalled threads, which will normally be just one.

So all in all, in the end, I still prefer my original output.

> We may need a NEWS entry, as this is a user-visible change.

Done.

>> +      ALL_NON_EXITED_THREADS (tp)
>> +        {
> 
> Replace eight spaces with a tab.

Thanks, fixed.

> 
>> @@ -5190,6 +5161,10 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
>>  	 what keep_going does as well, if we call it.  */
>>        ecs->event_thread->control.trap_expected = 0;
>>  
>> +      /* Likewise, clear the signal if it should not be passed.  */
>> +      if (!signal_program[ecs->event_thread->suspend.stop_signal])
>> +	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
>> +
> 
> I can understand this patch except this part.  Why do we need to set
> stop_signal here?

We can get here with the stop signal set to GDB_SIGNAL_TRAP due
to a breakpoint of a finished step.  If we don't clear it now,
the next time we'll resume the target, and this thread isn't
current, we'd pass the trap to the thread.  See below for further
explanation.

> 
>> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
>> index c9677ca..8f2600d 100644
>> --- a/gdb/linux-nat.c
>> +++ b/gdb/linux-nat.c
>> @@ -1694,8 +1694,7 @@ linux_nat_resume_callback (struct lwp_info *lp, void *except)
>>        thread = find_thread_ptid (lp->ptid);
>>        if (thread != NULL)
>>  	{
>> -	  if (signal_pass_state (thread->suspend.stop_signal))
>> -	    signo = thread->suspend.stop_signal;
>> +	  signo = thread->suspend.stop_signal;
>>  	  thread->suspend.stop_signal = GDB_SIGNAL_0;
>>  	}


> 
> You didn't say much about these two changes.  Is it because we've
> already set thread->suspend.stop_signal to GDB_SIGNAL_0 if
> signal_pass_state (tp->suspend.stop_signal) is false,

...

> 
> +  /* If this signal should not be seen by program, give it zero.
> +     Used for debugging signals.  */
> +  if (!signal_pass_state (tp->suspend.stop_signal))
> +    tp->suspend.stop_signal = GDB_SIGNAL_0;
> +
> 
> that means (tp->suspend.stop_signal == GDB_SIGNAL_0 ||
> signal_pass_state (tp->suspend.stop_signal)) is constantly true.
> so in the callees of target_resume, signal_pass_state
> (thread->suspend.stop_signal) is always true if
> thread->suspend.stop_signal isn't GDB_SIGNAL_0?

Nope, "signal SIGFOO" should still pass SIGFOO even if
"handle SIGFOO nopass".  So in that case, 
signal_pass_state (thread->suspend.stop_signal) is false,
but we should still pass stop_signal.  We assume the thread
that was current at "signal SIGFOO" time will be resumed immediately,
because GDB may need to e.g., step-over a breakpoint for another
thread first.  So we store the intent to pass SIGFOO once the
step over is finished in stop_signal.

I've added this comment:

 --- c/gdb/gdbthread.h
 +++ w/gdb/gdbthread.h
 @@ -135,7 +135,13 @@ struct thread_control_state
 
  struct thread_suspend_state
  {
 -  /* Last signal that the inferior received (why it stopped).  */
 +  /* Last signal that the inferior received (why it stopped).  When
 +     the thread is resumed, this signal is delivered.  Note: the
 +     target should not check whether the signal is in pass state,
 +     because the signal may have been explicitly passed with the
 +     "signal" command, which overrides "handle nopass".  If the signal
 +     should be suppressed, the core will take care of clearing this
 +     before the target is resumed.  */
    enum gdb_signal stop_signal;
  };

Does that make things clearer ?


>> +
>> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
>> +	 executable { debug }] != "" } {
>> +    return -1
>> +}
> 
> Need [target_info exists gdb,nosignals] check?

Yeah, thanks.

> 
>> +
>> +# Run the test proper.  STEP_OVER indicates whether we leave in place
>> +# a breakpoint that needs to be stepped over when we explicitly
>> +# request a signal be delivered with the "signal" command.
>> +
>> +proc test { step_over } {
>> +    global srcfile binfile
>> +
>> +    with_test_prefix "step-over $step_over" {
>> +	clean_restart ${binfile}
>> +
>> +	if ![runto_main] then {
>> +	    fail "Can't run to main"
>> +	    return 0
>> +	}
>> +
>> +	gdb_test "handle SIGUSR1 stop print nopass"
>> +
>> +	gdb_test "b thread_function" "Breakpoint .* at .*$srcfile.*"
>> +	gdb_test "continue" "thread_function.*" "stopped in thread"
>> +
>> +	# Thread 2 is stopped at a breakpoint.  If we leave the
>> +	# breakpoint in place, GDB needs to move thread 2 past the
>> +	# breakpoint before delivering the signal to thread 1.  We
>> +	# want to be sure that GDB doesn't mistakenly deliver the
>> +	# signal to thread 1 while doing that.
>> +	if { $step_over == "no" } {
>> +	    delete_breakpoints
>> +	}
>> +
>> +	gdb_test "break handler" "Breakpoint .* at .*$srcfile.*"
>> +
>> +	gdb_test "thread 1" "Switching to thread 1.*"
>> +
>> +	set ws "\[ \t\]+"
>> +	set line "\[^\r\n\]+"
>> +
>> +	set pattern ""
>> +	append pattern "${ws}2${ws}Thread ${line}\r\n"
>> +	append pattern "\\\* 1${ws}Thread ${line}.*"
>> +
>> +	gdb_test "info threads" $pattern "thread 1 selected"
> 
> We want to know whether thread 1 is selected, so using "info threads 1"
> is simpler in the regexp pattern, like
> 
>  gdb_test "info threads 1" "\\\* 1${ws}Thread .*" "thread 1 selected"

The reason I don't like "info threads 1" this is that if the test fails,
when you go look at the logs, you don't see which thread was actually
current, which tends to make debugging things a little easier.   But we
can still simplify the patterns.  I was aiming at having no wildcards in
the middle of the output, but that's really not necessary.
I've simplified the patterns now.

Here's the updated patch.

8<-------------------------------
From 5834f1fea7d303e3964751d6af505cac44fd1754 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Tue, 24 Jun 2014 12:12:57 +0100
Subject: [PATCH] Always pass signals to the right thread.

Currently, GDB can pass a signal to the wrong thread in several
different but related scenarios.

E.g., if thread 1 stops for signal SIGFOO, the user switches to thread
2, and then issues "continue", SIGFOO is actually delivered to thread
2, not thread 1.  This obviously messes up programs that use
pthread_kill to send signals to specific threads.

This has been a known issue for a long while.  Back in 2008 when I
made stop_signal be per-thread (2020b7ab), I kept the behavior -- see
code in 'proceed' being removed -- wanting to come back to it later.
The time has finally come now.

The patch fixes this -- on resumption, intercepted signals are always
delivered to the thread that had intercepted them.

Another example: if thread 1 stops for a breakpoint, the user switches
to thread 2, and then issues "signal SIGFOO", SIGFOO is actually
delivered to thread 1, not thread 2, because 'proceed' first switches
to thread 1 to step over its breakpoint...  If the user deletes the
breakpoint before issuing "signal FOO", then the signal is delivered
to thread 2 (the current thread).

"signal SIGFOO" can be used for two things: inject a signal in the
program while the program/thread had stopped for none, bypassing
"handle nopass"; or changing/suppressing a signal the program had
stopped for.  These scenarios are really two faces of the same coin,
and GDB can't really guess what the user is trying to do.  GDB might
have intercepted signals in more than one thread even (see the new
signal-command-multiple-signals-pending.exp test).  At least in the
inject case, it's obviously clear to me that the user means to deliver
the signal to the currently selected thread, so best is to make the
command's behavior consistent and easy to explain.

Then, if the user is trying to suppress/change a signal the program
had stopped for instead of injecting a new signal, but, the user had
changed threads meanwhile, then she will be surprised that with:

  (gdb) continue
  Thread 1 stopped for signal SIGFOO.
  (gdb) thread 2
  (gdb) signal SIGBAR

... GDB actually delivers SIGFOO to thread 1, and SIGBAR to thread 2
(with scheduler-locking off, which is the default, because then
"signal" or any other resumption command resumes all threads).

So the patch makes GDB detect that, and ask for confirmation:

  (gdb) thread 1
  [Switching to thread 1 (Thread 10979)]
  (gdb) signal SIGUSR2
  Note:
    Thread 3 previously stopped with signal SIGUSR2, User defined signal 2.
    Thread 2 previously stopped with signal SIGUSR1, User defined signal 1.
  Continuing thread 1 (the current thread) with specified signal will
  still deliver the signals noted above to their respective threads.
  Continue anyway? (y or n)

All these scenarios are covered by the new tests.

Tested on x86_64 Fedora 20, native and gdbserver.

gdb/
2014-06-24  Pedro Alves  <palves@redhat.com>

	* NEWS: Mention signal passing and "signal" command changes.

	* gdbthread.h (struct thread_suspend_state) <stop_signal>: Extend
	comment.
	* breakpoint.c (until_break_command): Adjust clear_proceed_status
	call.
	* infcall.c (run_inferior_call): Adjust clear_proceed_status call.
	* infcmd.c (proceed_thread_callback, continue_1, step_once)
	(jump_command): Adjust clear_proceed_status call.
	(signal_command): Warn if other thread that are resumed have
	signals that will be delivered.  Adjust clear_proceed_status call.
	(until_next_command, finish_command)
	(proceed_after_attach_callback, attach_command_post_wait)
	(attach_command): Adjust clear_proceed_status call.
	* infrun.c (proceed_after_vfork_done): Likewise.
	(proceed_after_attach_callback): Adjust comment.
	(clear_proceed_status_thread): Clear stop_signal if not in pass
	state.
	(clear_proceed_status_callback): Delete.
	(clear_proceed_status): New 'step' parameter.  Only clear the
	proceed status of threads the command being prepared is about to
	resume.
	(proceed): If passed in an explicit signal, override stop_signal
	with it.  Don't pass the last stop signal to the thread we're
	resuming.
	(init_wait_for_inferior): Adjust clear_proceed_status call.
	(switch_back_to_stepped_thread): Clear the signal if it should not
	be passed.
	* infrun.h (clear_proceed_status): New 'step' parameter.
	(user_visible_resume_ptid): Add comment.
	* linux-nat.c (linux_nat_resume_callback): Don't check whether the
	signal is in pass state.
	* remote.c (append_pending_thread_resumptions): Likewise.
	* mi/mi-main.c (proceed_thread): Adjust clear_proceed_status call.


gdb/doc/
2014-06-24  Pedro Alves  <palves@redhat.com>

	* gdb.texinfo (Signaling) <signal command>: Explain what happens
	with multi-threaded programs.

gdb/testsuite/
2014-06-24  Pedro Alves  <palves@redhat.com>

	* gdb.threads/signal-command-handle-nopass.c: New file.
	* gdb.threads/signal-command-handle-nopass.exp: New file.
	* gdb.threads/signal-command-multiple-signals-pending.c: New file.
	* gdb.threads/signal-command-multiple-signals-pending.exp: New file.
	* gdb.threads/signal-delivered-right-thread.c: New file.
	* gdb.threads/signal-delivered-right-thread.exp: New file.
---
 gdb/NEWS                                           |  11 ++
 gdb/breakpoint.c                                   |   2 +-
 gdb/doc/gdb.texinfo                                |  10 +-
 gdb/gdbthread.h                                    |   8 +-
 gdb/infcall.c                                      |   2 +-
 gdb/infcmd.c                                       |  64 ++++++--
 gdb/infrun.c                                       |  93 +++++-------
 gdb/infrun.h                                       |   8 +-
 gdb/linux-nat.c                                    |   3 +-
 gdb/mi/mi-main.c                                   |   2 +-
 gdb/remote.c                                       |   3 +-
 .../gdb.threads/signal-command-handle-nopass.c     |  49 ++++++
 .../gdb.threads/signal-command-handle-nopass.exp   |  78 ++++++++++
 .../signal-command-multiple-signals-pending.c      |  98 ++++++++++++
 .../signal-command-multiple-signals-pending.exp    | 166 +++++++++++++++++++++
 .../gdb.threads/signal-delivered-right-thread.c    |  61 ++++++++
 .../gdb.threads/signal-delivered-right-thread.exp  |  85 +++++++++++
 17 files changed, 664 insertions(+), 79 deletions(-)
 create mode 100644 gdb/testsuite/gdb.threads/signal-command-handle-nopass.c
 create mode 100644 gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp
 create mode 100644 gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c
 create mode 100644 gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp
 create mode 100644 gdb/testsuite/gdb.threads/signal-delivered-right-thread.c
 create mode 100644 gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp
  

Comments

Yao Qi June 26, 2014, 5:45 a.m. UTC | #1
On 06/24/2014 07:44 PM, Pedro Alves wrote:
> But, what about "signal 0" ?  That results in:
> 
> (gdb) signal 0
> Some of the threads other than the current that are also about to be resumed had previously stopped for signals.
> If you proceed, those signals will be delivered to the respective threads.
>   Continuing thread 3 with signal SIGUSR2.
>   Continuing thread 1 with no signal.
> Continue anyway? (y or n)
> 
> And again, that makes me wonder why "no signal" is mentioned for only
> one thread and not any other that will be resumed with no signal
> either (because it hadn't stopped with one).
> 
> We could then list what will happen to _all_ threads that will be
> resumed, with or without signal, but I _really_ don't think it's
> a good idea -- that set will usually be _much_ larger than the
> signalled threads, which will normally be just one.

Agreed.

> 
> So all in all, in the end, I still prefer my original output.

That is fine by me.

>> > 
>>> >> @@ -5190,6 +5161,10 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
>>> >>  	 what keep_going does as well, if we call it.  */
>>> >>        ecs->event_thread->control.trap_expected = 0;
>>> >>  
>>> >> +      /* Likewise, clear the signal if it should not be passed.  */
>>> >> +      if (!signal_program[ecs->event_thread->suspend.stop_signal])
>>> >> +	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
>>> >> +
>> > 
>> > I can understand this patch except this part.  Why do we need to set
>> > stop_signal here?
> We can get here with the stop signal set to GDB_SIGNAL_TRAP due
> to a breakpoint of a finished step.  If we don't clear it now,
> the next time we'll resume the target, and this thread isn't
> current, we'd pass the trap to the thread.  See below for further
> explanation.
> 

Right, without this part, I can get this:

"Program terminated with signal SIGTRAP, Trace/breakpoint trap."

>> > 
>>> >> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
>>> >> index c9677ca..8f2600d 100644
>>> >> --- a/gdb/linux-nat.c
>>> >> +++ b/gdb/linux-nat.c
>>> >> @@ -1694,8 +1694,7 @@ linux_nat_resume_callback (struct lwp_info *lp, void *except)
>>> >>        thread = find_thread_ptid (lp->ptid);
>>> >>        if (thread != NULL)
>>> >>  	{
>>> >> -	  if (signal_pass_state (thread->suspend.stop_signal))
>>> >> -	    signo = thread->suspend.stop_signal;
>>> >> +	  signo = thread->suspend.stop_signal;
>>> >>  	  thread->suspend.stop_signal = GDB_SIGNAL_0;
>>> >>  	}
> 
>> > 
>> > You didn't say much about these two changes.  Is it because we've
>> > already set thread->suspend.stop_signal to GDB_SIGNAL_0 if
>> > signal_pass_state (tp->suspend.stop_signal) is false,
> ...
> 
>> > 
>> > +  /* If this signal should not be seen by program, give it zero.
>> > +     Used for debugging signals.  */
>> > +  if (!signal_pass_state (tp->suspend.stop_signal))
>> > +    tp->suspend.stop_signal = GDB_SIGNAL_0;
>> > +
>> > 
>> > that means (tp->suspend.stop_signal == GDB_SIGNAL_0 ||
>> > signal_pass_state (tp->suspend.stop_signal)) is constantly true.
>> > so in the callees of target_resume, signal_pass_state
>> > (thread->suspend.stop_signal) is always true if
>> > thread->suspend.stop_signal isn't GDB_SIGNAL_0?
> Nope, "signal SIGFOO" should still pass SIGFOO even if
> "handle SIGFOO nopass".  So in that case, 
> signal_pass_state (thread->suspend.stop_signal) is false,
> but we should still pass stop_signal.  We assume the thread

Yeah, that is why I am confused on this....

> that was current at "signal SIGFOO" time will be resumed immediately,
> because GDB may need to e.g., step-over a breakpoint for another
> thread first.  So we store the intent to pass SIGFOO once the
> step over is finished in stop_signal.
> 
> I've added this comment:
> 
>  --- c/gdb/gdbthread.h
>  +++ w/gdb/gdbthread.h
>  @@ -135,7 +135,13 @@ struct thread_control_state
>  
>   struct thread_suspend_state
>   {
>  -  /* Last signal that the inferior received (why it stopped).  */
>  +  /* Last signal that the inferior received (why it stopped).  When
>  +     the thread is resumed, this signal is delivered.  Note: the
>  +     target should not check whether the signal is in pass state,
>  +     because the signal may have been explicitly passed with the
>  +     "signal" command, which overrides "handle nopass".  If the signal
>  +     should be suppressed, the core will take care of clearing this
>  +     before the target is resumed.  */
>     enum gdb_signal stop_signal;
>   };
> 
> Does that make things clearer ?
> 

Yes, it is clearer.  Now, "stop_signal" is the signal to be delivered
to the inferior, either from the program or from "signal" command.


>> > We want to know whether thread 1 is selected, so using "info threads 1"
>> > is simpler in the regexp pattern, like
>> > 
>> >  gdb_test "info threads 1" "\\\* 1${ws}Thread .*" "thread 1 selected"
> The reason I don't like "info threads 1" this is that if the test fails,
> when you go look at the logs, you don't see which thread was actually
> current, which tends to make debugging things a little easier.   But we
> can still simplify the patterns.  I was aiming at having no wildcards in
> the middle of the output, but that's really not necessary.
> I've simplified the patterns now.

OK.

> 
> Here's the updated patch.

Patch looks good to me.
  
Pedro Alves July 24, 2014, 3:40 p.m. UTC | #2
Hi Eli,

Could you take a look at the documentation bits of this patch?

Thanks!

Pedro Alves

On 06/24/2014 12:44 PM, Pedro Alves wrote:
> On 06/23/2014 03:28 AM, Yao Qi wrote:
>> On 06/19/2014 09:09 PM, Pedro Alves wrote:
>>>   (gdb) thread 1
>>>   [Switching to thread 1 (Thread 10979)]
>>>   (gdb) signal SIGUSR2
>>>   Note:
>>>     Thread 3 previously stopped with signal SIGUSR2, User defined signal 2.
>>>     Thread 2 previously stopped with signal SIGUSR1, User defined signal 1.
>>>   Continuing thread 1 (the current thread) with specified signal will
>>>   still deliver the signals noted above to their respective threads.
>>>   Continue anyway? (y or n)
>>
>> This message isn't clear to me, because user has to read this sentence
>> and think what GDB will do for these threads.
> 
> Well, stop and think is the point of the warning/query.  :-)
> 
>> IMO, it is better to say
>> explicitly what GDB will do for each thread, like
>>
>> (gdb) signal SIGUSR2
>>   Continuing Thread 3 with signal SIGUSR2, User defined signal 2.
>>   Continuing Thread 2 with signal SIGUSR1, User defined signal 1.
>>   Continuing Thread 1 with signal SIGUSR2, User defined signal 2.
>> Continue anyway? (y or n)
> 
> Thanks.  Even though it first appeared promising, I've been playing
> with this since yesterday and in the end I can't seem to find it
> really better.  :-/
> (I had already contemplated lots of different options before
> posting the original patch.)
> 
> That kind of reads to me like only those three threads
> are continued.  With my user hat on, that then makes me wonder what
> will happen to all the other threads not listed.  And why is GDB
> really telling about these signal that I didn't specify?  And which
> is the one that is getting the signal because I'm overriding
> it?  Thread 3 or thread 1?  And that output would seem to make more
> sense to me if we always asked for confirmation even if no thread
> other than the current would get a signal, otherwise, the user has
> no clue really why he's being asked for confirmation), but I'm not sure
> that'd be a good idea.  (Also, I think the output should still
> make sense if we ever find a need to add a cap on the number of
> threads listed and say "many threads" instead of showing a list.)
> 
> In any case, I still tried this direction, by doing two passes
> over the threads, to determine whether we need to ask for confirmation,
> and added an intro text:
> 
> (gdb) signal SIGUSR1
> Some of the threads other than the current that are also about to be resumed had previously stopped for signals.
> If you proceed, those signals will be delivered to the respective threads.
>   Continuing thread 3 with signal SIGUSR2.
>   Continuing thread 1 with signal SIGUSR1.
> Continue anyway? (y or n)
> 
> But, what about "signal 0" ?  That results in:
> 
> (gdb) signal 0
> Some of the threads other than the current that are also about to be resumed had previously stopped for signals.
> If you proceed, those signals will be delivered to the respective threads.
>   Continuing thread 3 with signal SIGUSR2.
>   Continuing thread 1 with no signal.
> Continue anyway? (y or n)
> 
> And again, that makes me wonder why "no signal" is mentioned for only
> one thread and not any other that will be resumed with no signal
> either (because it hadn't stopped with one).
> 
> We could then list what will happen to _all_ threads that will be
> resumed, with or without signal, but I _really_ don't think it's
> a good idea -- that set will usually be _much_ larger than the
> signalled threads, which will normally be just one.
> 
> So all in all, in the end, I still prefer my original output.
> 
>> We may need a NEWS entry, as this is a user-visible change.
> 
> Done.
> 
>>> +      ALL_NON_EXITED_THREADS (tp)
>>> +        {
>>
>> Replace eight spaces with a tab.
> 
> Thanks, fixed.
> 
>>
>>> @@ -5190,6 +5161,10 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
>>>  	 what keep_going does as well, if we call it.  */
>>>        ecs->event_thread->control.trap_expected = 0;
>>>  
>>> +      /* Likewise, clear the signal if it should not be passed.  */
>>> +      if (!signal_program[ecs->event_thread->suspend.stop_signal])
>>> +	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
>>> +
>>
>> I can understand this patch except this part.  Why do we need to set
>> stop_signal here?
> 
> We can get here with the stop signal set to GDB_SIGNAL_TRAP due
> to a breakpoint of a finished step.  If we don't clear it now,
> the next time we'll resume the target, and this thread isn't
> current, we'd pass the trap to the thread.  See below for further
> explanation.
> 
>>
>>> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
>>> index c9677ca..8f2600d 100644
>>> --- a/gdb/linux-nat.c
>>> +++ b/gdb/linux-nat.c
>>> @@ -1694,8 +1694,7 @@ linux_nat_resume_callback (struct lwp_info *lp, void *except)
>>>        thread = find_thread_ptid (lp->ptid);
>>>        if (thread != NULL)
>>>  	{
>>> -	  if (signal_pass_state (thread->suspend.stop_signal))
>>> -	    signo = thread->suspend.stop_signal;
>>> +	  signo = thread->suspend.stop_signal;
>>>  	  thread->suspend.stop_signal = GDB_SIGNAL_0;
>>>  	}
> 
> 
>>
>> You didn't say much about these two changes.  Is it because we've
>> already set thread->suspend.stop_signal to GDB_SIGNAL_0 if
>> signal_pass_state (tp->suspend.stop_signal) is false,
> 
> ...
> 
>>
>> +  /* If this signal should not be seen by program, give it zero.
>> +     Used for debugging signals.  */
>> +  if (!signal_pass_state (tp->suspend.stop_signal))
>> +    tp->suspend.stop_signal = GDB_SIGNAL_0;
>> +
>>
>> that means (tp->suspend.stop_signal == GDB_SIGNAL_0 ||
>> signal_pass_state (tp->suspend.stop_signal)) is constantly true.
>> so in the callees of target_resume, signal_pass_state
>> (thread->suspend.stop_signal) is always true if
>> thread->suspend.stop_signal isn't GDB_SIGNAL_0?
> 
> Nope, "signal SIGFOO" should still pass SIGFOO even if
> "handle SIGFOO nopass".  So in that case, 
> signal_pass_state (thread->suspend.stop_signal) is false,
> but we should still pass stop_signal.  We assume the thread
> that was current at "signal SIGFOO" time will be resumed immediately,
> because GDB may need to e.g., step-over a breakpoint for another
> thread first.  So we store the intent to pass SIGFOO once the
> step over is finished in stop_signal.
> 
> I've added this comment:
> 
>  --- c/gdb/gdbthread.h
>  +++ w/gdb/gdbthread.h
>  @@ -135,7 +135,13 @@ struct thread_control_state
>  
>   struct thread_suspend_state
>   {
>  -  /* Last signal that the inferior received (why it stopped).  */
>  +  /* Last signal that the inferior received (why it stopped).  When
>  +     the thread is resumed, this signal is delivered.  Note: the
>  +     target should not check whether the signal is in pass state,
>  +     because the signal may have been explicitly passed with the
>  +     "signal" command, which overrides "handle nopass".  If the signal
>  +     should be suppressed, the core will take care of clearing this
>  +     before the target is resumed.  */
>     enum gdb_signal stop_signal;
>   };
> 
> Does that make things clearer ?
> 
> 
>>> +
>>> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
>>> +	 executable { debug }] != "" } {
>>> +    return -1
>>> +}
>>
>> Need [target_info exists gdb,nosignals] check?
> 
> Yeah, thanks.
> 
>>
>>> +
>>> +# Run the test proper.  STEP_OVER indicates whether we leave in place
>>> +# a breakpoint that needs to be stepped over when we explicitly
>>> +# request a signal be delivered with the "signal" command.
>>> +
>>> +proc test { step_over } {
>>> +    global srcfile binfile
>>> +
>>> +    with_test_prefix "step-over $step_over" {
>>> +	clean_restart ${binfile}
>>> +
>>> +	if ![runto_main] then {
>>> +	    fail "Can't run to main"
>>> +	    return 0
>>> +	}
>>> +
>>> +	gdb_test "handle SIGUSR1 stop print nopass"
>>> +
>>> +	gdb_test "b thread_function" "Breakpoint .* at .*$srcfile.*"
>>> +	gdb_test "continue" "thread_function.*" "stopped in thread"
>>> +
>>> +	# Thread 2 is stopped at a breakpoint.  If we leave the
>>> +	# breakpoint in place, GDB needs to move thread 2 past the
>>> +	# breakpoint before delivering the signal to thread 1.  We
>>> +	# want to be sure that GDB doesn't mistakenly deliver the
>>> +	# signal to thread 1 while doing that.
>>> +	if { $step_over == "no" } {
>>> +	    delete_breakpoints
>>> +	}
>>> +
>>> +	gdb_test "break handler" "Breakpoint .* at .*$srcfile.*"
>>> +
>>> +	gdb_test "thread 1" "Switching to thread 1.*"
>>> +
>>> +	set ws "\[ \t\]+"
>>> +	set line "\[^\r\n\]+"
>>> +
>>> +	set pattern ""
>>> +	append pattern "${ws}2${ws}Thread ${line}\r\n"
>>> +	append pattern "\\\* 1${ws}Thread ${line}.*"
>>> +
>>> +	gdb_test "info threads" $pattern "thread 1 selected"
>>
>> We want to know whether thread 1 is selected, so using "info threads 1"
>> is simpler in the regexp pattern, like
>>
>>  gdb_test "info threads 1" "\\\* 1${ws}Thread .*" "thread 1 selected"
> 
> The reason I don't like "info threads 1" this is that if the test fails,
> when you go look at the logs, you don't see which thread was actually
> current, which tends to make debugging things a little easier.   But we
> can still simplify the patterns.  I was aiming at having no wildcards in
> the middle of the output, but that's really not necessary.
> I've simplified the patterns now.
> 
> Here's the updated patch.
> 
> 8<-------------------------------
> From 5834f1fea7d303e3964751d6af505cac44fd1754 Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Tue, 24 Jun 2014 12:12:57 +0100
> Subject: [PATCH] Always pass signals to the right thread.
> 
> Currently, GDB can pass a signal to the wrong thread in several
> different but related scenarios.
> 
> E.g., if thread 1 stops for signal SIGFOO, the user switches to thread
> 2, and then issues "continue", SIGFOO is actually delivered to thread
> 2, not thread 1.  This obviously messes up programs that use
> pthread_kill to send signals to specific threads.
> 
> This has been a known issue for a long while.  Back in 2008 when I
> made stop_signal be per-thread (2020b7ab), I kept the behavior -- see
> code in 'proceed' being removed -- wanting to come back to it later.
> The time has finally come now.
> 
> The patch fixes this -- on resumption, intercepted signals are always
> delivered to the thread that had intercepted them.
> 
> Another example: if thread 1 stops for a breakpoint, the user switches
> to thread 2, and then issues "signal SIGFOO", SIGFOO is actually
> delivered to thread 1, not thread 2, because 'proceed' first switches
> to thread 1 to step over its breakpoint...  If the user deletes the
> breakpoint before issuing "signal FOO", then the signal is delivered
> to thread 2 (the current thread).
> 
> "signal SIGFOO" can be used for two things: inject a signal in the
> program while the program/thread had stopped for none, bypassing
> "handle nopass"; or changing/suppressing a signal the program had
> stopped for.  These scenarios are really two faces of the same coin,
> and GDB can't really guess what the user is trying to do.  GDB might
> have intercepted signals in more than one thread even (see the new
> signal-command-multiple-signals-pending.exp test).  At least in the
> inject case, it's obviously clear to me that the user means to deliver
> the signal to the currently selected thread, so best is to make the
> command's behavior consistent and easy to explain.
> 
> Then, if the user is trying to suppress/change a signal the program
> had stopped for instead of injecting a new signal, but, the user had
> changed threads meanwhile, then she will be surprised that with:
> 
>   (gdb) continue
>   Thread 1 stopped for signal SIGFOO.
>   (gdb) thread 2
>   (gdb) signal SIGBAR
> 
> ... GDB actually delivers SIGFOO to thread 1, and SIGBAR to thread 2
> (with scheduler-locking off, which is the default, because then
> "signal" or any other resumption command resumes all threads).
> 
> So the patch makes GDB detect that, and ask for confirmation:
> 
>   (gdb) thread 1
>   [Switching to thread 1 (Thread 10979)]
>   (gdb) signal SIGUSR2
>   Note:
>     Thread 3 previously stopped with signal SIGUSR2, User defined signal 2.
>     Thread 2 previously stopped with signal SIGUSR1, User defined signal 1.
>   Continuing thread 1 (the current thread) with specified signal will
>   still deliver the signals noted above to their respective threads.
>   Continue anyway? (y or n)
> 
> All these scenarios are covered by the new tests.
> 
> Tested on x86_64 Fedora 20, native and gdbserver.
> 
> gdb/
> 2014-06-24  Pedro Alves  <palves@redhat.com>
> 
> 	* NEWS: Mention signal passing and "signal" command changes.
> 
> 	* gdbthread.h (struct thread_suspend_state) <stop_signal>: Extend
> 	comment.
> 	* breakpoint.c (until_break_command): Adjust clear_proceed_status
> 	call.
> 	* infcall.c (run_inferior_call): Adjust clear_proceed_status call.
> 	* infcmd.c (proceed_thread_callback, continue_1, step_once)
> 	(jump_command): Adjust clear_proceed_status call.
> 	(signal_command): Warn if other thread that are resumed have
> 	signals that will be delivered.  Adjust clear_proceed_status call.
> 	(until_next_command, finish_command)
> 	(proceed_after_attach_callback, attach_command_post_wait)
> 	(attach_command): Adjust clear_proceed_status call.
> 	* infrun.c (proceed_after_vfork_done): Likewise.
> 	(proceed_after_attach_callback): Adjust comment.
> 	(clear_proceed_status_thread): Clear stop_signal if not in pass
> 	state.
> 	(clear_proceed_status_callback): Delete.
> 	(clear_proceed_status): New 'step' parameter.  Only clear the
> 	proceed status of threads the command being prepared is about to
> 	resume.
> 	(proceed): If passed in an explicit signal, override stop_signal
> 	with it.  Don't pass the last stop signal to the thread we're
> 	resuming.
> 	(init_wait_for_inferior): Adjust clear_proceed_status call.
> 	(switch_back_to_stepped_thread): Clear the signal if it should not
> 	be passed.
> 	* infrun.h (clear_proceed_status): New 'step' parameter.
> 	(user_visible_resume_ptid): Add comment.
> 	* linux-nat.c (linux_nat_resume_callback): Don't check whether the
> 	signal is in pass state.
> 	* remote.c (append_pending_thread_resumptions): Likewise.
> 	* mi/mi-main.c (proceed_thread): Adjust clear_proceed_status call.
> 
> 
> gdb/doc/
> 2014-06-24  Pedro Alves  <palves@redhat.com>
> 
> 	* gdb.texinfo (Signaling) <signal command>: Explain what happens
> 	with multi-threaded programs.
> 
> gdb/testsuite/
> 2014-06-24  Pedro Alves  <palves@redhat.com>
> 
> 	* gdb.threads/signal-command-handle-nopass.c: New file.
> 	* gdb.threads/signal-command-handle-nopass.exp: New file.
> 	* gdb.threads/signal-command-multiple-signals-pending.c: New file.
> 	* gdb.threads/signal-command-multiple-signals-pending.exp: New file.
> 	* gdb.threads/signal-delivered-right-thread.c: New file.
> 	* gdb.threads/signal-delivered-right-thread.exp: New file.
> ---
>  gdb/NEWS                                           |  11 ++
>  gdb/breakpoint.c                                   |   2 +-
>  gdb/doc/gdb.texinfo                                |  10 +-
>  gdb/gdbthread.h                                    |   8 +-
>  gdb/infcall.c                                      |   2 +-
>  gdb/infcmd.c                                       |  64 ++++++--
>  gdb/infrun.c                                       |  93 +++++-------
>  gdb/infrun.h                                       |   8 +-
>  gdb/linux-nat.c                                    |   3 +-
>  gdb/mi/mi-main.c                                   |   2 +-
>  gdb/remote.c                                       |   3 +-
>  .../gdb.threads/signal-command-handle-nopass.c     |  49 ++++++
>  .../gdb.threads/signal-command-handle-nopass.exp   |  78 ++++++++++
>  .../signal-command-multiple-signals-pending.c      |  98 ++++++++++++
>  .../signal-command-multiple-signals-pending.exp    | 166 +++++++++++++++++++++
>  .../gdb.threads/signal-delivered-right-thread.c    |  61 ++++++++
>  .../gdb.threads/signal-delivered-right-thread.exp  |  85 +++++++++++
>  17 files changed, 664 insertions(+), 79 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.threads/signal-command-handle-nopass.c
>  create mode 100644 gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp
>  create mode 100644 gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c
>  create mode 100644 gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp
>  create mode 100644 gdb/testsuite/gdb.threads/signal-delivered-right-thread.c
>  create mode 100644 gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index d9a19ae..2b61ff4 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,17 @@
>  
>  *** Changes since GDB 7.8
>  
> +* On resume, GDB now always passes the signal the program had stopped
> +  for to the thread the signal was sent to, even if the user changed
> +  threads before resuming.  Previously GDB would often (but not
> +  always) deliver the signal to the thread that happens to be current
> +  at resume time.
> +
> +* Conversely, the "signal" command now consistently delivers the
> +  requested signal to the current thread.  GDB now asks for
> +  confirmation if the program had stopped for a signal and the user
> +  switched threads meanwhile.
> +
>  *** Changes in GDB 7.8
>  
>  * New command line options
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index b04f3b7..d75e8c7 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -11670,7 +11670,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
>    int thread;
>    struct thread_info *tp;
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>  
>    /* Set a breakpoint where the user wants it and at return from
>       this function.  */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 8588f73..d0afc3d 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -16546,7 +16546,7 @@ detail.
>  @table @code
>  @kindex signal
>  @item signal @var{signal}
> -Resume execution where your program stopped, but immediately give it the
> +Resume execution where your program is stopped, but immediately give it the
>  signal @var{signal}.  The @var{signal} can be the name or the number of a
>  signal.  For example, on many systems @code{signal 2} and @code{signal
>  SIGINT} are both ways of sending an interrupt signal.
> @@ -16557,6 +16557,14 @@ a signal and would ordinarily see the signal when resumed with the
>  @code{continue} command; @samp{signal 0} causes it to resume without a
>  signal.
>  
> +@emph{Note:} When debugging multi-threaded programs, @var{signal} is
> +delivered to the currently selected thread, not the thread that last
> +reported a stop.  If for example the program last stopped on account
> +of a signal in thread 2 and you want to continue execution suppressing
> +that signal, you must have thread 2 selected as current before issuing
> +the @samp{signal 0} command.  @value{GDBN} detects the scenario and
> +asks for confirmation if you had switched threads meanwhile.
> +
>  @code{signal} does not repeat when you press @key{RET} a second time
>  after executing the command.
>  @end table
> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
> index 9ef74cd..522b674 100644
> --- a/gdb/gdbthread.h
> +++ b/gdb/gdbthread.h
> @@ -135,7 +135,13 @@ struct thread_control_state
>  
>  struct thread_suspend_state
>  {
> -  /* Last signal that the inferior received (why it stopped).  */
> +  /* Last signal that the inferior received (why it stopped).  When
> +     the thread is resumed, this signal is delivered.  Note: the
> +     target should not check whether the signal is in pass state,
> +     because the signal may have been explicitly passed with the
> +     "signal" command, which overrides "handle nopass".  If the signal
> +     should be suppressed, the core will take care of clearing this
> +     before the target is resumed.  */
>    enum gdb_signal stop_signal;
>  };
>  
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index 685b8a4..2aaac85 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -391,7 +391,7 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
>  
>    call_thread->control.in_infcall = 1;
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>  
>    disable_watchpoints_before_interactive_call_start ();
>  
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index c4bb401..5c32c5c 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -679,7 +679,7 @@ proceed_thread_callback (struct thread_info *thread, void *arg)
>      return 0;
>  
>    switch_to_thread (thread->ptid);
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>    proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
>    return 0;
>  }
> @@ -745,7 +745,7 @@ continue_1 (int all_threads)
>      {
>        ensure_valid_thread ();
>        ensure_not_running ();
> -      clear_proceed_status ();
> +      clear_proceed_status (0);
>        proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
>      }
>  }
> @@ -1013,7 +1013,7 @@ step_once (int skip_subroutines, int single_inst, int count, int thread)
>  	 THREAD is set.  */
>        struct thread_info *tp = inferior_thread ();
>  
> -      clear_proceed_status ();
> +      clear_proceed_status (!skip_subroutines);
>        set_step_frame ();
>  
>        if (!single_inst)
> @@ -1186,7 +1186,7 @@ jump_command (char *arg, int from_tty)
>        printf_filtered (".\n");
>      }
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>    proceed (addr, GDB_SIGNAL_0, 0);
>  }
>  
> @@ -1245,6 +1245,50 @@ signal_command (char *signum_exp, int from_tty)
>  	oursig = gdb_signal_from_command (num);
>      }
>  
> +  /* Look for threads other than the current that this command ends up
> +     resuming too (due to schedlock off), and warn if they'll get a
> +     signal delivered.  "signal 0" is used to suppress a previous
> +     signal, but if the current thread is no longer the one that got
> +     the signal, then the user is potentially suppressing the signal
> +     of the wrong thread.  */
> +  if (!non_stop)
> +    {
> +      struct thread_info *tp;
> +      ptid_t resume_ptid;
> +      int must_confirm = 0;
> +
> +      /* This indicates what will be resumed.  Either a single thread,
> +	 a whole process, or all threads of all processes.  */
> +      resume_ptid = user_visible_resume_ptid (0);
> +
> +      ALL_NON_EXITED_THREADS (tp)
> +	{
> +	  if (ptid_equal (tp->ptid, inferior_ptid))
> +	    continue;
> +	  if (!ptid_match (tp->ptid, resume_ptid))
> +	    continue;
> +
> +	  if (tp->suspend.stop_signal != GDB_SIGNAL_0
> +	      && signal_pass_state (tp->suspend.stop_signal))
> +	    {
> +	      if (!must_confirm)
> +		printf_unfiltered (_("Note:\n"));
> +	      printf_unfiltered (_("  Thread %d previously stopped with signal %s, %s.\n"),
> +				 tp->num,
> +				 gdb_signal_to_name (tp->suspend.stop_signal),
> +				 gdb_signal_to_string (tp->suspend.stop_signal));
> +	      must_confirm = 1;
> +	    }
> +	}
> +
> +      if (must_confirm
> +	  && !query (_("Continuing thread %d (the current thread) with specified signal will\n"
> +		       "still deliver the signals noted above to their respective threads.\n"
> +		       "Continue anyway? "),
> +		     inferior_thread ()->num))
> +	error (_("Not confirmed."));
> +    }
> +
>    if (from_tty)
>      {
>        if (oursig == GDB_SIGNAL_0)
> @@ -1254,7 +1298,7 @@ signal_command (char *signum_exp, int from_tty)
>  			 gdb_signal_to_name (oursig));
>      }
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>    proceed ((CORE_ADDR) -1, oursig, 0);
>  }
>  
> @@ -1295,7 +1339,7 @@ until_next_command (int from_tty)
>    int thread = tp->num;
>    struct cleanup *old_chain;
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>    set_step_frame ();
>  
>    frame = get_current_frame ();
> @@ -1687,7 +1731,7 @@ finish_command (char *arg, int from_tty)
>    if (frame == 0)
>      error (_("\"finish\" not meaningful in the outermost frame."));
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>  
>    /* Finishing from an inline frame is completely different.  We don't
>       try to show the "return value" - no way to locate it.  So we do
> @@ -2299,7 +2343,7 @@ proceed_after_attach_callback (struct thread_info *thread,
>        && thread->suspend.stop_signal == GDB_SIGNAL_0)
>      {
>        switch_to_thread (thread->ptid);
> -      clear_proceed_status ();
> +      clear_proceed_status (0);
>        proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
>      }
>  
> @@ -2399,7 +2443,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
>  	{
>  	  if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0)
>  	    {
> -	      clear_proceed_status ();
> +	      clear_proceed_status (0);
>  	      proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
>  	    }
>  	}
> @@ -2502,7 +2546,7 @@ attach_command (char *args, int from_tty)
>    /* Set up execution context to know that we should return from
>       wait_for_inferior as soon as the target reports a stop.  */
>    init_wait_for_inferior ();
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>  
>    if (non_stop)
>      {
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index bef69a8..2626233 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -623,7 +623,7 @@ proceed_after_vfork_done (struct thread_info *thread,
>  			    target_pid_to_str (thread->ptid));
>  
>        switch_to_thread (thread->ptid);
> -      clear_proceed_status ();
> +      clear_proceed_status (0);
>        proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
>      }
>  
> @@ -1721,15 +1721,6 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc)
>    return hw_step;
>  }
>  
> -/* Return a ptid representing the set of threads that we will proceed,
> -   in the perspective of the user/frontend.  We may actually resume
> -   fewer threads at first, e.g., if a thread is stopped at a
> -   breakpoint that needs stepping-off, but that should not be visible
> -   to the user/frontend, and neither should the frontend/user be
> -   allowed to proceed any of the threads that happen to be stopped for
> -   internal run control handling, if a previous command wanted them
> -   resumed.  */
> -
>  ptid_t
>  user_visible_resume_ptid (int step)
>  {
> @@ -1757,6 +1748,12 @@ user_visible_resume_ptid (int step)
>        resume_ptid = inferior_ptid;
>      }
>  
> +  /* We may actually resume fewer threads at first, e.g., if a thread
> +     is stopped at a breakpoint that needs stepping-off, but that
> +     should not be visible to the user/frontend, and neither should
> +     the frontend/user be allowed to proceed any of the threads that
> +     happen to be stopped for internal run control handling, if a
> +     previous command wanted them resumed.  */
>    return resume_ptid;
>  }
>  
> @@ -2032,6 +2029,11 @@ clear_proceed_status_thread (struct thread_info *tp)
>  			"infrun: clear_proceed_status_thread (%s)\n",
>  			target_pid_to_str (tp->ptid));
>  
> +  /* If this signal should not be seen by program, give it zero.
> +     Used for debugging signals.  */
> +  if (!signal_pass_state (tp->suspend.stop_signal))
> +    tp->suspend.stop_signal = GDB_SIGNAL_0;
> +
>    tp->control.trap_expected = 0;
>    tp->control.step_range_start = 0;
>    tp->control.step_range_end = 0;
> @@ -2051,26 +2053,24 @@ clear_proceed_status_thread (struct thread_info *tp)
>    bpstat_clear (&tp->control.stop_bpstat);
>  }
>  
> -static int
> -clear_proceed_status_callback (struct thread_info *tp, void *data)
> -{
> -  if (is_exited (tp->ptid))
> -    return 0;
> -
> -  clear_proceed_status_thread (tp);
> -  return 0;
> -}
> -
>  void
> -clear_proceed_status (void)
> +clear_proceed_status (int step)
>  {
>    if (!non_stop)
>      {
> -      /* In all-stop mode, delete the per-thread status of all
> -	 threads, even if inferior_ptid is null_ptid, there may be
> -	 threads on the list.  E.g., we may be launching a new
> -	 process, while selecting the executable.  */
> -      iterate_over_threads (clear_proceed_status_callback, NULL);
> +      struct thread_info *tp;
> +      ptid_t resume_ptid;
> +
> +      resume_ptid = user_visible_resume_ptid (step);
> +
> +      /* In all-stop mode, delete the per-thread status of all threads
> +	 we're about to resume, implicitly and explicitly.  */
> +      ALL_NON_EXITED_THREADS (tp)
> +        {
> +	  if (!ptid_match (tp->ptid, resume_ptid))
> +	    continue;
> +	  clear_proceed_status_thread (tp);
> +	}
>      }
>  
>    if (!ptid_equal (inferior_ptid, null_ptid))
> @@ -2252,6 +2252,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
>        regcache_write_pc (regcache, addr);
>      }
>  
> +  if (siggnal != GDB_SIGNAL_DEFAULT)
> +    tp->suspend.stop_signal = siggnal;
> +
>    /* Record the interpreter that issued the execution command that
>       caused this thread to resume.  If the top level interpreter is
>       MI/async, and the execution command was a CLI command
> @@ -2318,38 +2321,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
>  
>    tp->control.trap_expected = tp->stepping_over_breakpoint;
>  
> -  if (!non_stop)
> -    {
> -      /* Pass the last stop signal to the thread we're resuming,
> -	 irrespective of whether the current thread is the thread that
> -	 got the last event or not.  This was historically GDB's
> -	 behaviour before keeping a stop_signal per thread.  */
> -
> -      struct thread_info *last_thread;
> -      ptid_t last_ptid;
> -      struct target_waitstatus last_status;
> -
> -      get_last_target_status (&last_ptid, &last_status);
> -      if (!ptid_equal (inferior_ptid, last_ptid)
> -	  && !ptid_equal (last_ptid, null_ptid)
> -	  && !ptid_equal (last_ptid, minus_one_ptid))
> -	{
> -	  last_thread = find_thread_ptid (last_ptid);
> -	  if (last_thread)
> -	    {
> -	      tp->suspend.stop_signal = last_thread->suspend.stop_signal;
> -	      last_thread->suspend.stop_signal = GDB_SIGNAL_0;
> -	    }
> -	}
> -    }
> -
> -  if (siggnal != GDB_SIGNAL_DEFAULT)
> -    tp->suspend.stop_signal = siggnal;
> -  /* If this signal should not be seen by program,
> -     give it zero.  Used for debugging signals.  */
> -  else if (!signal_program[tp->suspend.stop_signal])
> -    tp->suspend.stop_signal = GDB_SIGNAL_0;
> -
>    annotate_starting ();
>  
>    /* Make sure that output from GDB appears before output from the
> @@ -2443,7 +2414,7 @@ init_wait_for_inferior (void)
>  
>    breakpoint_init_inferior (inf_starting);
>  
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>  
>    target_last_wait_ptid = minus_one_ptid;
>  
> @@ -5190,6 +5161,10 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
>  	 what keep_going does as well, if we call it.  */
>        ecs->event_thread->control.trap_expected = 0;
>  
> +      /* Likewise, clear the signal if it should not be passed.  */
> +      if (!signal_program[ecs->event_thread->suspend.stop_signal])
> +	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
> +
>        /* If scheduler locking applies even if not stepping, there's no
>  	 need to walk over threads.  Above we've checked whether the
>  	 current thread is stepping.  If some other thread not the
> diff --git a/gdb/infrun.h b/gdb/infrun.h
> index 66612a8..35b2246 100644
> --- a/gdb/infrun.h
> +++ b/gdb/infrun.h
> @@ -83,7 +83,11 @@ extern struct regcache *stop_registers;
>  
>  extern void start_remote (int from_tty);
>  
> -extern void clear_proceed_status (void);
> +/* Clear out all variables saying what to do when inferior is
> +   continued or stepped.  First do this, then set the ones you want,
> +   then call `proceed'.  STEP indicates whether we're preparing for a
> +   step/stepi command.  */
> +extern void clear_proceed_status (int step);
>  
>  extern void proceed (CORE_ADDR, enum gdb_signal, int);
>  
> @@ -91,6 +95,8 @@ extern void proceed (CORE_ADDR, enum gdb_signal, int);
>     Normally, use `proceed', which handles a lot of bookkeeping.  */
>  extern void resume (int, enum gdb_signal);
>  
> +/* Return a ptid representing the set of threads that we will proceed,
> +   in the perspective of the user/frontend.  */
>  extern ptid_t user_visible_resume_ptid (int step);
>  
>  extern void wait_for_inferior (void);
> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index c9677ca..8f2600d 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -1694,8 +1694,7 @@ linux_nat_resume_callback (struct lwp_info *lp, void *except)
>        thread = find_thread_ptid (lp->ptid);
>        if (thread != NULL)
>  	{
> -	  if (signal_pass_state (thread->suspend.stop_signal))
> -	    signo = thread->suspend.stop_signal;
> +	  signo = thread->suspend.stop_signal;
>  	  thread->suspend.stop_signal = GDB_SIGNAL_0;
>  	}
>      }
> diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
> index 96dfc71..26389f1 100644
> --- a/gdb/mi/mi-main.c
> +++ b/gdb/mi/mi-main.c
> @@ -253,7 +253,7 @@ proceed_thread (struct thread_info *thread, int pid)
>      return;
>  
>    switch_to_thread (thread->ptid);
> -  clear_proceed_status ();
> +  clear_proceed_status (0);
>    proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
>  }
>  
> diff --git a/gdb/remote.c b/gdb/remote.c
> index b5318f1..e56cfea 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -4629,8 +4629,7 @@ append_pending_thread_resumptions (char *p, char *endp, ptid_t ptid)
>    ALL_NON_EXITED_THREADS (thread)
>      if (ptid_match (thread->ptid, ptid)
>  	&& !ptid_equal (inferior_ptid, thread->ptid)
> -	&& thread->suspend.stop_signal != GDB_SIGNAL_0
> -	&& signal_pass_state (thread->suspend.stop_signal))
> +	&& thread->suspend.stop_signal != GDB_SIGNAL_0)
>        {
>  	p = append_resumption (p, endp, thread->ptid,
>  			       0, thread->suspend.stop_signal);
> diff --git a/gdb/testsuite/gdb.threads/signal-command-handle-nopass.c b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.c
> new file mode 100644
> index 0000000..abca2f9
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.c
> @@ -0,0 +1,49 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2014 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <pthread.h>
> +#include <signal.h>
> +
> +void
> +handler (int sig)
> +{
> +}
> +
> +void *
> +thread_function (void *arg)
> +{
> +  volatile unsigned int i = 1;
> +
> +  while (i != 0)
> +    usleep (1);
> +}
> +
> +int
> +main (void)
> +{
> +  pthread_t child_thread;
> +  int i;
> +
> +  signal (SIGUSR1, handler);
> +  pthread_create (&child_thread, NULL, thread_function, NULL);
> +  pthread_join (child_thread, NULL);
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp
> new file mode 100644
> index 0000000..3ea9cf8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp
> @@ -0,0 +1,78 @@
> +# Copyright (C) 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +# Test that an explicit "signal FOO" delivers FOO even if "handle" for
> +# that same signal is set to "nopass".  Also make sure the signal is
> +# delivered to the right thread, even if GDB has to step over a
> +# breakpoint in some other thread first.
> +
> +if [target_info exists gdb,nosignals] {
> +    verbose "Skipping ${testfile}.exp because of nosignals."
> +    return -1
> +}
> +
> +standard_testfile
> +
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
> +	 executable { debug }] != "" } {
> +    return -1
> +}
> +
> +# Run the test proper.  STEP_OVER indicates whether we leave in place
> +# a breakpoint that needs to be stepped over when we explicitly
> +# request a signal be delivered with the "signal" command.
> +
> +proc test { step_over } {
> +    global srcfile binfile
> +
> +    with_test_prefix "step-over $step_over" {
> +	clean_restart ${binfile}
> +
> +	if ![runto_main] then {
> +	    fail "Can't run to main"
> +	    return 0
> +	}
> +
> +	gdb_test "handle SIGUSR1 stop print nopass"
> +
> +	gdb_test "b thread_function" "Breakpoint .* at .*$srcfile.*"
> +	gdb_test "continue" "thread_function.*" "stopped in thread"
> +
> +	# Thread 2 is stopped at a breakpoint.  If we leave the
> +	# breakpoint in place, GDB needs to move thread 2 past the
> +	# breakpoint before delivering the signal to thread 1.  We
> +	# want to be sure that GDB doesn't mistakenly deliver the
> +	# signal to thread 1 while doing that.
> +	if { $step_over == "no" } {
> +	    delete_breakpoints
> +	}
> +
> +	gdb_test "break handler" "Breakpoint .* at .*$srcfile.*"
> +
> +	gdb_test "thread 1" "Switching to thread 1.*"
> +
> +	set pattern "\\\* 1\[ \t\]+Thread.*"
> +
> +	gdb_test "info threads" $pattern "thread 1 selected"
> +
> +	gdb_test "signal SIGUSR1" "handler .*"
> +
> +	gdb_test "info threads" $pattern "thread 1 got the signal"
> +    }
> +}
> +
> +foreach stepover {"yes" "no"} {
> +    test $stepover
> +}
> diff --git a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c
> new file mode 100644
> index 0000000..2fc5f53
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c
> @@ -0,0 +1,98 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2014 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <pthread.h>
> +#include <signal.h>
> +
> +pthread_barrier_t barrier;
> +sig_atomic_t got_sigusr1;
> +sig_atomic_t got_sigusr2;
> +
> +void
> +handler_sigusr1 (int sig)
> +{
> +  got_sigusr1 = 1;
> +}
> +
> +void
> +handler_sigusr2 (int sig)
> +{
> +  got_sigusr2 = 1;
> +}
> +
> +void *
> +thread_function (void *arg)
> +{
> +  volatile unsigned int count = 1;
> +
> +  pthread_barrier_wait (&barrier);
> +
> +  while (count++ != 0)
> +    {
> +      if (got_sigusr1 && got_sigusr2)
> +	break;
> +      usleep (1);
> +    }
> +}
> +
> +void
> +all_threads_started (void)
> +{
> +}
> +
> +void
> +all_threads_signalled (void)
> +{
> +}
> +
> +void
> +end (void)
> +{
> +}
> +
> +int
> +main (void)
> +{
> +  pthread_t child_thread[2];
> +  int i;
> +
> +  signal (SIGUSR1, handler_sigusr1);
> +  signal (SIGUSR2, handler_sigusr2);
> +
> +  pthread_barrier_init (&barrier, NULL, 3);
> +
> +  for (i = 0; i < 2; i++)
> +    pthread_create (&child_thread[i], NULL, thread_function, NULL);
> +
> +  pthread_barrier_wait (&barrier);
> +
> +  all_threads_started ();
> +
> +  pthread_kill (child_thread[0], SIGUSR1);
> +  pthread_kill (child_thread[1], SIGUSR2);
> +
> +  all_threads_signalled ();
> +
> +  for (i = 0; i < 2; i++)
> +    pthread_join (child_thread[i], NULL);
> +
> +  end ();
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp
> new file mode 100644
> index 0000000..b5ec00a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp
> @@ -0,0 +1,166 @@
> +# Copyright (C) 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +# Test that "signal FOO" behaves correctly when we have multiple
> +# threads that have stopped for a signal.
> +
> +if [target_info exists gdb,nosignals] {
> +    verbose "Skipping ${testfile}.exp because of nosignals."
> +    return -1
> +}
> +
> +standard_testfile
> +
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
> +	 executable { debug }] != "" } {
> +    return -1
> +}
> +
> +# Run the test proper.  SCHEDLOCK indicates which variant (around
> +# scheduler-locking) of the test to perform.
> +
> +proc test { schedlock } {
> +    global srcfile binfile
> +
> +    with_test_prefix "schedlock $schedlock" {
> +	clean_restart ${binfile}
> +
> +	if ![runto_main] then {
> +	    fail "Can't run to main"
> +	    return 0
> +	}
> +
> +	gdb_test "handle SIGUSR1 stop print pass"
> +	gdb_test "handle SIGUSR2 stop print pass"
> +
> +	gdb_test "break all_threads_started" "Breakpoint .* at .*$srcfile.*"
> +	gdb_test "continue" "all_threads_started.*"
> +
> +	# Using schedlock, let the main thread queue a signal for each
> +	# non-main thread.
> +	gdb_test_no_output "set scheduler-locking on"
> +
> +	gdb_test "break all_threads_signalled" "Breakpoint .* at .*$srcfile.*"
> +	gdb_test "continue" "all_threads_signalled.*"
> +
> +	gdb_test "info threads" "\\\* 1\[ \t\]+Thread.*" "thread 1 selected"
> +
> +	# With schedlock still enabled, let each thread report its
> +	# signal.
> +
> +	gdb_test "thread 3" "Switching to thread 3.*"
> +	gdb_test "continue" "Program received signal SIGUSR2.*" "stop with SIGUSR2"
> +	gdb_test "thread 2" "Switching to thread 2.*"
> +	gdb_test "continue" "Program received signal SIGUSR1.*" "stop with SIGUSR1"
> +
> +	gdb_test "break handler_sigusr1" "Breakpoint .* at .*$srcfile.*"
> +	gdb_test "break handler_sigusr2" "Breakpoint .* at .*$srcfile.*"
> +
> +	set handler_re "Breakpoint .*, handler_sigusr. \\(sig=.*\\) at .*"
> +
> +	# Now test the "signal" command with either scheduler locking
> +	# enabled or disabled.
> +
> +	if { $schedlock == "off" } {
> +	    # With scheduler locking off, switch to the main thread
> +	    # and issue "signal 0".  "signal 0" should then warn that
> +	    # two threads have signals that will be delivered.  When
> +	    # we let the command proceed, a signal should be
> +	    # delivered, and thus the corresponding breakpoint in the
> +	    # signal handler should trigger.
> +
> +	    gdb_test_no_output "set scheduler-locking off"
> +	    gdb_test "thread 1" "Switching to thread 1.*"
> +
> +	    set queried 0
> +	    set test "signal command queries"
> +	    gdb_test_multiple "signal 0" $test {
> +		-re "stopped with.*stopped with.*stopped with.*Continue anyway.*y or n. $" {
> +		    fail "$test (too many threads noted)"
> +		    set queried 1
> +		}
> +		-re "stopped with signal SIGUSR.*\r\nContinuing .*still deliver .*Continue anyway.*y or n. $" {
> +		    pass $test
> +		    set queried 1
> +		}
> +		-re "Continue anyway.*y or n. $" {
> +		    fail "$test (no threads noted)"
> +		    set queried 1
> +		}
> +	    }
> +
> +	    # Continuing should stop in one of the signal handlers.
> +	    # Which thread runs first is not determinate.
> +	    if {$queried} {
> +		gdb_test "y" "$handler_re" "one signal delivered"
> +	    }
> +
> +	    # Continuing a second time should stop in the other
> +	    # handler.
> +	    with_test_prefix "second signal" {
> +		gdb_test "continue" "$handler_re" "signal delivered"
> +	    }
> +	} else {
> +	    # With scheduler locking on, stay with thread 2 selected,
> +	    # and try to deliver its signal explicitly.  The "signal"
> +	    # command should then warn that one other thread has a
> +	    # signal that will be delivered.  When we let the command
> +	    # proceed, the current thread's signal should be
> +	    # delivered, and thus the corresponding breakpoint in the
> +	    # signal handler should trigger.
> +	    gdb_test "signal SIGUSR1" \
> +		"Breakpoint .*, handler_sigusr1 \\(sig=.*\\) at .*" \
> +		"signal command does not query, signal delivered"
> +
> +	    with_test_prefix "second signal" {
> +		# The other thread had stopped for a signal too, and
> +		# it wasn't resumed yet.  Disabling schedlock and
> +		# trying "signal 0" from the main thread should warn
> +		# again.
> +		gdb_test_no_output "set scheduler-locking off"
> +
> +		set queried 0
> +		set test "signal command queries"
> +		gdb_test_multiple "signal 0" $test {
> +		    -re "stopped with.*stopped with.*Continue anyway.*y or n. $" {
> +			fail "$test (too many threads noted)"
> +			set queried 1
> +		    }
> +		    -re "stopped with signal SIGUSR.*\r\nContinuing .*still deliver .*Continue anyway.*y or n. $" {
> +			pass $test
> +			set queried 1
> +		    }
> +		    -re "Continue anyway.*y or n. $" {
> +			fail "$test (no threads noted)"
> +			set queried 1
> +		    }
> +		}
> +
> +		if {$queried} {
> +		    gdb_test "y" "Breakpoint .*, handler_sigusr2 \\(sig=.*\\) at .*" "signal delivered"
> +		}
> +	    }
> +	}
> +
> +	# Both threads got their signal.  Continuing again should
> +	# neither intercept nor deliver any other signal.
> +	gdb_test "b end" "Breakpoint .* at .*$srcfile.*"
> +	gdb_test "continue" "end .*" "no more signals"
> +    }
> +}
> +
> +foreach schedlock {"off" "on"} {
> +    test $schedlock
> +}
> diff --git a/gdb/testsuite/gdb.threads/signal-delivered-right-thread.c b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.c
> new file mode 100644
> index 0000000..66b68a8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.c
> @@ -0,0 +1,61 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2014 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <pthread.h>
> +#include <signal.h>
> +
> +pthread_barrier_t barrier;
> +
> +void
> +handler (int sig)
> +{
> +}
> +
> +void *
> +thread_function (void *arg)
> +{
> +  pthread_barrier_wait (&barrier);
> +
> +  while (1)
> +    usleep (1);
> +}
> +
> +int
> +main (void)
> +{
> +  pthread_t child_thread[2];
> +  int i;
> +
> +  signal (SIGUSR1, handler);
> +
> +  pthread_barrier_init (&barrier, NULL, 3);
> +
> +  for (i = 0; i < 2; i++)
> +    pthread_create (&child_thread[i], NULL, thread_function, NULL);
> +
> +  pthread_barrier_wait (&barrier);
> +
> +  pthread_kill (child_thread[0], SIGUSR1);
> +
> +  for (i = 0; i < 2; i++)
> +    pthread_join (child_thread[i], NULL);
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp
> new file mode 100644
> index 0000000..4243495
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp
> @@ -0,0 +1,85 @@
> +# Copyright (C) 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +if [target_info exists gdb,nosignals] {
> +    verbose "Skipping ${testfile}.exp because of nosignals."
> +    return -1
> +}
> +
> +standard_testfile
> +
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
> +	 executable { debug }] != "" } {
> +    return -1
> +}
> +
> +# Run test proper.  COMMAND indicates whether to resume the inferior
> +# with "signal 0" or "continue".
> +
> +proc test { command } {
> +    global srcfile binfile
> +
> +    with_test_prefix "$command" {
> +	clean_restart ${binfile}
> +
> +	if ![runto_main] then {
> +	    fail "Can't run to main"
> +	    return 0
> +	}
> +
> +	gdb_test "handle SIGUSR1 stop print pass"
> +
> +	gdb_test "continue" "Program received signal SIGUSR1.*" "stop with SIGUSR1"
> +
> +	set pattern "\\\* 2\[ \t\]+Thread.*"
> +
> +	gdb_test "info threads" $pattern "thread 2 intercepted signal"
> +
> +	gdb_test "break handler" "Breakpoint .* at .*$srcfile.*"
> +
> +	gdb_test "thread 1" "Switching to thread 1.*"
> +
> +	if { $command == "continue" } {
> +	    gdb_test "continue" "handler .*"
> +	} elseif { $command == "signal 0" } {
> +	    set queried 0
> +	    set test "signal 0 queries"
> +	    gdb_test_multiple "signal 0" $test {
> +		-re "stopped with.*stopped with.*Continue anyway.*y or n. $" {
> +		    fail "$test (multiple threads noted)"
> +		    set queried 1
> +		}
> +		-re "stopped with signal SIGUSR1.*\r\nContinuing .*still deliver .*Continue anyway.*y or n. $" {
> +		    pass $test
> +		    set queried 1
> +		}
> +		-re "Continue anyway.*y or n. $" {
> +		    fail "$test (no threads noted)"
> +		    set queried 1
> +		}
> +	    }
> +
> +	    if {$queried} {
> +		gdb_test "y" "handler .*" "signal is delivered"
> +	    }
> +	}
> +
> +	gdb_test "info threads" $pattern "thread 2 got the signal"
> +    }
> +}
> +
> +foreach command {"continue" "signal 0"} {
> +    test $command
> +}
>
  
Eli Zaretskii July 25, 2014, 9:34 a.m. UTC | #3
> Date: Thu, 24 Jul 2014 16:40:42 +0100
> From: Pedro Alves <palves@redhat.com>
> CC: Eli Zaretskii <eliz@gnu.org>
> 
> Could you take a look at the documentation bits of this patch?

Below.

> >  *** Changes since GDB 7.8
> >  
> > +* On resume, GDB now always passes the signal the program had stopped
> > +  for to the thread the signal was sent to, even if the user changed
> > +  threads before resuming.  Previously GDB would often (but not
> > +  always) deliver the signal to the thread that happens to be current
> > +  at resume time.
> > +
> > +* Conversely, the "signal" command now consistently delivers the
> > +  requested signal to the current thread.  GDB now asks for
> > +  confirmation if the program had stopped for a signal and the user
> > +  switched threads meanwhile.

OK for this part.

> > +@emph{Note:} When debugging multi-threaded programs, @var{signal} is
> > +delivered to the currently selected thread, not the thread that last
> > +reported a stop.  If for example the program last stopped on account
> > +of a signal in thread 2 and you want to continue execution suppressing
> > +that signal, you must have thread 2 selected as current before issuing
> > +the @samp{signal 0} command.  @value{GDBN} detects the scenario and
> > +asks for confirmation if you had switched threads meanwhile.

This description is IMO confusing, as it changes the described
situation at least twice.  I suggest this text instead:

  @emph{Note:} When resuming a multi-threaded program, @var{signal} is
  by default delivered to the currently selected thread, not the thread
  that last reported a stop.  This includes the situation where a thread
  was stopped due to a signal.  So if you want to continue execution
  suppressing the signal that stopped a thread, you should select that
  same thread before issuing the @samp{signal 0} command.  If you issue
  the @samp{signal 0} command with another thread as the selected one,
  @value{GDBN} detects that and asks for confirmation.

Otherwise, OK.

Thanks.
  
Pedro Alves July 25, 2014, 10:32 a.m. UTC | #4
On 07/25/2014 10:34 AM, Eli Zaretskii wrote:
>> Date: Thu, 24 Jul 2014 16:40:42 +0100
>> From: Pedro Alves <palves@redhat.com>

>>> +@emph{Note:} When debugging multi-threaded programs, @var{signal} is
>>> +delivered to the currently selected thread, not the thread that last
>>> +reported a stop.  If for example the program last stopped on account
>>> +of a signal in thread 2 and you want to continue execution suppressing
>>> +that signal, you must have thread 2 selected as current before issuing
>>> +the @samp{signal 0} command.  @value{GDBN} detects the scenario and
>>> +asks for confirmation if you had switched threads meanwhile.
> 
> This description is IMO confusing, as it changes the described
> situation at least twice.  I suggest this text instead:
> 
>   @emph{Note:} When resuming a multi-threaded program, @var{signal} is
>   by default delivered to the currently selected thread, not the thread
>   that last reported a stop.  This includes the situation where a thread
>   was stopped due to a signal.  So if you want to continue execution
>   suppressing the signal that stopped a thread, you should select that
>   same thread before issuing the @samp{signal 0} command.  If you issue
>   the @samp{signal 0} command with another thread as the selected one,
>   @value{GDBN} detects that and asks for confirmation.
> 
> Otherwise, OK.

That looks great, thanks a lot!  Would you mind if I drop the "by default",
though?  When I read that I get the impression that there might be a knob
to configure this behavior, while there's none (and nor should there be one).
Like:

    @emph{Note:} When resuming a multi-threaded program, @var{signal} is
-   by default delivered to the currently selected thread, not the thread
+   delivered to the currently selected thread, not the thread
    that last reported a stop.  This includes the situation where a thread
    was stopped due to a signal.  So if you want to continue execution


Thanks,
Pedro Alves
  
Eli Zaretskii July 25, 2014, 12:13 p.m. UTC | #5
> Date: Fri, 25 Jul 2014 11:32:29 +0100
> From: Pedro Alves <palves@redhat.com>
> CC: gdb-patches@sourceware.org
> 
> >   @emph{Note:} When resuming a multi-threaded program, @var{signal} is
> >   by default delivered to the currently selected thread, not the thread
> >   that last reported a stop.  This includes the situation where a thread
> >   was stopped due to a signal.  So if you want to continue execution
> >   suppressing the signal that stopped a thread, you should select that
> >   same thread before issuing the @samp{signal 0} command.  If you issue
> >   the @samp{signal 0} command with another thread as the selected one,
> >   @value{GDBN} detects that and asks for confirmation.
> > 
> > Otherwise, OK.
> 
> That looks great, thanks a lot!  Would you mind if I drop the "by default",
> though?  When I read that I get the impression that there might be a knob
> to configure this behavior, while there's none (and nor should there be one).

You mean, if GDB asks for confirmation, per the above, and the user
confirms, GDB still won't signal the other thread?  If it will, then
there's your knob.

But I agree to remove "by default" from this text.
  
Doug Evans July 28, 2014, 7:39 p.m. UTC | #6
Yao Qi writes:
 > >> > We want to know whether thread 1 is selected, so using "info threads 1"
 > >> > is simpler in the regexp pattern, like
 > >> > 
 > >> >  gdb_test "info threads 1" "\\\* 1${ws}Thread .*" "thread 1 selected"
 > > The reason I don't like "info threads 1" this is that if the test fails,
 > > when you go look at the logs, you don't see which thread was actually
 > > current, which tends to make debugging things a little easier.   But we
 > > can still simplify the patterns.  I was aiming at having no wildcards in
 > > the middle of the output, but that's really not necessary.
 > > I've simplified the patterns now.
 > 
 > OK.

A good thing to document in the test though, eh?
[i.e., *why* "info threads" is used instead of "info threads 1"]

[I realize the patch has been pushed, just a thought for future reference.]
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index d9a19ae..2b61ff4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,17 @@ 
 
 *** Changes since GDB 7.8
 
+* On resume, GDB now always passes the signal the program had stopped
+  for to the thread the signal was sent to, even if the user changed
+  threads before resuming.  Previously GDB would often (but not
+  always) deliver the signal to the thread that happens to be current
+  at resume time.
+
+* Conversely, the "signal" command now consistently delivers the
+  requested signal to the current thread.  GDB now asks for
+  confirmation if the program had stopped for a signal and the user
+  switched threads meanwhile.
+
 *** Changes in GDB 7.8
 
 * New command line options
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b04f3b7..d75e8c7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -11670,7 +11670,7 @@  until_break_command (char *arg, int from_tty, int anywhere)
   int thread;
   struct thread_info *tp;
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
 
   /* Set a breakpoint where the user wants it and at return from
      this function.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8588f73..d0afc3d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -16546,7 +16546,7 @@  detail.
 @table @code
 @kindex signal
 @item signal @var{signal}
-Resume execution where your program stopped, but immediately give it the
+Resume execution where your program is stopped, but immediately give it the
 signal @var{signal}.  The @var{signal} can be the name or the number of a
 signal.  For example, on many systems @code{signal 2} and @code{signal
 SIGINT} are both ways of sending an interrupt signal.
@@ -16557,6 +16557,14 @@  a signal and would ordinarily see the signal when resumed with the
 @code{continue} command; @samp{signal 0} causes it to resume without a
 signal.
 
+@emph{Note:} When debugging multi-threaded programs, @var{signal} is
+delivered to the currently selected thread, not the thread that last
+reported a stop.  If for example the program last stopped on account
+of a signal in thread 2 and you want to continue execution suppressing
+that signal, you must have thread 2 selected as current before issuing
+the @samp{signal 0} command.  @value{GDBN} detects the scenario and
+asks for confirmation if you had switched threads meanwhile.
+
 @code{signal} does not repeat when you press @key{RET} a second time
 after executing the command.
 @end table
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 9ef74cd..522b674 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -135,7 +135,13 @@  struct thread_control_state
 
 struct thread_suspend_state
 {
-  /* Last signal that the inferior received (why it stopped).  */
+  /* Last signal that the inferior received (why it stopped).  When
+     the thread is resumed, this signal is delivered.  Note: the
+     target should not check whether the signal is in pass state,
+     because the signal may have been explicitly passed with the
+     "signal" command, which overrides "handle nopass".  If the signal
+     should be suppressed, the core will take care of clearing this
+     before the target is resumed.  */
   enum gdb_signal stop_signal;
 };
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 685b8a4..2aaac85 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -391,7 +391,7 @@  run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
 
   call_thread->control.in_infcall = 1;
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
 
   disable_watchpoints_before_interactive_call_start ();
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index c4bb401..5c32c5c 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -679,7 +679,7 @@  proceed_thread_callback (struct thread_info *thread, void *arg)
     return 0;
 
   switch_to_thread (thread->ptid);
-  clear_proceed_status ();
+  clear_proceed_status (0);
   proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
   return 0;
 }
@@ -745,7 +745,7 @@  continue_1 (int all_threads)
     {
       ensure_valid_thread ();
       ensure_not_running ();
-      clear_proceed_status ();
+      clear_proceed_status (0);
       proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
     }
 }
@@ -1013,7 +1013,7 @@  step_once (int skip_subroutines, int single_inst, int count, int thread)
 	 THREAD is set.  */
       struct thread_info *tp = inferior_thread ();
 
-      clear_proceed_status ();
+      clear_proceed_status (!skip_subroutines);
       set_step_frame ();
 
       if (!single_inst)
@@ -1186,7 +1186,7 @@  jump_command (char *arg, int from_tty)
       printf_filtered (".\n");
     }
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
   proceed (addr, GDB_SIGNAL_0, 0);
 }
 
@@ -1245,6 +1245,50 @@  signal_command (char *signum_exp, int from_tty)
 	oursig = gdb_signal_from_command (num);
     }
 
+  /* Look for threads other than the current that this command ends up
+     resuming too (due to schedlock off), and warn if they'll get a
+     signal delivered.  "signal 0" is used to suppress a previous
+     signal, but if the current thread is no longer the one that got
+     the signal, then the user is potentially suppressing the signal
+     of the wrong thread.  */
+  if (!non_stop)
+    {
+      struct thread_info *tp;
+      ptid_t resume_ptid;
+      int must_confirm = 0;
+
+      /* This indicates what will be resumed.  Either a single thread,
+	 a whole process, or all threads of all processes.  */
+      resume_ptid = user_visible_resume_ptid (0);
+
+      ALL_NON_EXITED_THREADS (tp)
+	{
+	  if (ptid_equal (tp->ptid, inferior_ptid))
+	    continue;
+	  if (!ptid_match (tp->ptid, resume_ptid))
+	    continue;
+
+	  if (tp->suspend.stop_signal != GDB_SIGNAL_0
+	      && signal_pass_state (tp->suspend.stop_signal))
+	    {
+	      if (!must_confirm)
+		printf_unfiltered (_("Note:\n"));
+	      printf_unfiltered (_("  Thread %d previously stopped with signal %s, %s.\n"),
+				 tp->num,
+				 gdb_signal_to_name (tp->suspend.stop_signal),
+				 gdb_signal_to_string (tp->suspend.stop_signal));
+	      must_confirm = 1;
+	    }
+	}
+
+      if (must_confirm
+	  && !query (_("Continuing thread %d (the current thread) with specified signal will\n"
+		       "still deliver the signals noted above to their respective threads.\n"
+		       "Continue anyway? "),
+		     inferior_thread ()->num))
+	error (_("Not confirmed."));
+    }
+
   if (from_tty)
     {
       if (oursig == GDB_SIGNAL_0)
@@ -1254,7 +1298,7 @@  signal_command (char *signum_exp, int from_tty)
 			 gdb_signal_to_name (oursig));
     }
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
   proceed ((CORE_ADDR) -1, oursig, 0);
 }
 
@@ -1295,7 +1339,7 @@  until_next_command (int from_tty)
   int thread = tp->num;
   struct cleanup *old_chain;
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
   set_step_frame ();
 
   frame = get_current_frame ();
@@ -1687,7 +1731,7 @@  finish_command (char *arg, int from_tty)
   if (frame == 0)
     error (_("\"finish\" not meaningful in the outermost frame."));
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
 
   /* Finishing from an inline frame is completely different.  We don't
      try to show the "return value" - no way to locate it.  So we do
@@ -2299,7 +2343,7 @@  proceed_after_attach_callback (struct thread_info *thread,
       && thread->suspend.stop_signal == GDB_SIGNAL_0)
     {
       switch_to_thread (thread->ptid);
-      clear_proceed_status ();
+      clear_proceed_status (0);
       proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
     }
 
@@ -2399,7 +2443,7 @@  attach_command_post_wait (char *args, int from_tty, int async_exec)
 	{
 	  if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0)
 	    {
-	      clear_proceed_status ();
+	      clear_proceed_status (0);
 	      proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
 	    }
 	}
@@ -2502,7 +2546,7 @@  attach_command (char *args, int from_tty)
   /* Set up execution context to know that we should return from
      wait_for_inferior as soon as the target reports a stop.  */
   init_wait_for_inferior ();
-  clear_proceed_status ();
+  clear_proceed_status (0);
 
   if (non_stop)
     {
diff --git a/gdb/infrun.c b/gdb/infrun.c
index bef69a8..2626233 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -623,7 +623,7 @@  proceed_after_vfork_done (struct thread_info *thread,
 			    target_pid_to_str (thread->ptid));
 
       switch_to_thread (thread->ptid);
-      clear_proceed_status ();
+      clear_proceed_status (0);
       proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
     }
 
@@ -1721,15 +1721,6 @@  maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc)
   return hw_step;
 }
 
-/* Return a ptid representing the set of threads that we will proceed,
-   in the perspective of the user/frontend.  We may actually resume
-   fewer threads at first, e.g., if a thread is stopped at a
-   breakpoint that needs stepping-off, but that should not be visible
-   to the user/frontend, and neither should the frontend/user be
-   allowed to proceed any of the threads that happen to be stopped for
-   internal run control handling, if a previous command wanted them
-   resumed.  */
-
 ptid_t
 user_visible_resume_ptid (int step)
 {
@@ -1757,6 +1748,12 @@  user_visible_resume_ptid (int step)
       resume_ptid = inferior_ptid;
     }
 
+  /* We may actually resume fewer threads at first, e.g., if a thread
+     is stopped at a breakpoint that needs stepping-off, but that
+     should not be visible to the user/frontend, and neither should
+     the frontend/user be allowed to proceed any of the threads that
+     happen to be stopped for internal run control handling, if a
+     previous command wanted them resumed.  */
   return resume_ptid;
 }
 
@@ -2032,6 +2029,11 @@  clear_proceed_status_thread (struct thread_info *tp)
 			"infrun: clear_proceed_status_thread (%s)\n",
 			target_pid_to_str (tp->ptid));
 
+  /* If this signal should not be seen by program, give it zero.
+     Used for debugging signals.  */
+  if (!signal_pass_state (tp->suspend.stop_signal))
+    tp->suspend.stop_signal = GDB_SIGNAL_0;
+
   tp->control.trap_expected = 0;
   tp->control.step_range_start = 0;
   tp->control.step_range_end = 0;
@@ -2051,26 +2053,24 @@  clear_proceed_status_thread (struct thread_info *tp)
   bpstat_clear (&tp->control.stop_bpstat);
 }
 
-static int
-clear_proceed_status_callback (struct thread_info *tp, void *data)
-{
-  if (is_exited (tp->ptid))
-    return 0;
-
-  clear_proceed_status_thread (tp);
-  return 0;
-}
-
 void
-clear_proceed_status (void)
+clear_proceed_status (int step)
 {
   if (!non_stop)
     {
-      /* In all-stop mode, delete the per-thread status of all
-	 threads, even if inferior_ptid is null_ptid, there may be
-	 threads on the list.  E.g., we may be launching a new
-	 process, while selecting the executable.  */
-      iterate_over_threads (clear_proceed_status_callback, NULL);
+      struct thread_info *tp;
+      ptid_t resume_ptid;
+
+      resume_ptid = user_visible_resume_ptid (step);
+
+      /* In all-stop mode, delete the per-thread status of all threads
+	 we're about to resume, implicitly and explicitly.  */
+      ALL_NON_EXITED_THREADS (tp)
+        {
+	  if (!ptid_match (tp->ptid, resume_ptid))
+	    continue;
+	  clear_proceed_status_thread (tp);
+	}
     }
 
   if (!ptid_equal (inferior_ptid, null_ptid))
@@ -2252,6 +2252,9 @@  proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
       regcache_write_pc (regcache, addr);
     }
 
+  if (siggnal != GDB_SIGNAL_DEFAULT)
+    tp->suspend.stop_signal = siggnal;
+
   /* Record the interpreter that issued the execution command that
      caused this thread to resume.  If the top level interpreter is
      MI/async, and the execution command was a CLI command
@@ -2318,38 +2321,6 @@  proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
 
   tp->control.trap_expected = tp->stepping_over_breakpoint;
 
-  if (!non_stop)
-    {
-      /* Pass the last stop signal to the thread we're resuming,
-	 irrespective of whether the current thread is the thread that
-	 got the last event or not.  This was historically GDB's
-	 behaviour before keeping a stop_signal per thread.  */
-
-      struct thread_info *last_thread;
-      ptid_t last_ptid;
-      struct target_waitstatus last_status;
-
-      get_last_target_status (&last_ptid, &last_status);
-      if (!ptid_equal (inferior_ptid, last_ptid)
-	  && !ptid_equal (last_ptid, null_ptid)
-	  && !ptid_equal (last_ptid, minus_one_ptid))
-	{
-	  last_thread = find_thread_ptid (last_ptid);
-	  if (last_thread)
-	    {
-	      tp->suspend.stop_signal = last_thread->suspend.stop_signal;
-	      last_thread->suspend.stop_signal = GDB_SIGNAL_0;
-	    }
-	}
-    }
-
-  if (siggnal != GDB_SIGNAL_DEFAULT)
-    tp->suspend.stop_signal = siggnal;
-  /* If this signal should not be seen by program,
-     give it zero.  Used for debugging signals.  */
-  else if (!signal_program[tp->suspend.stop_signal])
-    tp->suspend.stop_signal = GDB_SIGNAL_0;
-
   annotate_starting ();
 
   /* Make sure that output from GDB appears before output from the
@@ -2443,7 +2414,7 @@  init_wait_for_inferior (void)
 
   breakpoint_init_inferior (inf_starting);
 
-  clear_proceed_status ();
+  clear_proceed_status (0);
 
   target_last_wait_ptid = minus_one_ptid;
 
@@ -5190,6 +5161,10 @@  switch_back_to_stepped_thread (struct execution_control_state *ecs)
 	 what keep_going does as well, if we call it.  */
       ecs->event_thread->control.trap_expected = 0;
 
+      /* Likewise, clear the signal if it should not be passed.  */
+      if (!signal_program[ecs->event_thread->suspend.stop_signal])
+	ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
+
       /* If scheduler locking applies even if not stepping, there's no
 	 need to walk over threads.  Above we've checked whether the
 	 current thread is stepping.  If some other thread not the
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 66612a8..35b2246 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -83,7 +83,11 @@  extern struct regcache *stop_registers;
 
 extern void start_remote (int from_tty);
 
-extern void clear_proceed_status (void);
+/* Clear out all variables saying what to do when inferior is
+   continued or stepped.  First do this, then set the ones you want,
+   then call `proceed'.  STEP indicates whether we're preparing for a
+   step/stepi command.  */
+extern void clear_proceed_status (int step);
 
 extern void proceed (CORE_ADDR, enum gdb_signal, int);
 
@@ -91,6 +95,8 @@  extern void proceed (CORE_ADDR, enum gdb_signal, int);
    Normally, use `proceed', which handles a lot of bookkeeping.  */
 extern void resume (int, enum gdb_signal);
 
+/* Return a ptid representing the set of threads that we will proceed,
+   in the perspective of the user/frontend.  */
 extern ptid_t user_visible_resume_ptid (int step);
 
 extern void wait_for_inferior (void);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index c9677ca..8f2600d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1694,8 +1694,7 @@  linux_nat_resume_callback (struct lwp_info *lp, void *except)
       thread = find_thread_ptid (lp->ptid);
       if (thread != NULL)
 	{
-	  if (signal_pass_state (thread->suspend.stop_signal))
-	    signo = thread->suspend.stop_signal;
+	  signo = thread->suspend.stop_signal;
 	  thread->suspend.stop_signal = GDB_SIGNAL_0;
 	}
     }
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 96dfc71..26389f1 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -253,7 +253,7 @@  proceed_thread (struct thread_info *thread, int pid)
     return;
 
   switch_to_thread (thread->ptid);
-  clear_proceed_status ();
+  clear_proceed_status (0);
   proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
 }
 
diff --git a/gdb/remote.c b/gdb/remote.c
index b5318f1..e56cfea 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4629,8 +4629,7 @@  append_pending_thread_resumptions (char *p, char *endp, ptid_t ptid)
   ALL_NON_EXITED_THREADS (thread)
     if (ptid_match (thread->ptid, ptid)
 	&& !ptid_equal (inferior_ptid, thread->ptid)
-	&& thread->suspend.stop_signal != GDB_SIGNAL_0
-	&& signal_pass_state (thread->suspend.stop_signal))
+	&& thread->suspend.stop_signal != GDB_SIGNAL_0)
       {
 	p = append_resumption (p, endp, thread->ptid,
 			       0, thread->suspend.stop_signal);
diff --git a/gdb/testsuite/gdb.threads/signal-command-handle-nopass.c b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.c
new file mode 100644
index 0000000..abca2f9
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.c
@@ -0,0 +1,49 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+
+void
+handler (int sig)
+{
+}
+
+void *
+thread_function (void *arg)
+{
+  volatile unsigned int i = 1;
+
+  while (i != 0)
+    usleep (1);
+}
+
+int
+main (void)
+{
+  pthread_t child_thread;
+  int i;
+
+  signal (SIGUSR1, handler);
+  pthread_create (&child_thread, NULL, thread_function, NULL);
+  pthread_join (child_thread, NULL);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp
new file mode 100644
index 0000000..3ea9cf8
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/signal-command-handle-nopass.exp
@@ -0,0 +1,78 @@ 
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Test that an explicit "signal FOO" delivers FOO even if "handle" for
+# that same signal is set to "nopass".  Also make sure the signal is
+# delivered to the right thread, even if GDB has to step over a
+# breakpoint in some other thread first.
+
+if [target_info exists gdb,nosignals] {
+    verbose "Skipping ${testfile}.exp because of nosignals."
+    return -1
+}
+
+standard_testfile
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+	 executable { debug }] != "" } {
+    return -1
+}
+
+# Run the test proper.  STEP_OVER indicates whether we leave in place
+# a breakpoint that needs to be stepped over when we explicitly
+# request a signal be delivered with the "signal" command.
+
+proc test { step_over } {
+    global srcfile binfile
+
+    with_test_prefix "step-over $step_over" {
+	clean_restart ${binfile}
+
+	if ![runto_main] then {
+	    fail "Can't run to main"
+	    return 0
+	}
+
+	gdb_test "handle SIGUSR1 stop print nopass"
+
+	gdb_test "b thread_function" "Breakpoint .* at .*$srcfile.*"
+	gdb_test "continue" "thread_function.*" "stopped in thread"
+
+	# Thread 2 is stopped at a breakpoint.  If we leave the
+	# breakpoint in place, GDB needs to move thread 2 past the
+	# breakpoint before delivering the signal to thread 1.  We
+	# want to be sure that GDB doesn't mistakenly deliver the
+	# signal to thread 1 while doing that.
+	if { $step_over == "no" } {
+	    delete_breakpoints
+	}
+
+	gdb_test "break handler" "Breakpoint .* at .*$srcfile.*"
+
+	gdb_test "thread 1" "Switching to thread 1.*"
+
+	set pattern "\\\* 1\[ \t\]+Thread.*"
+
+	gdb_test "info threads" $pattern "thread 1 selected"
+
+	gdb_test "signal SIGUSR1" "handler .*"
+
+	gdb_test "info threads" $pattern "thread 1 got the signal"
+    }
+}
+
+foreach stepover {"yes" "no"} {
+    test $stepover
+}
diff --git a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c
new file mode 100644
index 0000000..2fc5f53
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.c
@@ -0,0 +1,98 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+
+pthread_barrier_t barrier;
+sig_atomic_t got_sigusr1;
+sig_atomic_t got_sigusr2;
+
+void
+handler_sigusr1 (int sig)
+{
+  got_sigusr1 = 1;
+}
+
+void
+handler_sigusr2 (int sig)
+{
+  got_sigusr2 = 1;
+}
+
+void *
+thread_function (void *arg)
+{
+  volatile unsigned int count = 1;
+
+  pthread_barrier_wait (&barrier);
+
+  while (count++ != 0)
+    {
+      if (got_sigusr1 && got_sigusr2)
+	break;
+      usleep (1);
+    }
+}
+
+void
+all_threads_started (void)
+{
+}
+
+void
+all_threads_signalled (void)
+{
+}
+
+void
+end (void)
+{
+}
+
+int
+main (void)
+{
+  pthread_t child_thread[2];
+  int i;
+
+  signal (SIGUSR1, handler_sigusr1);
+  signal (SIGUSR2, handler_sigusr2);
+
+  pthread_barrier_init (&barrier, NULL, 3);
+
+  for (i = 0; i < 2; i++)
+    pthread_create (&child_thread[i], NULL, thread_function, NULL);
+
+  pthread_barrier_wait (&barrier);
+
+  all_threads_started ();
+
+  pthread_kill (child_thread[0], SIGUSR1);
+  pthread_kill (child_thread[1], SIGUSR2);
+
+  all_threads_signalled ();
+
+  for (i = 0; i < 2; i++)
+    pthread_join (child_thread[i], NULL);
+
+  end ();
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp
new file mode 100644
index 0000000..b5ec00a
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/signal-command-multiple-signals-pending.exp
@@ -0,0 +1,166 @@ 
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Test that "signal FOO" behaves correctly when we have multiple
+# threads that have stopped for a signal.
+
+if [target_info exists gdb,nosignals] {
+    verbose "Skipping ${testfile}.exp because of nosignals."
+    return -1
+}
+
+standard_testfile
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+	 executable { debug }] != "" } {
+    return -1
+}
+
+# Run the test proper.  SCHEDLOCK indicates which variant (around
+# scheduler-locking) of the test to perform.
+
+proc test { schedlock } {
+    global srcfile binfile
+
+    with_test_prefix "schedlock $schedlock" {
+	clean_restart ${binfile}
+
+	if ![runto_main] then {
+	    fail "Can't run to main"
+	    return 0
+	}
+
+	gdb_test "handle SIGUSR1 stop print pass"
+	gdb_test "handle SIGUSR2 stop print pass"
+
+	gdb_test "break all_threads_started" "Breakpoint .* at .*$srcfile.*"
+	gdb_test "continue" "all_threads_started.*"
+
+	# Using schedlock, let the main thread queue a signal for each
+	# non-main thread.
+	gdb_test_no_output "set scheduler-locking on"
+
+	gdb_test "break all_threads_signalled" "Breakpoint .* at .*$srcfile.*"
+	gdb_test "continue" "all_threads_signalled.*"
+
+	gdb_test "info threads" "\\\* 1\[ \t\]+Thread.*" "thread 1 selected"
+
+	# With schedlock still enabled, let each thread report its
+	# signal.
+
+	gdb_test "thread 3" "Switching to thread 3.*"
+	gdb_test "continue" "Program received signal SIGUSR2.*" "stop with SIGUSR2"
+	gdb_test "thread 2" "Switching to thread 2.*"
+	gdb_test "continue" "Program received signal SIGUSR1.*" "stop with SIGUSR1"
+
+	gdb_test "break handler_sigusr1" "Breakpoint .* at .*$srcfile.*"
+	gdb_test "break handler_sigusr2" "Breakpoint .* at .*$srcfile.*"
+
+	set handler_re "Breakpoint .*, handler_sigusr. \\(sig=.*\\) at .*"
+
+	# Now test the "signal" command with either scheduler locking
+	# enabled or disabled.
+
+	if { $schedlock == "off" } {
+	    # With scheduler locking off, switch to the main thread
+	    # and issue "signal 0".  "signal 0" should then warn that
+	    # two threads have signals that will be delivered.  When
+	    # we let the command proceed, a signal should be
+	    # delivered, and thus the corresponding breakpoint in the
+	    # signal handler should trigger.
+
+	    gdb_test_no_output "set scheduler-locking off"
+	    gdb_test "thread 1" "Switching to thread 1.*"
+
+	    set queried 0
+	    set test "signal command queries"
+	    gdb_test_multiple "signal 0" $test {
+		-re "stopped with.*stopped with.*stopped with.*Continue anyway.*y or n. $" {
+		    fail "$test (too many threads noted)"
+		    set queried 1
+		}
+		-re "stopped with signal SIGUSR.*\r\nContinuing .*still deliver .*Continue anyway.*y or n. $" {
+		    pass $test
+		    set queried 1
+		}
+		-re "Continue anyway.*y or n. $" {
+		    fail "$test (no threads noted)"
+		    set queried 1
+		}
+	    }
+
+	    # Continuing should stop in one of the signal handlers.
+	    # Which thread runs first is not determinate.
+	    if {$queried} {
+		gdb_test "y" "$handler_re" "one signal delivered"
+	    }
+
+	    # Continuing a second time should stop in the other
+	    # handler.
+	    with_test_prefix "second signal" {
+		gdb_test "continue" "$handler_re" "signal delivered"
+	    }
+	} else {
+	    # With scheduler locking on, stay with thread 2 selected,
+	    # and try to deliver its signal explicitly.  The "signal"
+	    # command should then warn that one other thread has a
+	    # signal that will be delivered.  When we let the command
+	    # proceed, the current thread's signal should be
+	    # delivered, and thus the corresponding breakpoint in the
+	    # signal handler should trigger.
+	    gdb_test "signal SIGUSR1" \
+		"Breakpoint .*, handler_sigusr1 \\(sig=.*\\) at .*" \
+		"signal command does not query, signal delivered"
+
+	    with_test_prefix "second signal" {
+		# The other thread had stopped for a signal too, and
+		# it wasn't resumed yet.  Disabling schedlock and
+		# trying "signal 0" from the main thread should warn
+		# again.
+		gdb_test_no_output "set scheduler-locking off"
+
+		set queried 0
+		set test "signal command queries"
+		gdb_test_multiple "signal 0" $test {
+		    -re "stopped with.*stopped with.*Continue anyway.*y or n. $" {
+			fail "$test (too many threads noted)"
+			set queried 1
+		    }
+		    -re "stopped with signal SIGUSR.*\r\nContinuing .*still deliver .*Continue anyway.*y or n. $" {
+			pass $test
+			set queried 1
+		    }
+		    -re "Continue anyway.*y or n. $" {
+			fail "$test (no threads noted)"
+			set queried 1
+		    }
+		}
+
+		if {$queried} {
+		    gdb_test "y" "Breakpoint .*, handler_sigusr2 \\(sig=.*\\) at .*" "signal delivered"
+		}
+	    }
+	}
+
+	# Both threads got their signal.  Continuing again should
+	# neither intercept nor deliver any other signal.
+	gdb_test "b end" "Breakpoint .* at .*$srcfile.*"
+	gdb_test "continue" "end .*" "no more signals"
+    }
+}
+
+foreach schedlock {"off" "on"} {
+    test $schedlock
+}
diff --git a/gdb/testsuite/gdb.threads/signal-delivered-right-thread.c b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.c
new file mode 100644
index 0000000..66b68a8
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.c
@@ -0,0 +1,61 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+
+pthread_barrier_t barrier;
+
+void
+handler (int sig)
+{
+}
+
+void *
+thread_function (void *arg)
+{
+  pthread_barrier_wait (&barrier);
+
+  while (1)
+    usleep (1);
+}
+
+int
+main (void)
+{
+  pthread_t child_thread[2];
+  int i;
+
+  signal (SIGUSR1, handler);
+
+  pthread_barrier_init (&barrier, NULL, 3);
+
+  for (i = 0; i < 2; i++)
+    pthread_create (&child_thread[i], NULL, thread_function, NULL);
+
+  pthread_barrier_wait (&barrier);
+
+  pthread_kill (child_thread[0], SIGUSR1);
+
+  for (i = 0; i < 2; i++)
+    pthread_join (child_thread[i], NULL);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp
new file mode 100644
index 0000000..4243495
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/signal-delivered-right-thread.exp
@@ -0,0 +1,85 @@ 
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+if [target_info exists gdb,nosignals] {
+    verbose "Skipping ${testfile}.exp because of nosignals."
+    return -1
+}
+
+standard_testfile
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+	 executable { debug }] != "" } {
+    return -1
+}
+
+# Run test proper.  COMMAND indicates whether to resume the inferior
+# with "signal 0" or "continue".
+
+proc test { command } {
+    global srcfile binfile
+
+    with_test_prefix "$command" {
+	clean_restart ${binfile}
+
+	if ![runto_main] then {
+	    fail "Can't run to main"
+	    return 0
+	}
+
+	gdb_test "handle SIGUSR1 stop print pass"
+
+	gdb_test "continue" "Program received signal SIGUSR1.*" "stop with SIGUSR1"
+
+	set pattern "\\\* 2\[ \t\]+Thread.*"
+
+	gdb_test "info threads" $pattern "thread 2 intercepted signal"
+
+	gdb_test "break handler" "Breakpoint .* at .*$srcfile.*"
+
+	gdb_test "thread 1" "Switching to thread 1.*"
+
+	if { $command == "continue" } {
+	    gdb_test "continue" "handler .*"
+	} elseif { $command == "signal 0" } {
+	    set queried 0
+	    set test "signal 0 queries"
+	    gdb_test_multiple "signal 0" $test {
+		-re "stopped with.*stopped with.*Continue anyway.*y or n. $" {
+		    fail "$test (multiple threads noted)"
+		    set queried 1
+		}
+		-re "stopped with signal SIGUSR1.*\r\nContinuing .*still deliver .*Continue anyway.*y or n. $" {
+		    pass $test
+		    set queried 1
+		}
+		-re "Continue anyway.*y or n. $" {
+		    fail "$test (no threads noted)"
+		    set queried 1
+		}
+	    }
+
+	    if {$queried} {
+		gdb_test "y" "handler .*" "signal is delivered"
+	    }
+	}
+
+	gdb_test "info threads" $pattern "thread 2 got the signal"
+    }
+}
+
+foreach command {"continue" "signal 0"} {
+    test $command
+}