From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32078 invoked by alias); 23 Jan 2014 18:53:48 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 32066 invoked by uid 89); 23 Jan 2014 18:53:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 23 Jan 2014 18:53:17 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s0NIrFCr012608 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 23 Jan 2014 13:53:15 -0500 Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id s0NIrDOV003996; Thu, 23 Jan 2014 13:53:14 -0500 Message-ID: <52E16518.1020800@redhat.com> Date: Thu, 23 Jan 2014 18:53:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130625 Thunderbird/17.0.7 MIME-Version: 1.0 To: Sterling Augustine CC: gdb-patches Subject: Re: [PATCH] RFC: All stepping threads need the same checks and cleanup as the currently stepping thread References: <52DFCFCF.4030101@redhat.com> In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2014-01/txt/msg00910.txt.bz2 On 01/22/2014 05:41 PM, Sterling Augustine wrote: > On Wed, Jan 22, 2014 at 6:03 AM, Pedro Alves wrote: >> The issue seems to me, as previously discussed, not really about missing >> the "fix up" of the step range, but rather that we overstep the thread >> by mistake. > > That is incorrect. The thread's stepping range looks something like > this, in source code: > > x = 1; foo(); x = 2; > > With the step range equivalent to the single line. > > But the stepped-thread gets stopped in foo--that's what all the extra > logic in process_event_stop_test does to fix up the step range. OK, we're saying similar things. The thing is that the thread (call it A) doesn't report an event saying it's stopped in foo. It's quiesced while handling an event for another thread (B), and we noticed that thread B had moved. If we just blindly keep_going it, we might overstep -- that's what I'm saying. > > So the thread is not past the step range at all A matter of definition I guess. If the thread is in "foo", then it is out of the step range, and that needs care. > and will hit it eventually, but it is outside it. There is logic in > process_event_stop_test to handle this exact case. Right. > >> Running the thread through process_event_stop_test makes us >> detect that the step finished (before we ever get to fix up the step >> range). I understand that. > > The step didn't finish. The thread stopped deeper in the stack. > >> The thing missing is a testcase clearly showing that that's indeed >> the issue in question. I spent a few days trying to write one from >> scratch a while ago, but failed, because linux-nat.c always gives >> preference to reporting the stepping/SIGTRAP thread if there are multiple >> simultaneous events, and it seemed like another signal needs to be >> involved to trigger this. > > Even if I could release this app (which I can't), it is several > gigabytes big, and it takes a while to hit the case--it is obviously a > race that is unusual extremely uncommon. > > I have spent a solid week trying to write a case to hit this > independently, but I can't. > >> Perhaps we could confirm all this already in a log produced by >> your extra debug outputs ran against your big app? > > I have attached a severely trimmed log to the bug here: > > https://sourceware.org/bugzilla/show_bug.cgi?id=16292 Thank you that helps a lot. > The relevant lines in the log as far as I can tell are: > > 157292: LWP 28899 Takes a trace/breakpoint trap, and is inside its step range. > 157293: LWP 29437 has a breakpoint pushed back. > 157307: LWP 28899 is resumed and prepared to step (still inside step range). > 159355: GDB switches contexts from LWP 28899 to LWP 29437 > 159808: LWP 29437 Takes a trace/breakpoint trap, and GDB sends SIGSTOP > to all other threads > 161427: LWP 28899 Takes a Profiling timer expired trap, instead of a > SIGSTOP. outside of its step range. > 161466: switch_to_stepped_thread decides to restart LWP 28899 > (switch_to_stepped_thread). > 161488: assertion failure. We should start looking earlier even. I do believe this case eventually needs to be handled (though I'd prefer the form of my other patch, even though obviously it isn't complete). >> I'm not convinced the first two branches in switch_back_to_stepped_thread >> should be changed at all. So without those that reduces to exactly the >> original patch I had shown you originally: >> >> https://github.com/palves/gdb/commit/b6b55ba610f8db5d89ec7405c93013a10d9a1c20 >> >> Does that alone fix things for you? > > Yes, by itself it does work, but I thought you had rejected that for > some reason. I "rejected" it in the sense that that loses signals as mentioned in the second patch. > The second patch you made breaks things by bypassing the > step-range fix up in process_event_stop_test. Of course, for hardware step targets, it's essentially a revertion of the first patch. It's unfinished! It reverted the first patch, and then fixed things only for software step targets. It's needs finishing for hardware step targets... > >> In that branch, I then later rewrote that fix differently: >> >> https://github.com/palves/gdb/commit/1d56ddf439b6f7e7fa9759cf1f8e02106eea6af5 >> >> The idea of that "better fix" was to handle the case mentioned in >> this comment: >> >> + There might be some cases where this loses signal >> + information, if a signal has arrived at exactly the same >> + time that the PC changed, but this is the best we can do >> + with the information available. >> >> by setting a breakpoint at the current PC, and re-resuming the thread. >> That means that if there was indeed some other signal/event pending, >> we'd collect it first. But that's unfinished, and breaks hardware-step >> targets again in the process, for it only handles software-step targets. >> The thing preventing moving this forward is a testcase (or a log showing >> clearly that the problem is what I say above it is, which should show >> the steps needed to construct a testcase). > > This doesn't seem to address the case at hand. In any case, the second > patch does not fix it. I don't know how to say it more clearly -- it's unfinished. :-) Making the hardware step path do something like the the software step path should fix it. At least, that's my hope. > I would be fine with your first patch though. Let's step back a bit first. Trimming your log attached to the PR a bit, I noticed something related going wrong _before_ the assertion in question. So we're stepping 28899: infrun: target_wait (-1, status) = infrun: 28899 [Thread 0x7ffff7ff1b80 (LWP 28899)], infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: Thread 0x7ffff7ff1b80 (LWP 28899) may not range step infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x8a9878 infrun: stepping inside range [0x8a9769-0x8a9e9d] infrun: Thread 0x7ffff7ff1b80 (LWP 28899) may range step infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff7ff1b80 (LWP 28899)] at 0x8a9878 infrun: Thread 0x7ffff7ff1b80 (LWP 28899) step range = [8a9769-8a9e9d] pc = 8a9878 LLR: Preparing to step process 28899, 0, inferior_ptid Thread 0x7ffff7ff1b80 (LWP 28899) RC: Resuming sibling Thread 0x7fff60fa0700 (LWP 29437), 0, resume ... Above we've stepped it, in the range. But eventually, some other thread hits a breakpoint that needs stepping over: infrun: Switching context from Thread 0x7ffff7ff1b80 (LWP 28899) to Thread 0x7fff60fa0700 (LWP 29437) infrun: BPSTAT_WHAT_SINGLE infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [Thread 0x7fff60fa0700 (LWP 29437)] at 0x7ffff757cd70 infrun: Thread 0x7fff60fa0700 (LWP 29437) may not range step LLR: Preparing to step Thread 0x7fff60fa0700 (LWP 29437), 0, inferior_ptid Thread 0x7fff60fa0700 (LWP 29437) LLR: PTRACE_SINGLESTEP process 29437, 0 (resume event thread) infrun: prepare_to_wait linux_nat_wait: [process -1], [] LLW: enter LLW: retry LNW: waitpid(-1, ...) returned 0, ERRNO-OK sigchld LNW: waitpid(-1, ...) returned 29437, ERRNO-OK LLW: waitpid 29437 received Profiling timer expired (stopped) LLTA: KILL(SIG0) Thread 0x7fff60fa0700 (LWP 29437) (OK) LLW: Candidate event Profiling timer expired (stopped) in Thread 0x7fff60fa0700 (LWP 29437). SEL: Select single-step Thread 0x7fff60fa0700 (LWP 29437) LLW: exit ... and then while trying to step over the breakpoint, the thread reports a signal. infrun: target_wait (-1, status) = infrun: 28899 [Thread 0x7fff60fa0700 (LWP 29437)], infrun: status->kind = stopped, signal = GDB_SIGNAL_PROF infrun: Thread 0x7fff60fa0700 (LWP 29437) may not range step infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x7ffff757cd70 infrun: random signal (GDB_SIGNAL_PROF) infrun: signal arrived while stepping over breakpoint infrun: inserting step-resume breakpoint at 0x7ffff757cd70 So we set a step-resume breakpoint at the PC, and continue (all threads), to move past the signal handler. But, infrun: resume (step=0, signal=GDB_SIGNAL_PROF), trap_expected=0, current thread [Thread 0x7fff60fa0700 (LWP 29437)] at 0x7ffff757cd70 LLR: Preparing to resume process 28899, Profiling timer expired, inferior_ptid Thread 0x7fff60fa0700 (LWP 29437) RC: Not resuming sibling Thread 0x7fff60fa0700 (LWP 29437) (not stopped) ... RC: Resuming sibling Thread 0x7ffff7ff1b80 (LWP 28899), 0, resume ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... that means we CONTINUE thread 28899, the one stepping in the range, instead of stepping it! No wonder it later appeared outside the stepping range. When I saw this, I had a deja vu... https://sourceware.org/ml/gdb-patches/2011-05/msg00443.html (I never pushed that patch.) And lo, the test in that patch triggers your assertion too... I never pushed that patch because I wasn't really sure I liked it. Running the signal handler with scheduler locking on is "dangerous" in we could cause deadlock in the inferior (some other thread might be holding some form of lock the handler takes too). So, after that patch was written, things have evolved some in infrun.c, that I think this simpler patch suffices. There's a spot in resume that uses step_after_step_resume_breakpoint too (for software single-step targets), that I haven't really given much thought yet. It might well need something there too. ----- >From c6c4e2960d3f8c797ea96909c423d6d53934e1c6 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 23 Jan 2014 18:23:42 +0000 Subject: [PATCH] Make sure we don't resume the stepped thread by accident. Say: (gdb) thread 3 (gdb) step The above triggers the prepare_to_proceed/deferred_step_ptid process, which switches back to thread 2, to step over its breakpoint before getting back to thread 3 and "step" it. If while stepping over the breakpoint in thread 2, a signal arrives, and it is set to pass/nostop, we'll set a step-resume breakpoint at the supposed signal-handler resume address, and call keep_going. The problem is that we were supposely stepping thread 3, and that keep_going delivers a signal to thread 2, and due to scheduler-locking off, resumes everything else, _including_ thread 3, the thread we want stepping. This means that we lose control of thread 3 until the next event, when we stop everything. The end result for the user, is that GDB lost control of the "step". Here's the current infrun debug output of the above, with the testcase in the patch below: infrun: clear_proceed_status_thread (Thread 0x2aaaab8f5700 (LWP 11663)) infrun: clear_proceed_status_thread (Thread 0x2aaaab6f4700 (LWP 11662)) infrun: clear_proceed_status_thread (Thread 0x2aaaab4f2b20 (LWP 11659)) infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1) infrun: prepare_to_proceed (step=1), switched to [Thread 0x2aaaab6f4700 (LWP 11662)] infrun: resume (step=1, signal=0), trap_expected=1, current thread [Thread 0x2aaaab6f4700 (LWP 11662)] at 0x40098f infrun: wait_for_inferior () infrun: target_wait (-1, status) = infrun: 11659 [Thread 0x2aaaab6f4700 (LWP 11662)], infrun: status->kind = stopped, signal = SIGUSR1 infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x40098f infrun: random signal 30 Program received signal SIGUSR1, User defined signal 1. infrun: signal arrived while stepping over breakpoint infrun: inserting step-resume breakpoint at 0x40098f infrun: resume (step=0, signal=30), trap_expected=0, current thread [Thread 0x2aaaab6f4700 (LWP 11662)] at 0x40098f ^^^ this is a wildcard resume. infrun: prepare_to_wait infrun: target_wait (-1, status) = infrun: 11659 [Thread 0x2aaaab6f4700 (LWP 11662)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x40098f infrun: BPSTAT_WHAT_STEP_RESUME infrun: resume (step=1, signal=0), trap_expected=1, current thread [Thread 0x2aaaab6f4700 (LWP 11662)] at 0x40098f ^^^ step-resume hit, meaning the handler returned, so we go back to stepping thread 3. infrun: prepare_to_wait infrun: target_wait (-1, status) = infrun: 11659 [Thread 0x2aaaab6f4700 (LWP 11662)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x40088b infrun: switching back to stepped thread infrun: Switching context from Thread 0x2aaaab6f4700 (LWP 11662) to Thread 0x2aaaab8f5700 (LWP 11663) infrun: resume (step=1, signal=0), trap_expected=0, current thread [Thread 0x2aaaab8f5700 (LWP 11663)] at 0x400938 infrun: prepare_to_wait infrun: target_wait (-1, status) = infrun: 11659 [Thread 0x2aaaab8f5700 (LWP 11663)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x40093a infrun: keep going infrun: resume (step=1, signal=0), trap_expected=0, current thread [Thread 0x2aaaab8f5700 (LWP 11663)] at 0x40093a infrun: prepare_to_wait infrun: target_wait (-1, status) = infrun: 11659 [Thread 0x2aaaab8f5700 (LWP 11663)], infrun: status->kind = stopped, signal = SIGTRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x40091e infrun: stepped to a different line infrun: stop_stepping [Switching to Thread 0x2aaaab8f5700 (LWP 11663)] 69 (*myp) ++; /* set breakpoint child_two here */ ^^^ we stopped at the wrong line. We still stepped a bit because the test is running in a loop, and when we got back to stepping thread 3, it happened to be in the stepping range. (The loop increments a counter, and the test makes sure it increments exactly once. Without the fix, the counter increments a bunch, since the user-stepped thread runs free without GDB noticing.) The fix is switch to the stepping thread before continuing for the step-resume breakpoint. 2014-01-23 Pedro Alves gdb/ * infrun.c (handle_signal_stop) : Switch back to the stepping thread. 2014-01-23 Pedro Alves Pedro Alves gdb/testsuite/ * gdb.threads/step-after-sr-lock.c: New. * gdb.threads/step-after-sr-lock.exp: New. --- gdb/infrun.c | 6 +- gdb/testsuite/gdb.threads/step-after-sr-lock.c | 145 +++++++++++++++++++++++ gdb/testsuite/gdb.threads/step-after-sr-lock.exp | 120 +++++++++++++++++++ 3 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.threads/step-after-sr-lock.c create mode 100644 gdb/testsuite/gdb.threads/step-after-sr-lock.exp diff --git a/gdb/infrun.c b/gdb/infrun.c index 71d9615..99ef13b 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -4380,7 +4380,11 @@ handle_signal_stop (struct execution_control_state *ecs) ecs->event_thread->step_after_step_resume_breakpoint = 1; /* Reset trap_expected to ensure breakpoints are re-inserted. */ ecs->event_thread->control.trap_expected = 0; - keep_going (ecs); + + /* If we were nexting/stepping some other thread, switch to + it, so that we don't continue it, losing control. */ + if (!switch_back_to_stepped_thread (ecs)) + keep_going (ecs); return; } diff --git a/gdb/testsuite/gdb.threads/step-after-sr-lock.c b/gdb/testsuite/gdb.threads/step-after-sr-lock.c new file mode 100644 index 0000000..fa0f6f1 --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-after-sr-lock.c @@ -0,0 +1,145 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009, 2010, 2011 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 . */ + +#include +#include +#include +#include + +unsigned int args[2]; + +pid_t pid; +pthread_barrier_t barrier; +pthread_t child_thread_2, child_thread_3; + +void +handler (int signo) +{ + /* so that thread 3 is sure to run, in case the bug is present. */ + usleep (10); +} + +void +callme (void) +{ +} + +void +block_signals (void) +{ + sigset_t mask; + + sigfillset (&mask); + sigprocmask (SIG_BLOCK, &mask, NULL); +} + +void +unblock_signals (void) +{ + sigset_t mask; + + sigfillset (&mask); + sigprocmask (SIG_UNBLOCK, &mask, NULL); +} + +void * +child_function_3 (void *arg) +{ + int my_number = (long) arg; + volatile int *myp = (int *) &args[my_number]; + + pthread_barrier_wait (&barrier); + + while (*myp > 0) + { + (*myp) ++; /* set breakpoint child_two here */ + callme (); + } + + pthread_exit (NULL); +} + +void * +child_function_2 (void *arg) +{ + int my_number = (long) arg; + volatile int *myp = (int *) &args[my_number]; + + unblock_signals (); + + pthread_barrier_wait (&barrier); + + while (*myp > 0) + { + (*myp) ++; + callme (); /* set breakpoint child_one here */ + } + + *myp = 1; + while (*myp > 0) + { + (*myp) ++; + callme (); + } + + pthread_exit (NULL); +} + + +int +main () +{ + int res; + long i; + + /* Block signals in all threads but one, so that we're sure which + thread gets the signal we send from the command line. */ + block_signals (); + + signal (SIGUSR1, handler); + + /* Call these early so that PLTs for these are resolved soon, + instead of in the threads. RTLD_NOW should work as well. */ + usleep (0); + pthread_barrier_init (&barrier, NULL, 1); + pthread_barrier_wait (&barrier); + + pthread_barrier_init (&barrier, NULL, 2); + + /* The test uses this global to know where to send the signal + to. */ + pid = getpid (); + + i = 0; + args[i] = 1; + res = pthread_create (&child_thread_2, + NULL, child_function_2, (void *) i); + pthread_barrier_wait (&barrier); + callme (); /* set wait-thread-2 breakpoint here */ + + i = 1; + args[i] = 1; + res = pthread_create (&child_thread_3, + NULL, child_function_3, (void *) i); + pthread_barrier_wait (&barrier); + callme (); /* set wait-thread-3 breakpoint here */ + + pthread_join (child_thread_2, NULL); + pthread_join (child_thread_3, NULL); + + exit(EXIT_SUCCESS); +} diff --git a/gdb/testsuite/gdb.threads/step-after-sr-lock.exp b/gdb/testsuite/gdb.threads/step-after-sr-lock.exp new file mode 100644 index 0000000..7fea49e --- /dev/null +++ b/gdb/testsuite/gdb.threads/step-after-sr-lock.exp @@ -0,0 +1,120 @@ +# Copyright (C) 2011 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 . + +# Test that GDB doesn't inadvertently resume the stepped thread when a +# signal arrives while stepping over the breakpoint that last caused a +# stop, when the thread that hit that breakpoint is not the stepped +# thread. + +standard_testfile +set executable ${testfile} + +if [target_info exists gdb,nosignals] { + verbose "Skipping ${testfile}.exp because of nosignals." + return -1 +} + +# Test uses host "kill". +if { [is_remote target] } { + return -1 +} + +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ + executable [list debug "incdir=${objdir}"]] != "" } { + return -1 +} + +proc get_value {var test} { + global expect_out + global gdb_prompt + global decimal + + set value -1 + gdb_test_multiple "print $var" "$test" { + -re ".*= ($decimal).*\r\n$gdb_prompt $" { + set value $expect_out(1,string) + pass "$test" + } + } + return ${value} +} + +# Start with a fresh gdb. + +clean_restart $executable + +if ![runto_main] { + return -1 +} + +gdb_breakpoint [gdb_get_line_number "set wait-thread-2 breakpoint here"] +gdb_continue_to_breakpoint "run to wait-thread-2 breakpoint" +gdb_test "info threads" "" "info threads with thread 2" + +gdb_breakpoint [gdb_get_line_number "set wait-thread-3 breakpoint here"] +gdb_continue_to_breakpoint "run to breakpoint" +gdb_test "info threads" "" "info threads with thread 3" + +set testpid [get_value "pid" "get pid of inferior"] + +gdb_test "set scheduler-locking on" + +gdb_breakpoint [gdb_get_line_number "set breakpoint child_two here"] +gdb_breakpoint [gdb_get_line_number "set breakpoint child_one here"] + +gdb_test "thread 3" "" "switch to thread 3 to run to its breakpoint" +gdb_continue_to_breakpoint "run to breakpoint in thread 3" + +gdb_test "thread 2" "" "switch to thread 2 to run to its breakpoint" +gdb_continue_to_breakpoint "run to breakpoint in thread 2" + +delete_breakpoints + +gdb_test "b *\$pc" "" "set breakpoint to be stepped over" +# Make sure the first loop breaks without hitting the breakpoint +# again. +gdb_test "p *myp = 0" " = 0" "force loop break in thread 2" + +# We want "print" to make sure the target reports the signal to the +# core. +gdb_test "handle SIGUSR1 print nostop pass" "" "" + +# Queue a signal in thread 2. +remote_exec host "kill -SIGUSR1 ${testpid}" + +gdb_test "thread 3" "" "switch to thread 3 for stepping" +set my_number [get_value "my_number" "get my_number"] +set cnt_before [get_value "args\[$my_number\]" "get count before step"] +gdb_test "set scheduler-locking off" + +# Make sure we're exercising the paths we want to. +gdb_test "set debug infrun 1" + +gdb_test \ + "step" \ + ".*prepare_to_proceed \\(step=1\\), switched to.*signal arrived while stepping over breakpoint.*switching back to stepped thread.*stepped to a different line.*callme.*" \ + "step" + +set cnt_after [get_value "args\[$my_number\]" "get count after step"] + +# Test that GDB doesn't inadvertently resume the stepped thread when a +# signal arrives while stepping over a breakpoint in another thread. + +set test "stepped thread under control" +if { $cnt_before + 1 == $cnt_after } { + pass $test +} else { + fail $test +} -- 1.7.11.7