Linux native thread create/exit events support
A following patch (fix for gdb/19828) makes linux-nat.c add threads to
GDB's thread list earlier in the "attach" sequence, and that causes a
surprising regression on
gdb.threads/attach-many-short-lived-threads.exp on my machine. The
extra "thread x exited" handling and traffic slows down that test
enough that GDB core has trouble keeping up with new threads that are
spawned while trying to stop existing ones.
I saw the exact same issue with remote/gdbserver a while ago and fixed
it in 65706a29ba
(Remote thread create/exit events) so part of the
fix here is the exact same -- add support for thread created events to
gdb/linux-nat.c. infrun.c:stop_all_threads enables those events when
it tries to stop threads, which ensures that new threads never get a
chance to themselves start new threads, thus fixing the race.
gdb/
2016-05-24 Pedro Alves <palves@redhat.com>
PR gdb/19828
* linux-nat.c (report_thread_events): New global.
(linux_handle_extended_wait): Report
TARGET_WAITKIND_THREAD_CREATED if thread event reporting is
enabled.
(wait_lwp, linux_nat_filter_event): Report all thread exits if
thread event reporting is enabled. Remove comment.
(filter_exit_event): New function.
(linux_nat_wait_1): Use it.
(linux_nat_thread_events): New function.
(linux_nat_add_target): Install it as target_thread_events method.
This commit is contained in:
parent
44d3da2338
commit
aa01bd3689
3 changed files with 73 additions and 17 deletions
|
@ -1,3 +1,17 @@
|
||||||
|
2016-05-24 Pedro Alves <palves@redhat.com>
|
||||||
|
|
||||||
|
PR gdb/19828
|
||||||
|
* linux-nat.c (report_thread_events): New global.
|
||||||
|
(linux_handle_extended_wait): Report
|
||||||
|
TARGET_WAITKIND_THREAD_CREATED if thread event reporting is
|
||||||
|
enabled.
|
||||||
|
(wait_lwp, linux_nat_filter_event): Report all thread exits if
|
||||||
|
thread event reporting is enabled. Remove comment.
|
||||||
|
(filter_exit_event): New function.
|
||||||
|
(linux_nat_wait_1): Use it.
|
||||||
|
(linux_nat_thread_events): New function.
|
||||||
|
(linux_nat_add_target): Install it as target_thread_events method.
|
||||||
|
|
||||||
2016-05-24 Yan-Ting Lin <currygt52@gmail.com>
|
2016-05-24 Yan-Ting Lin <currygt52@gmail.com>
|
||||||
|
|
||||||
* MAINTAINERS (Write After Approval): Add "Yan-Ting Lin".
|
* MAINTAINERS (Write After Approval): Add "Yan-Ting Lin".
|
||||||
|
|
|
@ -239,6 +239,9 @@ struct simple_pid_list
|
||||||
};
|
};
|
||||||
struct simple_pid_list *stopped_pids;
|
struct simple_pid_list *stopped_pids;
|
||||||
|
|
||||||
|
/* Whether target_thread_events is in effect. */
|
||||||
|
static int report_thread_events;
|
||||||
|
|
||||||
/* Async mode support. */
|
/* Async mode support. */
|
||||||
|
|
||||||
/* The read/write ends of the pipe registered as waitable file in the
|
/* The read/write ends of the pipe registered as waitable file in the
|
||||||
|
@ -1952,6 +1955,11 @@ linux_handle_extended_wait (struct lwp_info *lp, int status)
|
||||||
status_to_str (status));
|
status_to_str (status));
|
||||||
new_lp->status = status;
|
new_lp->status = status;
|
||||||
}
|
}
|
||||||
|
else if (report_thread_events)
|
||||||
|
{
|
||||||
|
new_lp->waitstatus.kind = TARGET_WAITKIND_THREAD_CREATED;
|
||||||
|
new_lp->status = status;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2091,13 +2099,14 @@ wait_lwp (struct lwp_info *lp)
|
||||||
/* Check if the thread has exited. */
|
/* Check if the thread has exited. */
|
||||||
if (WIFEXITED (status) || WIFSIGNALED (status))
|
if (WIFEXITED (status) || WIFSIGNALED (status))
|
||||||
{
|
{
|
||||||
if (ptid_get_pid (lp->ptid) == ptid_get_lwp (lp->ptid))
|
if (report_thread_events
|
||||||
|
|| ptid_get_pid (lp->ptid) == ptid_get_lwp (lp->ptid))
|
||||||
{
|
{
|
||||||
if (debug_linux_nat)
|
if (debug_linux_nat)
|
||||||
fprintf_unfiltered (gdb_stdlog, "WL: Process %d exited.\n",
|
fprintf_unfiltered (gdb_stdlog, "WL: LWP %d exited.\n",
|
||||||
ptid_get_pid (lp->ptid));
|
ptid_get_pid (lp->ptid));
|
||||||
|
|
||||||
/* This is the leader exiting, it means the whole
|
/* If this is the leader exiting, it means the whole
|
||||||
process is gone. Store the status to report to the
|
process is gone. Store the status to report to the
|
||||||
core. Store it in lp->waitstatus, because lp->status
|
core. Store it in lp->waitstatus, because lp->status
|
||||||
would be ambiguous (W_EXITCODE(0,0) == 0). */
|
would be ambiguous (W_EXITCODE(0,0) == 0). */
|
||||||
|
@ -2902,7 +2911,8 @@ linux_nat_filter_event (int lwpid, int status)
|
||||||
/* Check if the thread has exited. */
|
/* Check if the thread has exited. */
|
||||||
if (WIFEXITED (status) || WIFSIGNALED (status))
|
if (WIFEXITED (status) || WIFSIGNALED (status))
|
||||||
{
|
{
|
||||||
if (num_lwps (ptid_get_pid (lp->ptid)) > 1)
|
if (!report_thread_events
|
||||||
|
&& num_lwps (ptid_get_pid (lp->ptid)) > 1)
|
||||||
{
|
{
|
||||||
if (debug_linux_nat)
|
if (debug_linux_nat)
|
||||||
fprintf_unfiltered (gdb_stdlog,
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
|
@ -2922,15 +2932,9 @@ linux_nat_filter_event (int lwpid, int status)
|
||||||
resumed. */
|
resumed. */
|
||||||
if (debug_linux_nat)
|
if (debug_linux_nat)
|
||||||
fprintf_unfiltered (gdb_stdlog,
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
"Process %ld exited (resumed=%d)\n",
|
"LWP %ld exited (resumed=%d)\n",
|
||||||
ptid_get_lwp (lp->ptid), lp->resumed);
|
ptid_get_lwp (lp->ptid), lp->resumed);
|
||||||
|
|
||||||
/* This was the last lwp in the process. Since events are
|
|
||||||
serialized to GDB core, we may not be able report this one
|
|
||||||
right now, but GDB core and the other target layers will want
|
|
||||||
to be notified about the exit code/signal, leave the status
|
|
||||||
pending for the next time we're able to report it. */
|
|
||||||
|
|
||||||
/* Dead LWP's aren't expected to reported a pending sigstop. */
|
/* Dead LWP's aren't expected to reported a pending sigstop. */
|
||||||
lp->signalled = 0;
|
lp->signalled = 0;
|
||||||
|
|
||||||
|
@ -3110,6 +3114,30 @@ check_zombie_leaders (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convenience function that is called when the kernel reports an exit
|
||||||
|
event. This decides whether to report the event to GDB as a
|
||||||
|
process exit event, a thread exit event, or to suppress the
|
||||||
|
event. */
|
||||||
|
|
||||||
|
static ptid_t
|
||||||
|
filter_exit_event (struct lwp_info *event_child,
|
||||||
|
struct target_waitstatus *ourstatus)
|
||||||
|
{
|
||||||
|
ptid_t ptid = event_child->ptid;
|
||||||
|
|
||||||
|
if (num_lwps (ptid_get_pid (ptid)) > 1)
|
||||||
|
{
|
||||||
|
if (report_thread_events)
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED;
|
||||||
|
else
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
|
||||||
|
exit_lwp (event_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptid;
|
||||||
|
}
|
||||||
|
|
||||||
static ptid_t
|
static ptid_t
|
||||||
linux_nat_wait_1 (struct target_ops *ops,
|
linux_nat_wait_1 (struct target_ops *ops,
|
||||||
ptid_t ptid, struct target_waitstatus *ourstatus,
|
ptid_t ptid, struct target_waitstatus *ourstatus,
|
||||||
|
@ -3339,6 +3367,9 @@ linux_nat_wait_1 (struct target_ops *ops,
|
||||||
else
|
else
|
||||||
lp->core = linux_common_core_of_thread (lp->ptid);
|
lp->core = linux_common_core_of_thread (lp->ptid);
|
||||||
|
|
||||||
|
if (ourstatus->kind == TARGET_WAITKIND_EXITED)
|
||||||
|
return filter_exit_event (lp, ourstatus);
|
||||||
|
|
||||||
return lp->ptid;
|
return lp->ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4614,6 +4645,14 @@ linux_nat_fileio_unlink (struct target_ops *self,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Implementation of the to_thread_events method. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
linux_nat_thread_events (struct target_ops *ops, int enable)
|
||||||
|
{
|
||||||
|
report_thread_events = enable;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
linux_nat_add_target (struct target_ops *t)
|
linux_nat_add_target (struct target_ops *t)
|
||||||
{
|
{
|
||||||
|
@ -4646,6 +4685,7 @@ linux_nat_add_target (struct target_ops *t)
|
||||||
t->to_supports_stopped_by_sw_breakpoint = linux_nat_supports_stopped_by_sw_breakpoint;
|
t->to_supports_stopped_by_sw_breakpoint = linux_nat_supports_stopped_by_sw_breakpoint;
|
||||||
t->to_stopped_by_hw_breakpoint = linux_nat_stopped_by_hw_breakpoint;
|
t->to_stopped_by_hw_breakpoint = linux_nat_stopped_by_hw_breakpoint;
|
||||||
t->to_supports_stopped_by_hw_breakpoint = linux_nat_supports_stopped_by_hw_breakpoint;
|
t->to_supports_stopped_by_hw_breakpoint = linux_nat_supports_stopped_by_hw_breakpoint;
|
||||||
|
t->to_thread_events = linux_nat_thread_events;
|
||||||
|
|
||||||
t->to_can_async_p = linux_nat_can_async_p;
|
t->to_can_async_p = linux_nat_can_async_p;
|
||||||
t->to_is_async_p = linux_nat_is_async_p;
|
t->to_is_async_p = linux_nat_is_async_p;
|
||||||
|
|
|
@ -1116,12 +1116,14 @@ thread_db_wait (struct target_ops *ops,
|
||||||
|
|
||||||
ptid = beneath->to_wait (beneath, ptid, ourstatus, options);
|
ptid = beneath->to_wait (beneath, ptid, ourstatus, options);
|
||||||
|
|
||||||
if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
|
switch (ourstatus->kind)
|
||||||
return ptid;
|
{
|
||||||
|
case TARGET_WAITKIND_IGNORE:
|
||||||
if (ourstatus->kind == TARGET_WAITKIND_EXITED
|
case TARGET_WAITKIND_EXITED:
|
||||||
|| ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
|
case TARGET_WAITKIND_THREAD_EXITED:
|
||||||
return ptid;
|
case TARGET_WAITKIND_SIGNALLED:
|
||||||
|
return ptid;
|
||||||
|
}
|
||||||
|
|
||||||
info = get_thread_db_info (ptid_get_pid (ptid));
|
info = get_thread_db_info (ptid_get_pid (ptid));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue