Reapply: List inferiors/threads/pspaces in ascending order
[deliverable/binutils-gdb.git] / gdb / thread.c
index 82c67607bd3b38fdf2c481f1b5e053a54cb7634b..4c2259f7928af6c8a81b075aab54aa7091af115f 100644 (file)
@@ -1,6 +1,6 @@
 /* Multi-process/thread control for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2014 Free Software Foundation, Inc.
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
 
    Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
 
@@ -42,7 +42,7 @@
 #include "cli/cli-decode.h"
 #include "gdb_regex.h"
 #include "cli/cli-utils.h"
-#include "continuations.h"
+#include "thread-fsm.h"
 
 /* Definition of struct thread_info exported to gdbthread.h.  */
 
@@ -62,13 +62,11 @@ static int highest_thread_num;
    spawned new threads we haven't heard of yet.  */
 static int threads_executing;
 
-static void thread_command (char *tidstr, int from_tty);
 static void thread_apply_all_command (char *, int);
 static int thread_alive (struct thread_info *);
 static void info_threads_command (char *, int);
 static void thread_apply_command (char *, int);
 static void restore_current_thread (ptid_t);
-static void prune_threads (void);
 
 /* Data to cleanup thread array.  */
 
@@ -117,6 +115,15 @@ delete_exception_resume_breakpoint (struct thread_info *tp)
     delete_thread_breakpoint (&tp->control.exception_resume_breakpoint);
 }
 
+/* See gdbthread.h.  */
+
+void
+delete_single_step_breakpoints (struct thread_info *tp)
+{
+  if (tp != NULL)
+    delete_thread_breakpoint (&tp->control.single_step_breakpoints);
+}
+
 /* Delete the breakpoint pointed at by BP_P at the next stop, if
    there's one.  */
 
@@ -130,6 +137,40 @@ delete_at_next_stop (struct breakpoint **bp)
     }
 }
 
+/* See gdbthread.h.  */
+
+int
+thread_has_single_step_breakpoints_set (struct thread_info *tp)
+{
+  return tp->control.single_step_breakpoints != NULL;
+}
+
+/* See gdbthread.h.  */
+
+int
+thread_has_single_step_breakpoint_here (struct thread_info *tp,
+                                       struct address_space *aspace,
+                                       CORE_ADDR addr)
+{
+  struct breakpoint *ss_bps = tp->control.single_step_breakpoints;
+
+  return (ss_bps != NULL
+         && breakpoint_has_location_inserted_here (ss_bps, aspace, addr));
+}
+
+/* See gdbthread.h.  */
+
+void
+thread_cancel_execution_command (struct thread_info *thr)
+{
+  if (thr->thread_fsm != NULL)
+    {
+      thread_fsm_clean_up (thr->thread_fsm);
+      thread_fsm_delete (thr->thread_fsm);
+      thr->thread_fsm = NULL;
+    }
+}
+
 static void
 clear_thread_inferior_resources (struct thread_info *tp)
 {
@@ -139,6 +180,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
      be stopped at the moment.  */
   delete_at_next_stop (&tp->control.step_resume_breakpoint);
   delete_at_next_stop (&tp->control.exception_resume_breakpoint);
+  delete_at_next_stop (&tp->control.single_step_breakpoints);
 
   delete_longjmp_breakpoint_at_next_stop (tp->num);
 
@@ -146,19 +188,18 @@ clear_thread_inferior_resources (struct thread_info *tp)
 
   btrace_teardown (tp);
 
-  do_all_intermediate_continuations_thread (tp, 1);
-  do_all_continuations_thread (tp, 1);
+  thread_cancel_execution_command (tp);
 }
 
 static void
 free_thread (struct thread_info *tp)
 {
-  if (tp->private)
+  if (tp->priv)
     {
       if (tp->private_dtor)
-       tp->private_dtor (tp->private);
+       tp->private_dtor (tp->priv);
       else
-       xfree (tp->private);
+       xfree (tp->priv);
     }
 
   xfree (tp->name);
@@ -191,18 +232,26 @@ init_thread_list (void)
 static struct thread_info *
 new_thread (ptid_t ptid)
 {
-  struct thread_info *tp;
-
-  tp = xcalloc (1, sizeof (*tp));
+  struct thread_info *tp = XCNEW (struct thread_info);
 
   tp->ptid = ptid;
   tp->num = ++highest_thread_num;
-  tp->next = thread_list;
-  thread_list = tp;
+
+  if (thread_list == NULL)
+    thread_list = tp;
+  else
+    {
+      struct thread_info *last;
+
+      for (last = thread_list; last->next != NULL; last = last->next)
+       ;
+      last->next = tp;
+    }
 
   /* Nothing to follow yet.  */
   tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
   tp->state = THREAD_STOPPED;
+  tp->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
 
   return tp;
 }
@@ -259,11 +308,11 @@ add_thread_silent (ptid_t ptid)
 }
 
 struct thread_info *
