[02/12] Fix "target extended-remote" + "maint set target-non-stop" + "attach"

Message ID 20210113011543.2047449-3-pedro@palves.net
State New
Headers show
Series
  • Fix detach + displaced-step regression + N bugs more
Related show

Commit Message

Pedro Alves Jan. 13, 2021, 1:15 a.m.
With "target extended-remote" + "maint set target-non-stop", attaching
hangs like so:

 (gdb) attach 1244450
 Attaching to process 1244450
 [New Thread 1244450.1244450]
 [New Thread 1244450.1244453]
 [New Thread 1244450.1244454]
 [New Thread 1244450.1244455]
 [New Thread 1244450.1244456]
 [New Thread 1244450.1244457]
 [New Thread 1244450.1244458]
 [New Thread 1244450.1244459]
 [New Thread 1244450.1244461]
 [New Thread 1244450.1244462]
 [New Thread 1244450.1244463]
 * hang *

Attaching to the hung GDB shows that GDB is busy in an infinite loop
in stop_all_threads:

 (top-gdb) bt
 #0  stop_all_threads () at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:4755
 #1  0x000055555597b424 in stop_waiting (ecs=0x7fffffffd930) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:7738
 #2  0x0000555555976fba in handle_signal_stop (ecs=0x7fffffffd930) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:5868
 #3  0x0000555555975f6a in handle_inferior_event (ecs=0x7fffffffd930) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:5527
 #4  0x0000555555971da4 in fetch_inferior_event () at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:3910
 #5  0x00005555559540b2 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/binutils-gdb/src/gdb/inf-loop.c:42
 #6  0x000055555597e825 in infrun_async_inferior_event_handler (data=0x0) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:9162
 #7  0x0000555555687d1d in check_async_event_handlers () at /home/pedro/gdb/binutils-gdb/src/gdb/async-event.c:328
 #8  0x0000555555e48284 in gdb_do_one_event () at /home/pedro/gdb/binutils-gdb/src/gdbsupport/event-loop.cc:216
 #9  0x00005555559e7512 in start_event_loop () at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:347
 #10 0x00005555559e765d in captured_command_loop () at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:407
 #11 0x00005555559e8f80 in captured_main (data=0x7fffffffdb70) at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:1239
 #12 0x00005555559e8ff2 in gdb_main (args=0x7fffffffdb70) at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:1254
 #13 0x0000555555627c86 in main (argc=12, argv=0x7fffffffdc88) at /home/pedro/gdb/binutils-gdb/src/gdb/gdb.c:32

The problem is that the remote sends stops for all the threads:

 Packet received: l/home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.threads/attach-non-stop/attach-non-stop
 Sending packet: $vStopped#55...Packet received: T0006:f06e25edec7f0000;07:f06e25edec7f0000;10:f14190ccf4550000;thread:p12fd22.12fd2f;core:15;
 Sending packet: $vStopped#55...Packet received: T0006:f0dea5f0ec7f0000;07:f0dea5f0ec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd27;core:4;
 Sending packet: $vStopped#55...Packet received: T0006:f0ee25f1ec7f0000;07:f0ee25f1ec7f0000;10:f14190ccf4550000;thread:p12fd22.12fd26;core:5;
 Sending packet: $vStopped#55...Packet received: T0006:f0bea5efec7f0000;07:f0bea5efec7f0000;10:f14190ccf4550000;thread:p12fd22.12fd29;core:1;
 Sending packet: $vStopped#55...Packet received: T0006:f0ce25f0ec7f0000;07:f0ce25f0ec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd28;core:a;
 Sending packet: $vStopped#55...Packet received: T0006:f07ea5edec7f0000;07:f07ea5edec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd2e;core:f;
 Sending packet: $vStopped#55...Packet received: T0006:f0ae25efec7f0000;07:f0ae25efec7f0000;10:df4190ccf4550000;thread:p12fd22.12fd2a;core:6;
 Sending packet: $vStopped#55...Packet received: T0006:0000000000000000;07:c0e8a381fe7f0000;10:bf43b4f1ec7f0000;thread:p12fd22.12fd22;core:2;
 Sending packet: $vStopped#55...Packet received: T0006:f0fea5f1ec7f0000;07:f0fea5f1ec7f0000;10:df4190ccf4550000;thread:p12fd22.12fd25;core:8;
 Sending packet: $vStopped#55...Packet received: T0006:f09ea5eeec7f0000;07:f09ea5eeec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd2b;core:b;
 Sending packet: $vStopped#55...Packet received: OK

