diff options
author | Pedro Alves <palves@redhat.com> | 2015-04-07 15:47:22 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2015-04-07 15:47:22 +0100 |
commit | 8a06aea71e0aa9099d0ca593dbb58f6e056af4ff (patch) | |
tree | a79ed9ea54e264511b552b4903067e3ecb152b71 /gdb/linux-nat.c | |
parent | 87070c082fd5c23e9a0e7994ff9ea13f6faecb3e (diff) | |
download | gdb-8a06aea71e0aa9099d0ca593dbb58f6e056af4ff.zip gdb-8a06aea71e0aa9099d0ca593dbb58f6e056af4ff.tar.gz gdb-8a06aea71e0aa9099d0ca593dbb58f6e056af4ff.tar.bz2 |
update thread list, delete exited threads
On GNU/Linux, if the running kernel supports clone events, then
linux-thread-db.c defers thread listing to the target beneath:
static void
thread_db_update_thread_list (struct target_ops *ops)
{
...
if (target_has_execution && !thread_db_use_events ())
ops->beneath->to_update_thread_list (ops->beneath);
else
thread_db_update_thread_list_td_ta_thr_iter (ops);
...
}
However, when live debugging, the target beneath, linux-nat.c, does
not implement the to_update_thread_list method. The result is that if
a thread is marked exited (because it can't be deleted right now,
e.g., it was the selected thread), then it won't ever be deleted,
until the process exits or is killed/detached.
A similar thing happens with the remote.c target. Because its
target_update_thread_list implementation skips exited threads when it
walks the current thread list looking for threads that no longer exits
on the target side, using ALL_NON_EXITED_THREADS_SAFE, stale exited
threads are never deleted.
This is not a big deal -- I can't think of any way this might be user
visible, other than gdb's memory growing a tiny bit whenever a thread
gets stuck in exited state. Still, might as well clean things up
properly.
All other targets use prune_threads, so are unaffected.
The fix adds a ALL_THREADS_SAFE macro, that like
ALL_NON_EXITED_THREADS_SAFE, walks the thread list and allows deleting
the iterated thread, and uses that in places that are walking the
thread list in order to delete threads. Actually, after converting
linux-nat.c and remote.c to use this, we find the only other user of
ALL_NON_EXITED_THREADS_SAFE is also walking the list to delete
threads. So we convert that too, and end up deleting
ALL_NON_EXITED_THREADS_SAFE.
Tested on x86_64 Fedora 20, native and gdbserver.
gdb/ChangeLog
2015-04-07 Pedro Alves <palves@redhat.com>
* gdbthread.h (ALL_NON_EXITED_THREADS_SAFE): Rename to ...
(ALL_THREADS_SAFE): ... this, and don't skip exited threads.
(delete_exited_threads): New declaration.
* infrun.c (follow_exec): Use ALL_THREADS_SAFE.
* linux-nat.c (linux_nat_update_thread_list): New function.
(linux_nat_add_target): Install it.
* remote.c (remote_update_thread_list): Use ALL_THREADS_SAFE.
* thread.c (prune_threads): Use ALL_THREADS_SAFE.
(delete_exited_threads): New function.
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r-- | gdb/linux-nat.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 04707dc..6c198cf 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -4030,6 +4030,23 @@ linux_nat_thread_alive (struct target_ops *ops, ptid_t ptid) return linux_thread_alive (ptid); } +/* Implement the to_update_thread_list target method for this + target. */ + +static void +linux_nat_update_thread_list (struct target_ops *ops) +{ + if (linux_supports_traceclone ()) + { + /* With support for clone events, we add/delete threads from the + list as clone/exit events are processed, so just try deleting + exited threads still in the thread list. */ + delete_exited_threads (); + } + else + prune_threads (); +} + static char * linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid) { @@ -4854,6 +4871,7 @@ linux_nat_add_target (struct target_ops *t) t->to_kill = linux_nat_kill; t->to_mourn_inferior = linux_nat_mourn_inferior; t->to_thread_alive = linux_nat_thread_alive; + t->to_update_thread_list = linux_nat_update_thread_list; t->to_pid_to_str = linux_nat_pid_to_str; t->to_thread_name = linux_nat_thread_name; t->to_has_thread_control = tc_schedlock; |