-add_thread_with_info (ptid_t ptid, struct private_thread_info *private)
+add_thread_with_info (ptid_t ptid, struct private_thread_info *priv)
 {
   struct thread_info *result = add_thread_silent (ptid);
 
-  result->private = private;
+  result->priv = priv;
 
   if (print_thread_events)
     printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
@@ -278,6 +327,86 @@ add_thread (ptid_t ptid)
   return add_thread_with_info (ptid, NULL);
 }
 
+/* Add TP to the end of the step-over chain LIST_P.  */
+
+static void
+step_over_chain_enqueue (struct thread_info **list_p, struct thread_info *tp)
+{
+  gdb_assert (tp->step_over_next == NULL);
+  gdb_assert (tp->step_over_prev == NULL);
+
+  if (*list_p == NULL)
+    {
+      *list_p = tp;
+      tp->step_over_prev = tp->step_over_next = tp;
+    }
+  else
+    {
+      struct thread_info *head = *list_p;
+      struct thread_info *tail = head->step_over_prev;
+
+      tp->step_over_prev = tail;
+      tp->step_over_next = head;
+      head->step_over_prev = tp;
+      tail->step_over_next = tp;
+    }
+}
+
+/* Remove TP from step-over chain LIST_P.  */
+
+static void
+step_over_chain_remove (struct thread_info **list_p, struct thread_info *tp)
+{
+  gdb_assert (tp->step_over_next != NULL);
+  gdb_assert (tp->step_over_prev != NULL);
+
+  if (*list_p == tp)
+    {
+      if (tp == tp->step_over_next)
+       *list_p = NULL;
+      else
+       *list_p = tp->step_over_next;
+    }
+
+  tp->step_over_prev->step_over_next = tp->step_over_next;
+  tp->step_over_next->step_over_prev = tp->step_over_prev;
+  tp->step_over_prev = tp->step_over_next = NULL;
+}
+
+/* See gdbthread.h.  */
+
+struct thread_info *
+thread_step_over_chain_next (struct thread_info *tp)
+{
+  struct thread_info *next = tp->step_over_next;
+
+  return (next == step_over_queue_head ? NULL : next);
+}
+
+/* See gdbthread.h.  */
+
+int
+thread_is_in_step_over_chain (struct thread_info *tp)
+{
+  return (tp->step_over_next != NULL);
+}
+
+/* See gdbthread.h.  */
+
+void
+thread_step_over_chain_enqueue (struct thread_info *tp)
+{
+  step_over_chain_enqueue (&step_over_queue_head, tp);
+}
+
+/* See gdbthread.h.  */
+
+void
+thread_step_over_chain_remove (struct thread_info *tp)
+{
+  step_over_chain_remove (&step_over_queue_head, tp);
+}
+
 /* Delete thread PTID.  If SILENT, don't notify the observer of this
    exit.  */
 static void
@@ -294,6 +423,10 @@ delete_thread_1 (ptid_t ptid, int silent)
   if (!tp)
     return;
 
+  /* Dead threads don't need to step-over.  Remove from queue.  */
+  if (tp->step_over_next != NULL)
+    thread_step_over_chain_remove (tp);
+
   /* If this is the current thread, or there's code out there that
      relies on it existing (refcount > 0) we can't delete yet.  Mark
      it as exited, and notify it.  */
@@ -591,19 +724,136 @@ thread_alive (struct thread_info *tp)
   return 1;
 }
 
