Add $_gthread convenience variable
[deliverable/binutils-gdb.git] / gdb / thread.c
index 7e8eec59b6043f405ec9b6dbc851a8307a5beb89..cdd2a2f2655bb85494b81ed59d2ec2c52f227ccf 100644 (file)
@@ -1,7 +1,6 @@
 /* Multi-process/thread control for GDB, the GNU debugger.
 
-   Copyright (C) 1986-1988, 1993-2004, 2007-2012 Free Software
-   Foundation, Inc.
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
 
    Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
 
 #include "value.h"
 #include "target.h"
 #include "gdbthread.h"
-#include "exceptions.h"
 #include "command.h"
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "gdb.h"
-#include "gdb_string.h"
+#include "btrace.h"
 
 #include <ctype.h>
 #include <sys/types.h>
@@ -44,7 +42,8 @@
 #include "cli/cli-decode.h"
 #include "gdb_regex.h"
 #include "cli/cli-utils.h"
-#include "continuations.h"
+#include "thread-fsm.h"
+#include "tid-parse.h"
 
 /* Definition of struct thread_info exported to gdbthread.h.  */
 
@@ -57,13 +56,31 @@ void _initialize_thread (void);
 struct thread_info *thread_list = NULL;
 static int highest_thread_num;
 
-static void thread_command (char *tidstr, int from_tty);
+/* True if any thread is, or may be executing.  We need to track this
+   separately because until we fully sync the thread list, we won't
+   know whether the target is fully stopped, even if we see stop
+   events for all known threads, because any of those threads may have
+   spawned new threads we haven't heard of yet.  */
+static int threads_executing;
+
 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.  */
+
+struct thread_array_cleanup
+{
+  /* Array of thread pointers used to set
+     reference count.  */
+  struct thread_info **tp_array;
+
+  /* Thread count in the array.  */
+  int count;
+};
+
 
 struct thread_info*
 inferior_thread (void)
@@ -73,23 +90,85 @@ inferior_thread (void)
   return tp;
 }
 
+/* Delete the breakpoint pointed at by BP_P, if there's one.  */
+
+static void
+delete_thread_breakpoint (struct breakpoint **bp_p)
+{
+  if (*bp_p != NULL)
+    {
+      delete_breakpoint (*bp_p);
+      *bp_p = NULL;
+    }
+}
+
 void
 delete_step_resume_breakpoint (struct thread_info *tp)
 {
-  if (tp && tp->control.step_resume_breakpoint)
+  if (tp != NULL)
+    delete_thread_breakpoint (&tp->control.step_resume_breakpoint);
+}
+
+void
+delete_exception_resume_breakpoint (struct thread_info *tp)
+{
+  if (tp != NULL)
+    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.  */
+
+static void
+delete_at_next_stop (struct breakpoint **bp)
+{
+  if (*bp != NULL)
     {
-      delete_breakpoint (tp->control.step_resume_breakpoint);
-      tp->control.step_resume_breakpoint = NULL;
+      (*bp)->disposition = disp_del_at_next_stop;
+      *bp = NULL;
     }
 }
 
+/* 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
-delete_exception_resume_breakpoint (struct thread_info *tp)
+thread_cancel_execution_command (struct thread_info *thr)
 {
-  if (tp && tp->control.exception_resume_breakpoint)
+  if (thr->thread_fsm != NULL)
     {
-      delete_breakpoint (tp->control.exception_resume_breakpoint);
-      tp->control.exception_resume_breakpoint = NULL;
+      thread_fsm_clean_up (thr->thread_fsm);
+      thread_fsm_delete (thr->thread_fsm);
+      thr->thread_fsm = NULL;
     }
 }
 
@@ -100,36 +179,28 @@ clear_thread_inferior_resources (struct thread_info *tp)
      but not any user-specified thread-specific breakpoints.  We can not
      delete the breakpoint straight-off, because the inferior might not
      be stopped at the moment.  */
-  if (tp->control.step_resume_breakpoint)
-    {
-      tp->control.step_resume_breakpoint->disposition = disp_del_at_next_stop;
-      tp->control.step_resume_breakpoint = NULL;
-    }
+  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);
 
-  if (tp->control.exception_resume_breakpoint)
-    {
-      tp->control.exception_resume_breakpoint->disposition
-       = disp_del_at_next_stop;
-      tp->control.exception_resume_breakpoint = NULL;
-    }
-
-  delete_longjmp_breakpoint_at_next_stop (tp->num);
+  delete_longjmp_breakpoint_at_next_stop (tp->global_num);
 
   bpstat_clear (&tp->control.stop_bpstat);
 
-  do_all_intermediate_continuations_thread (tp, 1);
-  do_all_continuations_thread (tp, 1);
+  btrace_teardown (tp);
+
+  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);
@@ -153,26 +224,41 @@ init_thread_list (void)
     }
 
   thread_list = NULL;
