+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.
+
2015-04-07 Pedro Alves <pedro@codesourcery.com>
* infrun.c (resume) <displaced stepping debug output>: Get the
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);
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);
them. Deleting them now rather than at the next user-visible
stop provides a nicer sequence of events for user and MI
notifications. */
- ALL_NON_EXITED_THREADS_SAFE (th, tmp)
+ ALL_THREADS_SAFE (th, tmp)
if (ptid_get_pid (th->ptid) == pid && !ptid_equal (th->ptid, ptid))
delete_thread (th->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)
{
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;
/* CONTEXT now holds the current thread list on the remote
target end. Delete GDB-side threads no longer found on the
target. */
- ALL_NON_EXITED_THREADS_SAFE (tp, tmp)
+ ALL_THREADS_SAFE (tp, tmp)
{
for (i = 0;
VEC_iterate (thread_item_t, context.items, i, item);
void
prune_threads (void)
{
- struct thread_info *tp, *next;
+ struct thread_info *tp, *tmp;
- for (tp = thread_list; tp; tp = next)
+ ALL_THREADS_SAFE (tp, tmp)
{
- next = tp->next;
if (!thread_alive (tp))
delete_thread (tp->ptid);
}
}
+/* See gdbthreads.h. */
+
+void
+delete_exited_threads (void)
+{
+ struct thread_info *tp, *tmp;
+
+ ALL_THREADS_SAFE (tp, tmp)
+ {
+ if (tp->state == THREAD_EXITED)
+ delete_thread (tp->ptid);
+ }
+}
+
/* Disable storing stack temporaries for the thread whose id is
stored in DATA. */