)]}'
{
  "commit": "e8a625d126e4be34d23b5df535bed134b2bb3156",
  "tree": "4f6facd5e1358c20b4ac8de9df20eb7957dd7f75",
  "parents": [
    "7ac958f267898ba87ae67ea04f94a3fda24567dc"
  ],
  "author": {
    "name": "Pedro Alves",
    "email": "pedro@palves.net",
    "time": "Wed Jun 15 13:19:47 2022 +0100"
  },
  "committer": {
    "name": "Pedro Alves",
    "email": "pedro@palves.net",
    "time": "Mon Nov 13 14:16:11 2023 +0000"
  },
  "message": "Report thread exit event for leader if reporting thread exit events\n\nIf GDB sets the GDB_THREAD_OPTION_EXIT option on a thread, then if the\nthread disappears from the thread list, GDB expects to shortly see a\nthread exit event for it.  See e.g., here, in\nremote_target::update_thread_list():\n\n    /* Do not remove the thread if we\u0027ve requested to be\n       notified of its exit.  For example, the thread may be\n       displaced stepping, infrun will need to handle the\n       exit event, and displaced stepping info is recorded\n       in the thread object.  If we deleted the thread now,\n       we\u0027d lose that info.  */\n    if ((tp-\u003ethread_options () \u0026 GDB_THREAD_OPTION_EXIT) !\u003d 0)\n      continue;\n\nThere\u0027s one scenario that is deleting a thread from the\nremote/gdbserver thread list without ever reporting a corresponding\nthread exit event though -- check_zombie_leaders.  This can lead to\nGDB getting confused.  For example, with a following patch that\nenables GDB_THREAD_OPTION_EXIT whenever schedlock is enabled, we\u0027d see\nthis regression:\n\n $ make check RUNTESTFLAGS\u003d\"--target_board\u003dnative-extended-gdbserver\" TESTS\u003d\"gdb.threads/no-unwaited-for-left.exp\"\n ...\n Running src/gdb/testsuite/gdb.threads/no-unwaited-for-left.exp ...\n FAIL: gdb.threads/no-unwaited-for-left.exp: continue stops when the main thread exits (timeout)\n ... some more cascading FAILs ...\n\ngdb.log shows:\n\n (gdb) continue\n Continuing.\n FAIL: gdb.threads/no-unwaited-for-left.exp: continue stops when the main thread exits (timeout)\n\nA passing run would have resulted in:\n\n (gdb) continue\n Continuing.\n No unwaited-for children left.\n (gdb) PASS: gdb.threads/no-unwaited-for-left.exp: continue stops when the main thread exits\n\nnote how the leader thread is not listed in the remote-reported XML\nthread list below:\n\n (gdb) set debug remote 1\n (gdb) set debug infrun 1\n (gdb) info threads\n   Id   Target Id                                Frame\n * 1    Thread 1163850.1163850 \"no-unwaited-for\" main () at /home/pedro/rocm/gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.threads/no-unwaited-for-left.c:65\n   3    Thread 1163850.1164130 \"no-unwaited-for\" [remote] Sending packet: $Hgp11c24a.11c362#39\n (gdb) c\n Continuing.\n [infrun] clear_proceed_status_thread: 1163850.1163850.0\n ...\n     [infrun] resume_1: step\u003d1, signal\u003dGDB_SIGNAL_0, trap_expected\u003d1, current thread [1163850.1163850.0] at 0x55555555534f\n     [remote] Sending packet: $QPassSignals:#f3\n     [remote] Packet received: OK\n     [remote] Sending packet: $QThreadOptions;3:p11c24a.11c24a#f3\n     [remote] Packet received: OK\n ...\n     [infrun] target_set_thread_options: [options for Thread 1163850.1163850 are now 0x3]\n ...\n   [infrun] do_target_resume: resume_ptid\u003d1163850.1163850.0, step\u003d0, sig\u003dGDB_SIGNAL_0\n   [remote] Sending packet: $vCont;c:p11c24a.11c24a#98\n   [infrun] prepare_to_wait: prepare_to_wait\n   [infrun] reset: reason\u003dhandling event\n   [infrun] maybe_set_commit_resumed_all_targets: enabling commit-resumed for target extended-remote\n   [infrun] maybe_call_commit_resumed_all_targets: calling commit_resumed for target extended-remote\n [infrun] fetch_inferior_event: exit\n [infrun] fetch_inferior_event: enter\n   [infrun] scoped_disable_commit_resumed: reason\u003dhandling event\n   [infrun] random_pending_event_thread: None found.\n   [remote] wait: enter\n     [remote] Packet received: N\n   [remote] wait: exit\n   [infrun] print_target_wait_results: target_wait (-1.0.0 [process -1], status) \u003d\n   [infrun] print_target_wait_results:   -1.0.0 [process -1],\n   [infrun] print_target_wait_results:   status-\u003ekind \u003d NO_RESUMED\n   [infrun] handle_inferior_event: status-\u003ekind \u003d NO_RESUMED\n   [remote] Sending packet: $Hgp0.0#ad\n   [remote] Packet received: OK\n   [remote] Sending packet: $qXfer:threads:read::0,1000#92\n   [remote] Packet received: l\u003cthreads\u003e\\n\u003cthread id\u003d\"p11c24a.11c362\" core\u003d\"0\" name\u003d\"no-unwaited-for\" handle\u003d\"0097d8f7ff7f0000\"/\u003e\\n\u003c/threads\u003e\\n\n   [infrun] handle_no_resumed: TARGET_WAITKIND_NO_RESUMED (ignoring: found resumed)\n ...\n\n... however, infrun decided there was a resumed thread still, so\nignored the TARGET_WAITKIND_NO_RESUMED event.  Debugging GDB, we see\nthat the \"found resumed\" thread that GDB finds, is the leader thread.\nEven though that thread is not on the remote-reported thread list, it\nis still on the GDB thread list, due to the special case in remote.c\nmentioned above.\n\nThis commit addresses the issue by fixing GDBserver to report a thread\nexit event for the zombie leader too, i.e., making GDBserver respect\nthe \"if thread has GDB_THREAD_OPTION_EXIT set, report a thread exit\"\ninvariant.  To do that, it takes a bit more code than one would\nimagine off hand, due to the fact that we currently always report LWP\nexit pending events as TARGET_WAITKIND_EXITED, and then decide whether\nto convert it to TARGET_WAITKIND_THREAD_EXITED just before reporting\nthe event to GDBserver core.  For the zombie leader scenario\ndescribed, we need to record early on that we want to report a\nTHREAD_EXITED event, and then make sure that decision isn\u0027t lost along\nthe way to reporting the event to GDBserver core.\n\nReviewed-By: Andrew Burgess \u003caburgess@redhat.com\u003e\nChange-Id: I1e68fccdbc9534434dee07163d3fd19744c8403b\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "44d0fe38030ff1d8c4b17fbd22532f90f7922b22",
      "old_mode": 33188,
      "old_path": "gdbserver/linux-low.cc",
      "new_id": "f9001e2fa1746e214ae20d6840e477ad67175295",
      "new_mode": 33188,
      "new_path": "gdbserver/linux-low.cc"
    },
    {
      "type": "modify",
      "old_id": "d46ea5aa3ec36f761233239687744cb410aa57ac",
      "old_mode": 33188,
      "old_path": "gdbserver/linux-low.h",
      "new_id": "51d1899893a6fa6de21933feaf25bd4471bc0bf8",
      "new_mode": 33188,
      "new_path": "gdbserver/linux-low.h"
    }
  ]
}