-static void
+/* See gdbthreads.h.  */
+
+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.  */
+
+static void
+disable_thread_stack_temporaries (void *data)
+{
+  ptid_t *pd = (ptid_t *) data;
+  struct thread_info *tp = find_thread_ptid (*pd);
+
+  if (tp != NULL)
+    {
+      tp->stack_temporaries_enabled = 0;
+      VEC_free (value_ptr, tp->stack_temporaries);
+    }
+
+  xfree (pd);
+}
+
+/* Enable storing stack temporaries for thread with id PTID and return a
+   cleanup which can disable and clear the stack temporaries.  */
+
+struct cleanup *
+enable_thread_stack_temporaries (ptid_t ptid)
+{
+  struct thread_info *tp = find_thread_ptid (ptid);
+  ptid_t  *data;
+  struct cleanup *c;
+
+  gdb_assert (tp != NULL);
+
+  tp->stack_temporaries_enabled = 1;
+  tp->stack_temporaries = NULL;
+  data = XNEW (ptid_t);
+  *data = ptid;
+  c = make_cleanup (disable_thread_stack_temporaries, data);
+
+  return c;
+}
+
+/* Return non-zero value if stack temporaies are enabled for the thread
+   with id PTID.  */
+
+int
+thread_stack_temporaries_enabled_p (ptid_t ptid)
+{
+  struct thread_info *tp = find_thread_ptid (ptid);
+
+  if (tp == NULL)
+    return 0;
+  else
+    return tp->stack_temporaries_enabled;
+}
+
+/* Push V on to the stack temporaries of the thread with id PTID.  */
+
+void
+push_thread_stack_temporary (ptid_t ptid, struct value *v)
+{
+  struct thread_info *tp = find_thread_ptid (ptid);
+
+  gdb_assert (tp != NULL && tp->stack_temporaries_enabled);
+  VEC_safe_push (value_ptr, tp->stack_temporaries, v);
+}
+
+/* Return 1 if VAL is among the stack temporaries of the thread
+   with id PTID.  Return 0 otherwise.  */
+
+int
+value_in_thread_stack_temporaries (struct value *val, ptid_t ptid)
+{
+  struct thread_info *tp = find_thread_ptid (ptid);
+
+  gdb_assert (tp != NULL && tp->stack_temporaries_enabled);
+  if (!VEC_empty (value_ptr, tp->stack_temporaries))
+    {
+      struct value *v;
+      int i;
+
+      for (i = 0; VEC_iterate (value_ptr, tp->stack_temporaries, i, v); i++)
+       if (v == val)
+         return 1;
+    }
+
+  return 0;
+}
+
+/* Return the last of the stack temporaries for thread with id PTID.
+   Return NULL if there are no stack temporaries for the thread.  */
+
+struct value *
+get_last_thread_stack_temporary (ptid_t ptid)
+{
+  struct value *lastval = NULL;
+  struct thread_info *tp = find_thread_ptid (ptid);
+
+  gdb_assert (tp != NULL);
+  if (!VEC_empty (value_ptr, tp->stack_temporaries))
+    lastval = VEC_last (value_ptr, tp->stack_temporaries);
+
+  return lastval;
+}
+
 void
 thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
 {
@@ -613,7 +863,7 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
   /* It can happen that what we knew as the target inferior id
      changes.  E.g, target remote may only discover the remote process
      pid after adding the inferior to GDB's list.  */
-  inf = find_inferior_pid (ptid_get_pid (old_ptid));
+  inf = find_inferior_ptid (old_ptid);
   inf->pid = ptid_get_pid (new_ptid);
 
   tp = find_thread_ptid (old_ptid);
@@ -622,44 +872,84 @@ thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
   observer_notify_thread_ptid_changed (old_ptid, new_ptid);
 }
 
+/* See gdbthread.h.  */
+
+void
+set_resumed (ptid_t ptid, int resumed)
+{
+  struct thread_info *tp;
+  int all = ptid_equal (ptid, minus_one_ptid);
+
+  if (all || ptid_is_pid (ptid))
+    {
+      for (tp = thread_list; tp; tp = tp->next)
+       if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
+         tp->resumed = resumed;
+    }
+  else
+    {
+      tp = find_thread_ptid (ptid);
+      gdb_assert (tp != NULL);
+      tp->resumed = resumed;
+    }
+}
+
+/* Helper for set_running, that marks one thread either running or
+   stopped.  */
+
+static int
+set_running_thread (struct thread_info *tp, int running)
+{
+  int started = 0;
+
+  if (running && tp->state == THREAD_STOPPED)
+    started = 1;
+  tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
+
+  if (!running)
+    {
+      /* If the thread is now marked stopped, remove it from
+        the step-over queue, so that we don't try to resume
+        it until the user wants it to.  */
+      if (tp->step_over_next != NULL)
+       thread_step_over_chain_remove (tp);
+    }
+
+  return started;
+}
+
 void
 set_running (ptid_t ptid, int running)
 {
   struct thread_info *tp;
   int all = ptid_equal (ptid, minus_one_ptid);
+  int any_started = 0;
 
   /* We try not to notify the observer if no thread has actually changed 
      the running state -- merely to reduce the number of messages to 
      frontend.  Frontend is supposed to handle multiple *running just fine.  */
   if (all || ptid_is_pid (ptid))
     {
-      int any_started = 0;
-
       for (tp = thread_list; tp; tp = tp->next)
        if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
          {
            if (tp->state == THREAD_EXITED)
              continue;
-           if (running && tp->state == THREAD_STOPPED)
+
+           if (set_running_thread (tp, running))
              any_started = 1;
-           tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
          }
-      if (any_started)
-       observer_notify_target_resumed (ptid);
     }
   else
     {
-      int started = 0;
-
       tp = find_thread_ptid (ptid);
-      gdb_assert (tp);
+      gdb_assert (tp != NULL);
       gdb_assert (tp->state != THREAD_EXITED);
-      if (running && tp->state == THREAD_STOPPED)
-       started = 1;
-      tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
-      if (started)
-       observer_notify_target_resumed (ptid);
+      if (set_running_thread (tp, running))
+       any_started = 1;
     }
+  if (any_started)
+    observer_notify_target_resumed (ptid);
 }
 
 static int
