gdb/infrun: stop all threads if there exists a non-stop target
authorTankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Wed, 1 Apr 2020 19:33:06 +0000 (21:33 +0200)
committerTankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Wed, 1 Apr 2020 19:33:06 +0000 (21:33 +0200)
commit53cccef118b80913d76c0737108f6c32471cd09e
tree66f06bd80be81a4c93fda5ed54769bf87aca481a
parenta0714d305fb78b3a2a74a2acd6d8c66da80a6387
gdb/infrun: stop all threads if there exists a non-stop target

Stop all threads not only if the current target is non-stop, but also
if there exists a non-stop target.

The multi-target patch (5b6d1e4fa4f "Multi-target support") made the
following change to gdb/inf-child.c:

void
 inf_child_target::maybe_unpush_target ()
 {
-  if (!inf_child_explicitly_opened && !have_inferiors ())
+  if (!inf_child_explicitly_opened)
     unpush_target (this);
 }

If we are in all-stop mode with multiple inferiors, and an exit event
is received from an inferior, target_mourn_inferior() gets to this
point and without the have_inferiors() check, the target is unpushed.
This leads to having exec_ops as the top target.

Here is a test scenario.  Two executables, ./a.out returns
immediately; ./sleepy just sleeps.

  $ gdb ./sleepy
  (gdb) start
  ...
  (gdb) add-inferior -exec ./a.out
  ...
  (gdb) inferior 2
  [Switching to inferior 2..
  (gdb) start
  ...
  (gdb) set schedule-multiple on
  (gdb) set debug infrun 1
  (gdb) continue

At this point, the exit event is received from ./a.out.  Normally,
this would lead to stop_all_threads() to also stop ./sleepy, but this
doesn't happen, because target_is_non_stop_p() returns false.  And it
returns false because the top target is no longer the process target;
it is the exec_ops.

This patch modifies 'stop_waiting' to call 'stop_all_threads' if there
exists a non-stop target, not just when the current top target is
non-stop.

Tested on X86_64 Linux.

gdb/ChangeLog:
2020-04-01  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

* infrun.c (stop_all_threads): Update assertion, plus when
stopping threads, take into account that we might be trying
to stop an all-stop target.
(stop_waiting): Call 'stop_all_threads' if there exists a
non-stop target.

gdb/testsuite/ChangeLog:
2020-04-01  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

* gdb.multi/stop-all-on-exit.c: New test.
* gdb.multi/stop-all-on-exit.exp: New file.
gdb/ChangeLog
gdb/infrun.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.multi/stop-all-on-exit.c [new file with mode: 0644]
gdb/testsuite/gdb.multi/stop-all-on-exit.exp [new file with mode: 0644]