+  threads_executing = 0;
 }
 
-/* Allocate a new thread with target id PTID and add it to the thread
-   list.  */
+/* Allocate a new thread of inferior INF with target id PTID and add
+   it to the thread list.  */
 
 static struct thread_info *
-new_thread (ptid_t ptid)
+new_thread (struct inferior *inf, ptid_t ptid)
 {
   struct thread_info *tp;
 
-  tp = xcalloc (1, sizeof (*tp));
+  gdb_assert (inf != NULL);
+
+  tp = XCNEW (struct thread_info);
 
   tp->ptid = ptid;
-  tp->num = ++highest_thread_num;
-  tp->next = thread_list;
-  thread_list = tp;
+  tp->global_num = ++highest_thread_num;
+  tp->inf = inf;
+  tp->per_inf_num = ++inf->highest_thread_num;
+
+  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;
 }
@@ -181,6 +267,8 @@ struct thread_info *
 add_thread_silent (ptid_t ptid)
 {
   struct thread_info *tp;
+  struct inferior *inf = find_inferior_ptid (ptid);
+  gdb_assert (inf != NULL);
 
   tp = find_thread_ptid (ptid);
   if (tp)
@@ -198,7 +286,7 @@ add_thread_silent (ptid_t ptid)
 
       if (ptid_equal (inferior_ptid, ptid))
        {
-         tp = new_thread (null_ptid);
+         tp = new_thread (inf, null_ptid);
 
          /* Make switch_to_thread not read from the thread.  */
          tp->state = THREAD_EXITED;
@@ -222,18 +310,18 @@ add_thread_silent (ptid_t ptid)
        delete_thread (ptid);
     }
 
-  tp = new_thread (ptid);
+  tp = new_thread (inf, ptid);
   observer_notify_new_thread (tp);
 
   return tp;
 }
 
 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));
@@ -248,6 +336,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
@@ -264,6 +432,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.  */
@@ -318,12 +490,24 @@ delete_thread_silent (ptid_t ptid)
 }
 
 struct thread_info *
-find_thread_id (int num)
+find_thread_global_id (int global_id)
+{
+  struct thread_info *tp;
+
+  for (tp = thread_list; tp; tp = tp->next)
+    if (tp->global_num == global_id)
+      return tp;
+
+  return NULL;
+}
+
+static struct thread_info *
+find_thread_id (struct inferior *inf, int thr_num)
 {
   struct thread_info *tp;
 
   for (tp = thread_list; tp; tp = tp->next)
-    if (tp->num == num)
+    if (tp->inf == inf && tp->per_inf_num == thr_num)
       return tp;
 
   return NULL;
@@ -385,38 +569,38 @@ thread_count (void)
 }
 
 int
-valid_thread_id (int num)
+valid_global_thread_id (int global_id)
 {
   struct thread_info *tp;
 
   for (tp = thread_list; tp; tp = tp->next)
-    if (tp->num == num)
+    if (tp->global_num == global_id)
       return 1;
 
   return 0;
 }
 
 int
-pid_to_thread_id (ptid_t ptid)
+ptid_to_global_thread_id (ptid_t ptid)
 {
   struct thread_info *tp;
 
   for (tp = thread_list; tp; tp = tp->next)
     if (ptid_equal (tp->ptid, ptid))
-      return tp->num;
+      return tp->global_num;
 
   return 0;
 }
 
 ptid_t
-thread_id_to_pid (int num)
+global_thread_id_to_ptid (int global_id)
 {
-  struct thread_info *thread = find_thread_id (num);
+  struct thread_info *thread = find_thread_global_id (global_id);
 
   if (thread)
     return thread->ptid;
   else
-    return pid_to_ptid (-1);
+    return minus_one_ptid;
 }
 
 int
@@ -441,7 +625,7 @@ first_thread_of_process (int pid)
 
   for (tp = thread_list; tp; tp = tp->next)
     if (pid == -1 || ptid_get_pid (tp->ptid) == pid)
-      if (ret == NULL || tp->num < ret->num)
+      if (ret == NULL || tp->global_num < ret->global_num)
        ret = tp;
 
   return ret;
@@ -452,7 +636,13 @@ any_thread_of_process (int pid)
 {
   struct thread_info *tp;
 
-  for (tp = thread_list; tp; tp = tp->next)
+  gdb_assert (pid != 0);
+
+  /* Prefer the current thread.  */
+  if (ptid_get_pid (inferior_ptid) == pid)
+    return inferior_thread ();
+
+  ALL_NON_EXITED_THREADS (tp)
     if (ptid_get_pid (tp->ptid) == pid)
       return tp;
 
@@ -462,18 +652,40 @@ any_thread_of_process (int pid)
 struct thread_info *
 any_live_thread_of_process (int pid)
 {
+  struct thread_info *curr_tp = NULL;
   struct thread_info *tp;
   struct thread_info *tp_executing = NULL;
 
-  for (tp = thread_list; tp; tp = tp->next)
-    if (tp->state != THREAD_EXITED && ptid_get_pid (tp->ptid) == pid)
+  gdb_assert (pid != 0);
+
+  /* Prefer the current thread if it's not executing.  */
+  if (ptid_get_pid (inferior_ptid) == pid)
+    {
+      /* If the current thread is dead, forget it.  If it's not
+        executing, use it.  Otherwise, still choose it (below), but
+        only if no other non-executing thread is found.  */
+      curr_tp = inferior_thread ();
+      if (curr_tp->state == THREAD_EXITED)
+       curr_tp = NULL;
+      else if (!curr_tp->executing)
+       return curr_tp;
+    }
+
+  ALL_NON_EXITED_THREADS (tp)
+    if (ptid_get_pid (tp->ptid) == pid)
       {
-       if (tp->executing)
-         tp_executing = tp;
-       else
+       if (!tp->executing)
          return tp;
+
+       tp_executing = tp;
       }
 
+  /* If both the current thread and all live threads are executing,
+     prefer the current thread.  */
+  if (curr_tp != NULL)
+    return curr_tp;
+
+  /* Otherwise, just return an executing thread, if any.  */
   return tp_executing;
 }
 
@@ -497,10 +709,10 @@ do_captured_list_thread_ids (struct ui_out *uiout, void *arg)
        continue;
 
       if (ptid_equal (tp->ptid, inferior_ptid))
-       current_thread = tp->num;
+       current_thread = tp->global_num;
 
       num++;
-      ui_out_field_int (uiout, "thread-id", tp->num);
+      ui_out_field_int (uiout, "thread-id", tp->global_num);
     }
 
   do_cleanups (cleanup_chain);
@@ -533,19 +745,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)
 {
@@ -555,7 +884,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);
@@ -564,44 +893,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
@@ -632,18 +1001,6 @@ is_running (ptid_t ptid)
   return is_thread_state (ptid, THREAD_RUNNING);
 }
 
-int
-any_running (void)
-{
-  struct thread_info *tp;
-
-  for (tp = thread_list; tp; tp = tp->next)
-    if (tp->state == THREAD_RUNNING)
-      return 1;
-
-  return 0;
-}
-
 int
 is_executing (ptid_t ptid)
 {
@@ -672,6 +1029,22 @@ set_executing (ptid_t ptid, int executing)
       gdb_assert (tp);
       tp->executing = executing;
     }
+
+  /* It only takes one running thread to spawn more threads.*/
+  if (executing)
+    threads_executing = 1;
+  /* Only clear the flag if the caller is telling us everything is
+     stopped.  */
+  else if (ptid_equal (minus_one_ptid, ptid))
+    threads_executing = 0;
+}
+
+/* See gdbthread.h.  */
+
+int
+threads_are_executing (void)
+{
+  return threads_executing;
 }
 
 void
@@ -716,9 +1089,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;
            }
        }
     }
@@ -728,9 +1100,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;
        }
     }
 
@@ -741,32 +1112,98 @@ 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);
 
   finish_thread_state (*ptid_p);
 }
 
-/* Prints the list of threads and their details on UIOUT.
-   This is a version of 'info_threads_command' suitable for
-   use from MI.
-   If REQUESTED_THREAD is not -1, it's the GDB id of the thread
-   that should be printed.  Otherwise, all threads are
-   printed.
-   If PID is not -1, only print threads from the process PID.
-   Otherwise, threads from all attached PIDs are printed.
-   If both REQUESTED_THREAD and PID are not -1, then the thread
-   is printed if it belongs to the specified process.  Otherwise,
-   an error is raised.  */
+/* See gdbthread.h.  */
+
 void