@@ -778,9 +1068,8 @@ finish_thread_state (ptid_t ptid)
            continue;
          if (all || ptid_get_pid (ptid) == ptid_get_pid (tp->ptid))
            {
-             if (tp->executing && tp->state == THREAD_STOPPED)
+             if (set_running_thread (tp, tp->executing))
                any_started = 1;
-             tp->state = tp->executing ? THREAD_RUNNING : THREAD_STOPPED;
            }
        }
     }
@@ -790,9 +1079,8 @@ finish_thread_state (ptid_t ptid)
       gdb_assert (tp);
       if (tp->state != THREAD_EXITED)
        {
-         if (tp->executing && tp->state == THREAD_STOPPED)
+         if (set_running_thread (tp, tp->executing))
            any_started = 1;
-         tp->state = tp->executing ? THREAD_RUNNING : THREAD_STOPPED;
        }
     }
 
@@ -803,7 +1091,7 @@ finish_thread_state (ptid_t ptid)
 void
 finish_thread_state_cleanup (void *arg)
 {
-  ptid_t *ptid_p = arg;
+  ptid_t *ptid_p = (ptid_t *) arg;
 
   gdb_assert (arg);
 
@@ -834,7 +1122,7 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
   struct thread_info *tp;
   ptid_t current_ptid;
   struct cleanup *old_chain;
-  char *extra_info, *name, *target_id;
+  const char *extra_info, *name, *target_id;
   int current_thread = -1;
 
   update_thread_list ();
@@ -1033,6 +1321,22 @@ info_threads_command (char *arg, int from_tty)
   print_thread_info (current_uiout, arg, -1);
 }
 
+/* See gdbthread.h.  */
+
+void
+switch_to_thread_no_regs (struct thread_info *thread)
+{
+  struct inferior *inf;
+
+  inf = find_inferior_ptid (thread->ptid);
+  gdb_assert (inf != NULL);
+  set_current_program_space (inf->pspace);
+  set_current_inferior (inf);
+
+  inferior_ptid = thread->ptid;
+  stop_pc = ~(CORE_ADDR) 0;
+}
+
 /* Switch from one thread to another.  */
 
 void
@@ -1045,7 +1349,7 @@ switch_to_thread (ptid_t ptid)
     {
       struct inferior *inf;
 
-      inf = find_inferior_pid (ptid_get_pid (ptid));
+      inf = find_inferior_ptid (ptid);
       gdb_assert (inf != NULL);
       set_current_program_space (inf->pspace);
       set_current_inferior (inf);
@@ -1133,8 +1437,16 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
     }
 }
 
+/* Data used by the cleanup installed by
+   'make_cleanup_restore_current_thread'.  */
+
 struct current_thread_cleanup
 {
+  /* Next in list of currently installed 'struct
+     current_thread_cleanup' cleanups.  See
+     'current_thread_cleanup_chain' below.  */
+  struct current_thread_cleanup *next;
+
   ptid_t inferior_ptid;
   struct frame_id selected_frame_id;
   int selected_frame_level;
@@ -1143,11 +1455,34 @@ struct current_thread_cleanup
   int was_removable;
 };
 