But then wait_one never consumes them, always hitting this path:

 4473          if (nfds == 0)
 4474            {
 4475              /* No waitable targets left.  All must be stopped.  */
 4476              return {NULL, minus_one_ptid, {TARGET_WAITKIND_NO_RESUMED}};
 4477            }

Resulting in GDB constanly calling target_stop to stop threads, but
the remote target never reporting back the stops to infrun.

That TARGET_WAITKIND_NO_RESUMED path shown above is always taken
because here, in wait_one too, just above:

 4428          for (inferior *inf : all_inferiors ())
 4429            {
 4430              process_stratum_target *target = inf->process_target ();
 4431              if (target == NULL
 4432                  || !target->is_async_p ()
                           ^^^^^^^^^^^^^^^^^^^^^
 4433                  || !target->threads_executing)
 4434                continue;

... the remote target is not async.

And in turn that happened because extended_remote_target::attach
misses enabling async in the target-non-stop path.

A testcase exercising this will be added in a following patch.

gdb/ChangeLog:

	* remote.c (extended_remote_target::attach): Set target async in
	the target-non-stop path too.
---
 gdb/remote.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

-- 
2.26.2

Comments

Eli Zaretskii via Gdb-patches Jan. 13, 2021, 5:01 a.m. | #1
On 2021-01-12 8:15 p.m., Pedro Alves wrote:
> With "target extended-remote" + "maint set target-non-stop", attaching

> hangs like so:

> 

>  (gdb) attach 1244450

>  Attaching to process 1244450

>  [New Thread 1244450.1244450]

>  [New Thread 1244450.1244453]

>  [New Thread 1244450.1244454]

>  [New Thread 1244450.1244455]

>  [New Thread 1244450.1244456]

>  [New Thread 1244450.1244457]

>  [New Thread 1244450.1244458]

>  [New Thread 1244450.1244459]

>  [New Thread 1244450.1244461]

>  [New Thread 1244450.1244462]

>  [New Thread 1244450.1244463]

>  * hang *

> 

> Attaching to the hung GDB shows that GDB is busy in an infinite loop

> in stop_all_threads:

> 

>  (top-gdb) bt

>  #0  stop_all_threads () at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:4755

>  #1  0x000055555597b424 in stop_waiting (ecs=0x7fffffffd930) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:7738

>  #2  0x0000555555976fba in handle_signal_stop (ecs=0x7fffffffd930) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:5868

>  #3  0x0000555555975f6a in handle_inferior_event (ecs=0x7fffffffd930) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:5527

>  #4  0x0000555555971da4 in fetch_inferior_event () at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:3910

>  #5  0x00005555559540b2 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/binutils-gdb/src/gdb/inf-loop.c:42

>  #6  0x000055555597e825 in infrun_async_inferior_event_handler (data=0x0) at /home/pedro/gdb/binutils-gdb/src/gdb/infrun.c:9162

>  #7  0x0000555555687d1d in check_async_event_handlers () at /home/pedro/gdb/binutils-gdb/src/gdb/async-event.c:328

>  #8  0x0000555555e48284 in gdb_do_one_event () at /home/pedro/gdb/binutils-gdb/src/gdbsupport/event-loop.cc:216

>  #9  0x00005555559e7512 in start_event_loop () at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:347

>  #10 0x00005555559e765d in captured_command_loop () at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:407

>  #11 0x00005555559e8f80 in captured_main (data=0x7fffffffdb70) at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:1239

>  #12 0x00005555559e8ff2 in gdb_main (args=0x7fffffffdb70) at /home/pedro/gdb/binutils-gdb/src/gdb/main.c:1254

>  #13 0x0000555555627c86 in main (argc=12, argv=0x7fffffffdc88) at /home/pedro/gdb/binutils-gdb/src/gdb/gdb.c:32

> 

> The problem is that the remote sends stops for all the threads:

> 

>  Packet received: l/home/pedro/gdb/binutils-gdb/build/gdb/testsuite/outputs/gdb.threads/attach-non-stop/attach-non-stop

>  Sending packet: $vStopped#55...Packet received: T0006:f06e25edec7f0000;07:f06e25edec7f0000;10:f14190ccf4550000;thread:p12fd22.12fd2f;core:15;

>  Sending packet: $vStopped#55...Packet received: T0006:f0dea5f0ec7f0000;07:f0dea5f0ec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd27;core:4;

>  Sending packet: $vStopped#55...Packet received: T0006:f0ee25f1ec7f0000;07:f0ee25f1ec7f0000;10:f14190ccf4550000;thread:p12fd22.12fd26;core:5;

>  Sending packet: $vStopped#55...Packet received: T0006:f0bea5efec7f0000;07:f0bea5efec7f0000;10:f14190ccf4550000;thread:p12fd22.12fd29;core:1;

>  Sending packet: $vStopped#55...Packet received: T0006:f0ce25f0ec7f0000;07:f0ce25f0ec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd28;core:a;

>  Sending packet: $vStopped#55...Packet received: T0006:f07ea5edec7f0000;07:f07ea5edec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd2e;core:f;

>  Sending packet: $vStopped#55...Packet received: T0006:f0ae25efec7f0000;07:f0ae25efec7f0000;10:df4190ccf4550000;thread:p12fd22.12fd2a;core:6;

>  Sending packet: $vStopped#55...Packet received: T0006:0000000000000000;07:c0e8a381fe7f0000;10:bf43b4f1ec7f0000;thread:p12fd22.12fd22;core:2;

>  Sending packet: $vStopped#55...Packet received: T0006:f0fea5f1ec7f0000;07:f0fea5f1ec7f0000;10:df4190ccf4550000;thread:p12fd22.12fd25;core:8;

>  Sending packet: $vStopped#55...Packet received: T0006:f09ea5eeec7f0000;07:f09ea5eeec7f0000;10:e84190ccf4550000;thread:p12fd22.12fd2b;core:b;

>  Sending packet: $vStopped#55...Packet received: OK

> 

> But then wait_one never consumes them, always hitting this path:

> 

>  4473          if (nfds == 0)

>  4474            {

>  4475              /* No waitable targets left.  All must be stopped.  */

>  4476              return {NULL, minus_one_ptid, {TARGET_WAITKIND_NO_RESUMED}};

>  4477            }

> 

> Resulting in GDB constanly calling target_stop to stop threads, but

> the remote target never reporting back the stops to infrun.

> 

> That TARGET_WAITKIND_NO_RESUMED path shown above is always taken

> because here, in wait_one too, just above:

> 

>  4428          for (inferior *inf : all_inferiors ())

>  4429            {

>  4430              process_stratum_target *target = inf->process_target ();

>  4431              if (target == NULL

>  4432                  || !target->is_async_p ()

>                            ^^^^^^^^^^^^^^^^^^^^^

>  4433                  || !target->threads_executing)

>  4434                continue;

> 

> ... the remote target is not async.

> 

> And in turn that happened because extended_remote_target::attach

> misses enabling async in the target-non-stop path.

> 

> A testcase exercising this will be added in a following patch.

> 

> gdb/ChangeLog:

> 

> 	* remote.c (extended_remote_target::attach): Set target async in

> 	the target-non-stop path too.

> ---

>  gdb/remote.c | 7 ++++++-

>  1 file changed, 6 insertions(+), 1 deletion(-)

> 

> diff --git a/gdb/remote.c b/gdb/remote.c

> index 6dacc24307e..2f15c4c1f32 100644

> --- a/gdb/remote.c

> +++ b/gdb/remote.c

> @@ -5968,7 +5968,12 @@ extended_remote_target::attach (const char *args, int from_tty)

>  	}

>      }

>    else

> -    gdb_assert (wait_status == NULL);

> +    {

> +      gdb_assert (wait_status == NULL);

> +

> +      gdb_assert (target_can_async_p ());

> +      target_async (1);

> +    }

>  }

>  

>  /* Implementation of the to_post_attach method.  */

> 


LGTM.

Simon

Patch

diff --git a/gdb/remote.c b/gdb/remote.c
index 6dacc24307e..2f15c4c1f32 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5968,7 +5968,12 @@  extended_remote_target::attach (const char *args, int from_tty)
 	}
     }
   else
-    gdb_assert (wait_status == NULL);
+    {
+      gdb_assert (wait_status == NULL);
+
+      gdb_assert (target_can_async_p ());
+      target_async (1);
+    }
 }
 
 /* Implementation of the to_post_attach method.  */