-print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
+validate_registers_access (void)
+{
+  /* No selected thread, no registers.  */
+  if (ptid_equal (inferior_ptid, null_ptid))
+    error (_("No thread selected."));
+
+  /* Don't try to read from a dead thread.  */
+  if (is_exited (inferior_ptid))
+    error (_("The current thread has terminated"));
+
+  /* ... or from a spinning thread.  FIXME: This isn't actually fully
+     correct.  It'll allow an user-requested access (e.g., "print $pc"
+     at the prompt) when a thread is not executing for some internal
+     reason, but is marked running from the user's perspective.  E.g.,
+     the thread is waiting for its turn in the step-over queue.  */
+  if (is_executing (inferior_ptid))
+    error (_("Selected thread is running."));
+}
+
+int
+pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread)
+{
+  return (pc >= thread->control.step_range_start
+         && pc < thread->control.step_range_end);
+}
+
+/* Helper for print_thread_info.  Returns true if THR should be
+   printed.  If REQUESTED_THREADS, a list of GDB ids/ranges, is not
+   NULL, only print THR if its ID is included in the list.  GLOBAL_IDS
+   is true if REQUESTED_THREADS is list of global IDs, false if a list
+   of per-inferior thread ids.  If PID is not -1, only print THR if it
+   is a thread from the process PID.  Otherwise, threads from all
+   attached PIDs are printed.  If both REQUESTED_THREADS is not NULL
+   and PID is not -1, then the thread is printed if it belongs to the
+   specified process.  Otherwise, an error is raised.  */
+
+static int
+should_print_thread (const char *requested_threads, int default_inf_num,
+                    int global_ids, int pid, struct thread_info *thr)
+{
+  if (requested_threads != NULL && *requested_threads != '\0')
+    {
+      int in_list;
+
+      if (global_ids)
+       in_list = number_is_in_list (requested_threads, thr->global_num);
+      else
+       in_list = tid_is_in_list (requested_threads, default_inf_num,
+                                 thr->inf->num, thr->per_inf_num);
+      if (!in_list)
+       return 0;
+    }
+
+  if (pid != -1 && ptid_get_pid (thr->ptid) != pid)
+    {
+      if (requested_threads != NULL && *requested_threads != '\0')
+       error (_("Requested thread not found in requested process"));
+      return 0;
+    }
+
+  if (thr->state == THREAD_EXITED)
+    return 0;
+
+  return 1;
+}
+
+/* Like print_thread_info, but in addition, GLOBAL_IDS indicates
+   whether REQUESTED_THREADS is a list of global or per-inferior
+   thread ids.  */
+
+static void
+print_thread_info_1 (struct ui_out *uiout, char *requested_threads,
+                    int global_ids, int pid,
+                    int show_global_ids)
 {
   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;
+  struct inferior *inf;
+  int default_inf_num = current_inferior ()->num;
 
   update_thread_list ();
   current_ptid = inferior_ptid;
@@ -785,13 +1222,8 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
 
       for (tp = thread_list; tp; tp = tp->next)
        {
-         if (!number_is_in_list (requested_threads, tp->num))
-           continue;
-
-         if (pid != -1 && PIDGET (tp->ptid) != pid)
-           continue;
-
-         if (tp->state == THREAD_EXITED)
+         if (!should_print_thread (requested_threads, default_inf_num,
+                                   global_ids, pid, tp))
            continue;
 
          ++n_threads;
@@ -808,34 +1240,32 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
          return;
        }
 
-      make_cleanup_ui_out_table_begin_end (uiout, 4, n_threads, "threads");
+      if (show_global_ids || ui_out_is_mi_like_p (uiout))
+       make_cleanup_ui_out_table_begin_end (uiout, 5, n_threads, "threads");
+      else
+       make_cleanup_ui_out_table_begin_end (uiout, 4, n_threads, "threads");
 
       ui_out_table_header (uiout, 1, ui_left, "current", "");
-      ui_out_table_header (uiout, 4, ui_left, "id", "Id");
+
+      if (!ui_out_is_mi_like_p (uiout))
+       ui_out_table_header (uiout, 4, ui_left, "id-in-tg", "Id");
+      if (show_global_ids || ui_out_is_mi_like_p (uiout))
+       ui_out_table_header (uiout, 4, ui_left, "id", "GId");
       ui_out_table_header (uiout, 17, ui_left, "target-id", "Target Id");
       ui_out_table_header (uiout, 1, ui_left, "frame", "Frame");
       ui_out_table_body (uiout);
     }
 
-  for (tp = thread_list; tp; tp = tp->next)
+  ALL_THREADS_BY_INFERIOR (inf, tp)
     {
       struct cleanup *chain2;
       int core;
 
-      if (!number_is_in_list (requested_threads, tp->num))
-       continue;
-
-      if (pid != -1 && PIDGET (tp->ptid) != pid)
-       {
-         if (requested_threads != NULL && *requested_threads != '\0')
-           error (_("Requested thread not found in requested process"));
-         continue;
-       }
-
       if (ptid_equal (tp->ptid, current_ptid))
-       current_thread = tp->num;
+       current_thread = tp->global_num;
 
-      if (tp->state == THREAD_EXITED)
+      if (!should_print_thread (requested_threads, default_inf_num,
+                               global_ids, pid, tp))
        continue;
 
       chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
@@ -856,7 +1286,11 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
            ui_out_field_skip (uiout, "current");
        }
 
