aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbthread.h
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2015-04-07 15:47:22 +0100
committerPedro Alves <palves@redhat.com>2015-04-07 15:47:22 +0100
commit8a06aea71e0aa9099d0ca593dbb58f6e056af4ff (patch)
treea79ed9ea54e264511b552b4903067e3ecb152b71 /gdb/gdbthread.h
parent87070c082fd5c23e9a0e7994ff9ea13f6faecb3e (diff)
downloadfsf-binutils-gdb-8a06aea71e0aa9099d0ca593dbb58f6e056af4ff.zip
fsf-binutils-gdb-8a06aea71e0aa9099d0ca593dbb58f6e056af4ff.tar.gz
fsf-binutils-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/gdbthread.h')
-rw-r--r--gdb/gdbthread.h14
1 files changed, 9 insertions, 5 deletions
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index bb15717..ff7cec2 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -380,13 +380,12 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
for (T = thread_list; T; T = T->next) \
if ((T)->state != THREAD_EXITED)
-/* Like ALL_NON_EXITED_THREADS, but allows deleting the currently
- iterated thread. */
-#define ALL_NON_EXITED_THREADS_SAFE(T, TMP) \
+/* Traverse all threads, including those that have THREAD_EXITED
+ state. Allows deleting the currently iterated thread. */
+#define ALL_THREADS_SAFE(T, TMP) \
for ((T) = thread_list; \
(T) != NULL ? ((TMP) = (T)->next, 1): 0; \
- (T) = (TMP)) \
- if ((T)->state != THREAD_EXITED)
+ (T) = (TMP))
extern int thread_count (void);
@@ -484,6 +483,11 @@ extern void update_thread_list (void);
extern void prune_threads (void);
+/* Delete threads marked THREAD_EXITED. Unlike prune_threads, this
+ does not consult the target about whether the thread is alive right
+ now. */
+extern void delete_exited_threads (void);
+
/* Return true if PC is in the stepping range of THREAD. */
int pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread);