Hi Don, Sorry for the delay. On 07/24/2015 07:43 PM, Don Breazeal wrote: >> index 17b2a51..56a33ff 100644 >> --- a/gdb/gdbserver/linux-low.c >> +++ b/gdb/gdbserver/linux-low.c >> @@ -488,6 +488,13 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat) >> child_lwp->status_pending_p = 0; >> child_thr = get_lwp_thread (child_lwp); >> child_thr->last_resume_kind = resume_stop; >> + child_thr->last_status.kind = TARGET_WAITKIND_STOPPED; > > This makes perfect sense to me. > Great. >> + >> + /* If we're suspending all threads, leave this one suspended >> + too. */ >> + if (stopping_threads == STOPPING_AND_SUSPENDING_THREADS) >> + child_lwp->suspended = 1; > > I have a question about this. In the definition of struct lwp_info in > linux-low.h, it has this comment: > > /* When this is true, we shall not try to resume this thread, even > if last_resume_kind isn't resume_stop. */ > int suspended; > > Since we are setting last_resume_kind to resume_stop here, is this > unnecessary? We still need it, because otherwise we'd decrement the suspend count below 0: static int unsuspend_and_proceed_one_lwp (struct inferior_list_entry *entry, void *except) { struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); if (lwp == except) return 0; lwp->suspended--; gdb_assert (lwp->suspended >= 0); return proceed_one_lwp (entry, except); } It's proceed_one_lwp that skips resuming if the client wants the lwp stopped: static int proceed_one_lwp (struct inferior_list_entry *entry, void *except) { ... if (thread->last_resume_kind == resume_stop && thread->last_status.kind != TARGET_WAITKIND_IGNORE) { if (debug_threads) debug_printf (" client wants LWP to remain %ld stopped\n", lwpid_of (thread)); return 0; } I tried writing a test for this, by making a multithreaded program have all its threads but the main continuously fork (see attached), while the main thread continuously steps over a breakpoint (a conditional breakpoint with condition "0" should do it, as gdbserver handles that breakpoint itself), but that stumbles on yet more problems... :-/ $ ./gdb ./testsuite/gdb.threads/fork-plus-threads-2 -ex "set non-stop on" -ex "set detach-on-fork off" -ex "tar extended-rem :9999" ... Remote debugging using :9999 (gdb) [Thread 24971.24971] #1 stopped. 0x0000003615a011f0 in ?? () c& Continuing. (gdb) [New Thread 24971.24981] [New Thread 24983.24983] [New Thread 24971.24982] [Thread 24983.24983] #3 stopped. 0x0000003615ebc7cc in __libc_fork () at ../nptl/sysdeps/unix/sysv/linux/fork.c:130 130 pid = ARCH_FORK (); [New Thread 24984.24984] Error in re-setting breakpoint -16: PC register is not available Error in re-setting breakpoint -17: PC register is not available Error in re-setting breakpoint -18: PC register is not available Error in re-setting breakpoint -19: PC register is not available Error in re-setting breakpoint -24: PC register is not available Error in re-setting breakpoint -25: PC register is not available Error in re-setting breakpoint -26: PC register is not available Error in re-setting breakpoint -27: PC register is not available Error in re-setting breakpoint -28: PC register is not available Error in re-setting breakpoint -29: PC register is not available Error in re-setting breakpoint -30: PC register is not available PC register is not available (gdb) >> set test "reached breakpoint" BTW, I noticed that this test message is stale from my previous attempt at running to a breakpoint instead of to exit. I changed it to: set test "inferior 1 exited" in patch 1/2. >> gdb_test_multiple "" $test { >> + -re "Cannot remove breakpoints" { >> + set saw_cannot_remove_breakpoints 1 >> + exp_continue >> + } >> + -re "Thread \[^\r\n\]+ stopped\\." { >> + set saw_thread_stopped 1 >> + exp_continue >> + } >> -re "Inferior 1 \(\[^\r\n\]+\) exited normally" { >> pass $test >> } >> } Thanks, Pedro Alves