-      ui_out_field_int (uiout, "id", tp->num);
+      if (!ui_out_is_mi_like_p (uiout))
+       ui_out_field_string (uiout, "id-in-tg", print_thread_id (tp));
+
+      if (show_global_ids || ui_out_is_mi_like_p (uiout))
+       ui_out_field_int (uiout, "id", tp->global_num);
 
       /* For the CLI, we stuff everything into the target-id field.
         This is a gross hack to make the output come out looking
@@ -907,7 +1341,7 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
          print_stack_frame (get_selected_frame (NULL),
                             /* For MI output, print frame level.  */
                             ui_out_is_mi_like_p (uiout),
-                            LOCATION);
+                            LOCATION, 0);
        }
 
       if (ui_out_is_mi_like_p (uiout))
@@ -932,27 +1366,35 @@ print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
 
   if (pid == -1 && requested_threads == NULL)
     {
-      gdb_assert (current_thread != -1
-                 || !thread_list
-                 || ptid_equal (inferior_ptid, null_ptid));
-      if (current_thread != -1 && ui_out_is_mi_like_p (uiout))
-       ui_out_field_int (uiout, "current-thread-id", current_thread);
+      if (ui_out_is_mi_like_p (uiout)
+         && !ptid_equal (inferior_ptid, null_ptid))
+       {
+         int num = ptid_to_global_thread_id (inferior_ptid);
 
-      if (current_thread != -1 && is_exited (current_ptid))
+         gdb_assert (num != 0);
+         ui_out_field_int (uiout, "current-thread-id", num);
+       }
+
+      if (!ptid_equal (inferior_ptid, null_ptid) && is_exited (inferior_ptid))
        ui_out_message (uiout, 0, "\n\
-The current thread <Thread ID %d> has terminated.  See `help thread'.\n",
-                       current_thread);
-      else if (thread_list
-              && current_thread == -1
-              && ptid_equal (current_ptid, null_ptid))
+The current thread <Thread ID %s> has terminated.  See `help thread'.\n",
+                       print_thread_id (inferior_thread ()));
+      else if (thread_list != NULL
+              && ptid_equal (inferior_ptid, null_ptid))
        ui_out_message (uiout, 0, "\n\
 No selected thread.  See `help thread'.\n");
     }
 }
 
-/* Print information about currently known threads 
+/* See gdbthread.h.  */
+
+void
+print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
+{
+  print_thread_info_1 (uiout, requested_threads, 1, pid, 0);
+}
 
-   Optional ARG is a thread id, or list of thread ids.
+/* Implementation of the "info threads" command.
 
    Note: this has the drawback that it _really_ switches
          threads, which frees the frame cache.  A no-side
@@ -961,7 +1403,32 @@ No selected thread.  See `help thread'.\n");
 static void
 info_threads_command (char *arg, int from_tty)
 {
-  print_thread_info (current_uiout, arg, -1);
+  int show_global_ids = 0;
+
+  if (arg != NULL
+      && check_for_argument (&arg, "-gid", sizeof ("-gid") - 1))
+    {
+      arg = skip_spaces (arg);
+      show_global_ids = 1;
+    }
+
+  print_thread_info_1 (current_uiout, arg, 0, -1, show_global_ids);
+}
+
+/* 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.  */
@@ -976,7 +1443,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);
@@ -1055,17 +1522,25 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
   if (frame_level > 0 && !ui_out_is_mi_like_p (current_uiout))
     {
       warning (_("Couldn't restore frame #%d in "
-                "current thread, at reparsed frame #0\n"),
+                "current thread.  Bottom (innermost) frame selected:"),
               frame_level);
       /* For MI, we should probably have a notification about
         current frame change.  But this error is not very
         likely, so don't bother for now.  */
-      print_stack_frame (get_selected_frame (NULL), 1, SRC_LINE);
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
     }
 }
 
+/* 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;
@@ -1074,11 +1549,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);
 
@@ -1087,7 +1585,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
     {
@@ -1110,10 +1608,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--;
@@ -1123,18 +1623,33 @@ restore_current_thread_cleanup_dtor (void *arg)
   xfree (old);
 }
 
+/* Set the thread reference count.  */
+
+static void
+set_thread_refcount (void *data)
+{
+  int k;
+  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--;
+}
+
 struct cleanup *
 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);
@@ -1167,6 +1682,54 @@ make_cleanup_restore_current_thread (void)
                            restore_current_thread_cleanup_dtor);
 }
 