+/* A chain of currently installed 'struct current_thread_cleanup'
+   cleanups.  Restoring the previously selected thread looks up the
+   old thread in the thread list by ptid.  If the thread changes ptid,
+   we need to update the cleanup's thread structure so the look up
+   succeeds.  */
+static struct current_thread_cleanup *current_thread_cleanup_chain;
+
+/* A thread_ptid_changed observer.  Update all currently installed
+   current_thread_cleanup cleanups that want to switch back to
+   OLD_PTID to switch back to NEW_PTID instead.  */
+
+static void
+restore_current_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
+{
+  struct current_thread_cleanup *it;
+
+  for (it = current_thread_cleanup_chain; it != NULL; it = it->next)
+    {
+      if (ptid_equal (it->inferior_ptid, old_ptid))
+       it->inferior_ptid = new_ptid;
+    }
+}
+
 static void
 do_restore_current_thread_cleanup (void *arg)
 {
   struct thread_info *tp;
-  struct current_thread_cleanup *old = arg;
+  struct current_thread_cleanup *old = (struct current_thread_cleanup *) arg;
 
   tp = find_thread_ptid (old->inferior_ptid);
 
@@ -1156,7 +1491,7 @@ do_restore_current_thread_cleanup (void *arg)
      then don't revert back to it, but instead simply drop back to no
      thread selected.  */
   if (tp
-      && find_inferior_pid (ptid_get_pid (tp->ptid)) != NULL)
+      && find_inferior_ptid (tp->ptid) != NULL)
     restore_current_thread (old->inferior_ptid);
   else
     {
@@ -1179,10 +1514,12 @@ do_restore_current_thread_cleanup (void *arg)
 static void
 restore_current_thread_cleanup_dtor (void *arg)
 {
-  struct current_thread_cleanup *old = arg;
+  struct current_thread_cleanup *old = (struct current_thread_cleanup *) arg;
   struct thread_info *tp;
   struct inferior *inf;
 
+  current_thread_cleanup_chain = current_thread_cleanup_chain->next;
+
   tp = find_thread_ptid (old->inferior_ptid);
   if (tp)
     tp->refcount--;
@@ -1198,7 +1535,8 @@ static void
 set_thread_refcount (void *data)
 {
   int k;
-  struct thread_array_cleanup *ta_cleanup = data;
+  struct thread_array_cleanup *ta_cleanup
+    = (struct thread_array_cleanup *) data;
 
   for (k = 0; k != ta_cleanup->count; k++)
     ta_cleanup->tp_array[k]->refcount--;
@@ -1209,13 +1547,15 @@ make_cleanup_restore_current_thread (void)
 {
   struct thread_info *tp;
   struct frame_info *frame;
-  struct current_thread_cleanup *old;
+  struct current_thread_cleanup *old = XNEW (struct current_thread_cleanup);
 
-  old = xmalloc (sizeof (struct current_thread_cleanup));
   old->inferior_ptid = inferior_ptid;
   old->inf_id = current_inferior ()->num;
   old->was_removable = current_inferior ()->removable;
 
+  old->next = current_thread_cleanup_chain;
+  current_thread_cleanup_chain = old;
+
   if (!ptid_equal (inferior_ptid, null_ptid))
     {
       old->was_stopped = is_stopped (inferior_ptid);
@@ -1248,6 +1588,26 @@ make_cleanup_restore_current_thread (void)
                            restore_current_thread_cleanup_dtor);
 }
 
+/* If non-zero tp_array_compar should sort in ascending order, otherwise in
+   descending order.  */
+
+static int tp_array_compar_ascending;
+
+/* Sort an array for struct thread_info pointers by their NUM, order is
+   determined by TP_ARRAY_COMPAR_ASCENDING.  */
+
+static int
+tp_array_compar (const void *ap_voidp, const void *bp_voidp)
+{
+  const struct thread_info *const *ap
+    = (const struct thread_info * const*) ap_voidp;
+  const struct thread_info *const *bp
+    = (const struct thread_info * const*) bp_voidp;
+
+  return ((((*ap)->num > (*bp)->num) - ((*ap)->num < (*bp)->num))
+         * (tp_array_compar_ascending ? +1 : -1));
+}
+
 /* Apply a GDB command to a list of threads.  List syntax is a whitespace
    seperated list of numbers, or ranges, or the keyword `all'.  Ranges consist
    of two numbers seperated by a hyphen.  Examples:
@@ -1264,6 +1624,14 @@ thread_apply_all_command (char *cmd, int from_tty)
   int tc;
   struct thread_array_cleanup ta_cleanup;
 
+  tp_array_compar_ascending = 0;
+  if (cmd != NULL
+      && check_for_argument (&cmd, "-ascending", strlen ("-ascending")))
+    {
+      cmd = skip_spaces (cmd);
+      tp_array_compar_ascending = 1;
+    }
+
   if (cmd == NULL || *cmd == '\000')
     error (_("Please specify a command following the thread ID list"));
 
@@ -1275,9 +1643,10 @@ thread_apply_all_command (char *cmd, int from_tty)
      execute_command.  */
   saved_cmd = xstrdup (cmd);
   make_cleanup (xfree, saved_cmd);
-  tc = thread_count ();
 
-  if (tc)
+  /* Note this includes exited threads.  */
+  tc = thread_count ();
+  if (tc != 0)
     {
       struct thread_info **tp_array;
       struct thread_info *tp;
@@ -1285,10 +1654,8 @@ thread_apply_all_command (char *cmd, int from_tty)
 
       /* Save a copy of the thread_list in case we execute detach
          command.  */
-      tp_array = xmalloc (sizeof (struct thread_info *) * tc);
+      tp_array = XNEWVEC (struct thread_info *, tc);
       make_cleanup (xfree, tp_array);
-      ta_cleanup.tp_array = tp_array;
-      ta_cleanup.count = tc;
 
       ALL_NON_EXITED_THREADS (tp)
         {
@@ -1296,7 +1663,15 @@ thread_apply_all_command (char *cmd, int from_tty)
           tp->refcount++;
           i++;
         }
+      /* Because we skipped exited threads, we may end up with fewer
+        threads in the array than the total count of threads.  */
+      gdb_assert (i <= tc);
+
+      if (i != 0)
+       qsort (tp_array, i, sizeof (*tp_array), tp_array_compar);
 
+      ta_cleanup.tp_array = tp_array;
+      ta_cleanup.count = i;
       make_cleanup (set_thread_refcount, &ta_cleanup);
 
       for (k = 0; k != i; k++)
@@ -1372,7 +1747,7 @@ thread_apply_command (char *tidlist, int from_tty)
 /* Switch to the specified thread.  Will dispatch off to thread_apply_command
    if prefix of arg is `apply'.  */
 
-static void
+void
 thread_command (char *tidstr, int from_tty)
 {
   if (!tidstr)
@@ -1422,7 +1797,7 @@ static void
 thread_find_command (char *arg, int from_tty)
 {
   struct thread_info *tp;
-  char *tmp;
+  const char *tmp;
   unsigned long match = 0;
 
   if (arg == NULL || *arg == '\0')
@@ -1487,7 +1862,7 @@ do_captured_thread_select (struct ui_out *uiout, void *tidstr)
   int num;
   struct thread_info *tp;
 
-  num = value_as_long (parse_and_eval (tidstr));
+  num = value_as_long (parse_and_eval ((const char *) tidstr));
 
   tp = find_thread_id (num);
 
@@ -1555,8 +1930,7 @@ update_threads_executing (void)
 void
 update_thread_list (void)
 {
-  prune_threads ();
-  target_find_new_threads ();
+  target_update_thread_list ();
   update_threads_executing ();
 }
 
@@ -1606,7 +1980,14 @@ The new thread ID must be currently known."),
                  &thread_apply_list, "thread apply ", 1, &thread_cmd_list);
 
   add_cmd ("all", class_run, thread_apply_all_command,
-          _("Apply a command to all threads."), &thread_apply_list);
+          _("\
+Apply a command to all threads.\n\
+\n\
+Usage: thread apply all [-ascending] <command>\n\
+-ascending: Call <command> for all threads in ascending order.\n\
+            The default is descending order.\
+"),
+          &thread_apply_list);
 
   add_cmd ("name", class_run, thread_name_command,
           _("Set the current thread's name.\n\
@@ -1619,8 +2000,7 @@ Usage: thread find REGEXP\n\
 Will display thread ids whose name, target ID, or extra info matches REGEXP."),
           &thread_cmd_list);
 
-  if (!xdb_commands)
-    add_com_alias ("t", "thread", class_run, 1);
+  add_com_alias ("t", "thread", class_run, 1);
 
   add_setshow_boolean_cmd ("thread-events", no_class,
          &print_thread_events, _("\
@@ -1631,4 +2011,6 @@ Show printing of thread events (such as thread start and exit)."), NULL,
          &setprintlist, &showprintlist);
 
   create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
+
+  observer_attach_thread_ptid_changed (restore_current_thread_ptid_changed);
 }
This page took 0.052308 seconds and 4 git commands to generate.