+/* See gdbthread.h.  */
+
+int
+show_inferior_qualified_tids (void)
+{
+  return (inferior_list->next != NULL || inferior_list->num != 1);
+}
+
+/* See gdbthread.h.  */
+
+const char *
+print_thread_id (struct thread_info *thr)
+{
+  char *s = get_print_cell ();
+
+  if (show_inferior_qualified_tids ())
+    xsnprintf (s, PRINT_CELL_SIZE, "%d.%d", thr->inf->num, thr->per_inf_num);
+  else
+    xsnprintf (s, PRINT_CELL_SIZE, "%d", thr->per_inf_num);
+  return s;
+}
+
+/* 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 thread ID (first
+   by inferior number, and then by per-inferior thread number).  The
+   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 *a = *(const struct thread_info * const *) ap_voidp;
+  const struct thread_info *b = *(const struct thread_info * const *) bp_voidp;
+
+  if (a->inf->num != b->inf->num)
+    {
+      return ((a->inf->num > b->inf->num) - (a->inf->num < b->inf->num)
+             * (tp_array_compar_ascending ? +1 : -1));
+    }
+
+  return (((a->per_inf_num > b->per_inf_num)
+          - (a->per_inf_num < b->per_inf_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:
@@ -1178,9 +1741,18 @@ make_cleanup_restore_current_thread (void)
 static void
 thread_apply_all_command (char *cmd, int from_tty)
 {
-  struct thread_info *tp;
   struct cleanup *old_chain;
   char *saved_cmd;
+  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"));
@@ -1193,28 +1765,63 @@ thread_apply_all_command (char *cmd, int from_tty)
      execute_command.  */
   saved_cmd = xstrdup (cmd);
   make_cleanup (xfree, saved_cmd);
-  for (tp = thread_list; tp; tp = tp->next)
-    if (thread_alive (tp))
-      {
-       switch_to_thread (tp->ptid);
 
-       printf_filtered (_("\nThread %d (%s):\n"),
-                        tp->num, target_pid_to_str (inferior_ptid));
-       execute_command (cmd, from_tty);
-       strcpy (cmd, saved_cmd);        /* Restore exact command used
-                                          previously.  */
-      }
+  /* Note this includes exited threads.  */
+  tc = thread_count ();
+  if (tc != 0)
+    {
+      struct thread_info **tp_array;
+      struct thread_info *tp;
+      int i = 0, k;
+
+      /* Save a copy of the thread_list in case we execute detach
+         command.  */
+      tp_array = XNEWVEC (struct thread_info *, tc);
+      make_cleanup (xfree, tp_array);
+
+      ALL_NON_EXITED_THREADS (tp)
+        {
+          tp_array[i] = tp;
+          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++)
+        if (thread_alive (tp_array[k]))
+          {
+            switch_to_thread (tp_array[k]->ptid);
+            printf_filtered (_("\nThread %s (%s):\n"),
+                            print_thread_id (tp_array[k]),
+                            target_pid_to_str (inferior_ptid));
+            execute_command (cmd, from_tty);
+
+            /* Restore exact command used previously.  */
+            strcpy (cmd, saved_cmd);
+         }
+    }
 
   do_cleanups (old_chain);
 }
 
+/* Implementation of the "thread apply" command.  */
+
 static void
 thread_apply_command (char *tidlist, int from_tty)
 {
   char *cmd;
   struct cleanup *old_chain;
   char *saved_cmd;
-  struct get_number_or_range_state state;
+  struct tid_range_parser parser;
 
   if (tidlist == NULL || *tidlist == '\000')
     error (_("Please specify a thread ID list"));
@@ -1229,34 +1836,44 @@ thread_apply_command (char *tidlist, int from_tty)
   saved_cmd = xstrdup (cmd);
   old_chain = make_cleanup (xfree, saved_cmd);
 
-  init_number_or_range (&state, tidlist);
-  while (!state.finished && state.string < cmd)
-    {
-      struct thread_info *tp;
-      int start;
-      char *p = tidlist;
+  make_cleanup_restore_current_thread ();
 
-      start = get_number_or_range (&state);
-
-      make_cleanup_restore_current_thread ();
+  tid_range_parser_init (&parser, tidlist, current_inferior ()->num);
+  while (!tid_range_parser_finished (&parser)
+        && tid_range_parser_string (&parser) < cmd)
+    {
+      struct thread_info *tp = NULL;
+      struct inferior *inf;
+      int inf_num, thr_num;
 
-      tp = find_thread_id (start);
+      tid_range_parser_get_tid (&parser, &inf_num, &thr_num);
+      inf = find_inferior_id (inf_num);
+      if (inf != NULL)
+       tp = find_thread_id (inf, thr_num);
+      if (tp == NULL)
+       {
+         if (show_inferior_qualified_tids ()
+             || tid_range_parser_qualified (&parser))
+           warning (_("Unknown thread %d.%d"), inf_num, thr_num);
+         else
+           warning (_("Unknown thread %d"), thr_num);
+         continue;
+       }
 
-      if (!tp)
-       warning (_("Unknown thread %d."), start);
-      else if (!thread_alive (tp))
-       warning (_("Thread %d has terminated."), start);
-      else
+      if (!thread_alive (tp))
        {
-         switch_to_thread (tp->ptid);
+         warning (_("Thread %s has terminated."), print_thread_id (tp));
+         continue;
+       }
 
-         printf_filtered (_("\nThread %d (%s):\n"), tp->num,
-                          target_pid_to_str (inferior_ptid));
-         execute_command (cmd, from_tty);
+      switch_to_thread (tp->ptid);
 
-         /* Restore exact command used previously.  */
-         strcpy (cmd, saved_cmd);
-       }
+      printf_filtered (_("\nThread %s (%s):\n"), print_thread_id (tp),
+                      target_pid_to_str (inferior_ptid));
+      execute_command (cmd, from_tty);
+
+      /* Restore exact command used previously.  */
+      strcpy (cmd, saved_cmd);
     }
 
   do_cleanups (old_chain);
@@ -1265,7 +1882,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)
@@ -1275,13 +1892,15 @@ thread_command (char *tidstr, int from_tty)
 
       if (target_has_stack)
        {
+         struct thread_info *tp = inferior_thread ();
+
          if (is_exited (inferior_ptid))
-           printf_filtered (_("[Current thread is %d (%s) (exited)]\n"),
-                            pid_to_thread_id (inferior_ptid),
+           printf_filtered (_("[Current thread is %s (%s) (exited)]\n"),
+                            print_thread_id (tp),
                             target_pid_to_str (inferior_ptid));
          else
-           printf_filtered (_("[Current thread is %d (%s)]\n"),
-                            pid_to_thread_id (inferior_ptid),
+           printf_filtered (_("[Current thread is %s (%s)]\n"),
+                            print_thread_id (tp),
                             target_pid_to_str (inferior_ptid));
        }
       else
@@ -1302,8 +1921,7 @@ thread_name_command (char *arg, int from_tty)
   if (ptid_equal (inferior_ptid, null_ptid))
     error (_("No thread selected"));
 
-  while (arg && isspace (*arg))
-    ++arg;
+  arg = skip_spaces (arg);
 
   info = inferior_thread ();
   xfree (info->name);
@@ -1316,7 +1934,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')
@@ -1331,32 +1949,32 @@ thread_find_command (char *arg, int from_tty)
     {
       if (tp->name != NULL && re_exec (tp->name))
        {
-         printf_filtered (_("Thread %d has name '%s'\n"),
-                          tp->num, tp->name);
+         printf_filtered (_("Thread %s has name '%s'\n"),
+                          print_thread_id (tp), tp->name);
          match++;
        }
 
       tmp = target_thread_name (tp);
       if (tmp != NULL && re_exec (tmp))
        {
-         printf_filtered (_("Thread %d has target name '%s'\n"),
-                          tp->num, tmp);
+         printf_filtered (_("Thread %s has target name '%s'\n"),
+                          print_thread_id (tp), tmp);
          match++;
        }
 
       tmp = target_pid_to_str (tp->ptid);
       if (tmp != NULL && re_exec (tmp))
        {
-         printf_filtered (_("Thread %d has target id '%s'\n"),
-                          tp->num, tmp);
+         printf_filtered (_("Thread %s has target id '%s'\n"),
+                          print_thread_id (tp), tmp);
          match++;
        }
 
       tmp = target_extra_thread_info (tp);
       if (tmp != NULL && re_exec (tmp))
        {
-         printf_filtered (_("Thread %d has extra info '%s'\n"),
-                          tp->num, tmp);
+         printf_filtered (_("Thread %s has extra info '%s'\n"),
+                          print_thread_id (tp), tmp);
          match++;
        }
     }
@@ -1376,30 +1994,42 @@ show_print_thread_events (struct ui_file *file, int from_tty,
 }
 
 static int
-do_captured_thread_select (struct ui_out *uiout, void *tidstr)
+do_captured_thread_select (struct ui_out *uiout, void *tidstr_v)
 {
-  int num;
+  const char *tidstr = tidstr_v;
   struct thread_info *tp;
 
-  num = value_as_long (parse_and_eval (tidstr));
-
-  tp = find_thread_id (num);
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      int num = value_as_long (parse_and_eval (tidstr));
 
-  if (!tp)
-    error (_("Thread ID %d not known."), num);
+      tp = find_thread_global_id (num);
+      if (tp == NULL)
+       error (_("Thread ID %d not known."), num);
+    }
+  else
+    {
+      tp = parse_thread_id (tidstr, NULL);
+      gdb_assert (tp != NULL);
+    }
 
   if (!thread_alive (tp))
-    error (_("Thread ID %d has terminated."), num);
+    error (_("Thread ID %s has terminated."), tidstr);
 
   switch_to_thread (tp->ptid);
 
   annotate_thread_changed ();
 
-  ui_out_text (uiout, "[Switching to thread ");
-  ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
-  ui_out_text (uiout, " (");
-  ui_out_text (uiout, target_pid_to_str (inferior_ptid));
-  ui_out_text (uiout, ")]");
+  if (ui_out_is_mi_like_p (uiout))
+    ui_out_field_int (uiout, "new-thread-id", inferior_thread ()->global_num);
+  else
+    {
+      ui_out_text (uiout, "[Switching to thread ");
+      ui_out_field_string (uiout, "new-thread-id", print_thread_id (tp));
+      ui_out_text (uiout, " (");
+      ui_out_text (uiout, target_pid_to_str (inferior_ptid));
+      ui_out_text (uiout, ")]");
+    }
 
   /* Note that we can't reach this with an exited thread, due to the
      thread_alive check above.  */
@@ -1408,7 +2038,7 @@ do_captured_thread_select (struct ui_out *uiout, void *tidstr)
   else
     {
       ui_out_text (uiout, "\n");
-      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
     }
 
   /* Since the current thread may have changed, see if there is any
@@ -1427,24 +2057,71 @@ gdb_thread_select (struct ui_out *uiout, char *tidstr, char **error_message)
   return GDB_RC_OK;
 }
 
+/* Update the 'threads_executing' global based on the threads we know
+   about right now.  */
+
+static void
+update_threads_executing (void)
+{
+  struct thread_info *tp;
+
+  threads_executing = 0;
+  ALL_NON_EXITED_THREADS (tp)
+    {
+      if (tp->executing)
+       {
+         threads_executing = 1;
+         break;
+       }
+    }
+}
+
 void
 update_thread_list (void)
 {
-  prune_threads ();
-  target_find_new_threads ();
+  target_update_thread_list ();
+  update_threads_executing ();
 }
 
-/* Return a new value for the selected thread's id.  Return a value of 0 if
-   no thread is selected, or no threads exist.  */
+/* Return a new value for the selected thread's id.  Return a value of
+   0 if no thread is selected.  If GLOBAL is true, return the thread's
+   global number.  Otherwise return the per-inferior number.  */
 
 static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
-                     void *ignore)
+thread_num_make_value_helper (struct gdbarch *gdbarch, int global)
 {
   struct thread_info *tp = find_thread_ptid (inferior_ptid);
+  int int_val;
 
-  return value_from_longest (builtin_type (gdbarch)->builtin_int,
-                            (tp ? tp->num : 0));
+  if (tp == NULL)
+    int_val = 0;
+  else if (global)
+    int_val = tp->global_num;
+  else
+    int_val = tp->per_inf_num;
+
+  return value_from_longest (builtin_type (gdbarch)->builtin_int, int_val);
+}
+
+/* Return a new value for the selected thread's per-inferior thread
+   number.  Return a value of 0 if no thread is selected, or no
+   threads exist.  */
+
+static struct value *
+thread_id_per_inf_num_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+                                 void *ignore)
+{
+  return thread_num_make_value_helper (gdbarch, 0);
+}
+
+/* Return a new value for the selected thread's global id.  Return a
+   value of 0 if no thread is selected, or no threads exist.  */
+
+static struct value *
+global_thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+                            void *ignore)
+{
+  return thread_num_make_value_helper (gdbarch, 1);
 }
 
 /* Commands with a prefix of `thread'.  */
@@ -1454,7 +2131,16 @@ struct cmd_list_element *thread_cmd_list = NULL;
 
 static const struct internalvar_funcs thread_funcs =
 {
-  thread_id_make_value,
+  thread_id_per_inf_num_make_value,
+  NULL,
+  NULL
+};
+
+/* Implementation of `gthread' variable.  */
+
+static const struct internalvar_funcs gthread_funcs =
+{
+  global_thread_id_make_value,
   NULL,
   NULL
 };
@@ -1466,9 +2152,10 @@ _initialize_thread (void)
 
   add_info ("threads", info_threads_command, 
            _("Display currently known threads.\n\
-Usage: info threads [ID]...\n\
-Optional arguments are thread IDs with spaces between.\n\
-If no arguments, all threads are displayed."));
+Usage: info threads [-gid] [ID]...\n\
+-gid: Show global thread IDs.\n\
+If ID is given, it is a space-separated list of IDs of threads to display.\n\
+Otherwise, all threads are displayed."));
 
   add_prefix_cmd ("thread", class_run, thread_command, _("\
 Use this command to switch between threads.\n\
@@ -1480,7 +2167,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\
@@ -1493,8 +2187,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, _("\
@@ -1505,4 +2198,7 @@ Show printing of thread events (such as thread start and exit)."), NULL,
          &setprintlist, &showprintlist);
 
   create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
+  create_internalvar_type_lazy ("_gthread", &gthread_funcs, NULL);
+
+  observer_attach_thread_ptid_changed (restore_current_thread_ptid_changed);
 }
This page took 0.046508 seconds and 4 git commands to generate.