xref: /dflybsd-src/contrib/gdb-7/gdb/thread.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Multi-process/thread control for GDB, the GNU debugger.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 1986-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    Contributed by Lynx Real-Time Systems, Inc.  Los Gatos, CA.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This file is part of GDB.
85796c8dcSSimon Schubert 
95796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
105796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
115796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
125796c8dcSSimon Schubert    (at your option) any later version.
135796c8dcSSimon Schubert 
145796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
155796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
165796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
175796c8dcSSimon Schubert    GNU General Public License for more details.
185796c8dcSSimon Schubert 
195796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
205796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
215796c8dcSSimon Schubert 
225796c8dcSSimon Schubert #include "defs.h"
235796c8dcSSimon Schubert #include "symtab.h"
245796c8dcSSimon Schubert #include "frame.h"
255796c8dcSSimon Schubert #include "inferior.h"
265796c8dcSSimon Schubert #include "environ.h"
275796c8dcSSimon Schubert #include "value.h"
285796c8dcSSimon Schubert #include "target.h"
295796c8dcSSimon Schubert #include "gdbthread.h"
305796c8dcSSimon Schubert #include "exceptions.h"
315796c8dcSSimon Schubert #include "command.h"
325796c8dcSSimon Schubert #include "gdbcmd.h"
335796c8dcSSimon Schubert #include "regcache.h"
345796c8dcSSimon Schubert #include "gdb.h"
355796c8dcSSimon Schubert #include "gdb_string.h"
36*ef5ccd6cSJohn Marino #include "btrace.h"
375796c8dcSSimon Schubert 
385796c8dcSSimon Schubert #include <ctype.h>
395796c8dcSSimon Schubert #include <sys/types.h>
405796c8dcSSimon Schubert #include <signal.h>
415796c8dcSSimon Schubert #include "ui-out.h"
425796c8dcSSimon Schubert #include "observer.h"
435796c8dcSSimon Schubert #include "annotate.h"
445796c8dcSSimon Schubert #include "cli/cli-decode.h"
45c50c785cSJohn Marino #include "gdb_regex.h"
46c50c785cSJohn Marino #include "cli/cli-utils.h"
47a45ae5f8SJohn Marino #include "continuations.h"
485796c8dcSSimon Schubert 
49c50c785cSJohn Marino /* Definition of struct thread_info exported to gdbthread.h.  */
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert /* Prototypes for exported functions.  */
525796c8dcSSimon Schubert 
535796c8dcSSimon Schubert void _initialize_thread (void);
545796c8dcSSimon Schubert 
555796c8dcSSimon Schubert /* Prototypes for local functions.  */
565796c8dcSSimon Schubert 
57*ef5ccd6cSJohn Marino struct thread_info *thread_list = NULL;
585796c8dcSSimon Schubert static int highest_thread_num;
595796c8dcSSimon Schubert 
605796c8dcSSimon Schubert static void thread_command (char *tidstr, int from_tty);
615796c8dcSSimon Schubert static void thread_apply_all_command (char *, int);
625796c8dcSSimon Schubert static int thread_alive (struct thread_info *);
635796c8dcSSimon Schubert static void info_threads_command (char *, int);
645796c8dcSSimon Schubert static void thread_apply_command (char *, int);
655796c8dcSSimon Schubert static void restore_current_thread (ptid_t);
665796c8dcSSimon Schubert static void prune_threads (void);
675796c8dcSSimon Schubert 
685796c8dcSSimon Schubert struct thread_info*
inferior_thread(void)695796c8dcSSimon Schubert inferior_thread (void)
705796c8dcSSimon Schubert {
715796c8dcSSimon Schubert   struct thread_info *tp = find_thread_ptid (inferior_ptid);
725796c8dcSSimon Schubert   gdb_assert (tp);
735796c8dcSSimon Schubert   return tp;
745796c8dcSSimon Schubert }
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert void
delete_step_resume_breakpoint(struct thread_info * tp)775796c8dcSSimon Schubert delete_step_resume_breakpoint (struct thread_info *tp)
785796c8dcSSimon Schubert {
79c50c785cSJohn Marino   if (tp && tp->control.step_resume_breakpoint)
805796c8dcSSimon Schubert     {
81c50c785cSJohn Marino       delete_breakpoint (tp->control.step_resume_breakpoint);
82c50c785cSJohn Marino       tp->control.step_resume_breakpoint = NULL;
83c50c785cSJohn Marino     }
84c50c785cSJohn Marino }
85c50c785cSJohn Marino 
86c50c785cSJohn Marino void
delete_exception_resume_breakpoint(struct thread_info * tp)87c50c785cSJohn Marino delete_exception_resume_breakpoint (struct thread_info *tp)
88c50c785cSJohn Marino {
89c50c785cSJohn Marino   if (tp && tp->control.exception_resume_breakpoint)
90c50c785cSJohn Marino     {
91c50c785cSJohn Marino       delete_breakpoint (tp->control.exception_resume_breakpoint);
92c50c785cSJohn Marino       tp->control.exception_resume_breakpoint = NULL;
935796c8dcSSimon Schubert     }
945796c8dcSSimon Schubert }
955796c8dcSSimon Schubert 
965796c8dcSSimon Schubert static void
clear_thread_inferior_resources(struct thread_info * tp)975796c8dcSSimon Schubert clear_thread_inferior_resources (struct thread_info *tp)
985796c8dcSSimon Schubert {
995796c8dcSSimon Schubert   /* NOTE: this will take care of any left-over step_resume breakpoints,
1005796c8dcSSimon Schubert      but not any user-specified thread-specific breakpoints.  We can not
1015796c8dcSSimon Schubert      delete the breakpoint straight-off, because the inferior might not
1025796c8dcSSimon Schubert      be stopped at the moment.  */
103c50c785cSJohn Marino   if (tp->control.step_resume_breakpoint)
1045796c8dcSSimon Schubert     {
105c50c785cSJohn Marino       tp->control.step_resume_breakpoint->disposition = disp_del_at_next_stop;
106c50c785cSJohn Marino       tp->control.step_resume_breakpoint = NULL;
1075796c8dcSSimon Schubert     }
1085796c8dcSSimon Schubert 
109c50c785cSJohn Marino   if (tp->control.exception_resume_breakpoint)
110c50c785cSJohn Marino     {
111c50c785cSJohn Marino       tp->control.exception_resume_breakpoint->disposition
112c50c785cSJohn Marino 	= disp_del_at_next_stop;
113c50c785cSJohn Marino       tp->control.exception_resume_breakpoint = NULL;
114c50c785cSJohn Marino     }
115c50c785cSJohn Marino 
116*ef5ccd6cSJohn Marino   delete_longjmp_breakpoint_at_next_stop (tp->num);
117*ef5ccd6cSJohn Marino 
118c50c785cSJohn Marino   bpstat_clear (&tp->control.stop_bpstat);
1195796c8dcSSimon Schubert 
120*ef5ccd6cSJohn Marino   btrace_teardown (tp);
121*ef5ccd6cSJohn Marino 
122a45ae5f8SJohn Marino   do_all_intermediate_continuations_thread (tp, 1);
123a45ae5f8SJohn Marino   do_all_continuations_thread (tp, 1);
1245796c8dcSSimon Schubert }
1255796c8dcSSimon Schubert 
1265796c8dcSSimon Schubert static void
free_thread(struct thread_info * tp)1275796c8dcSSimon Schubert free_thread (struct thread_info *tp)
1285796c8dcSSimon Schubert {
1295796c8dcSSimon Schubert   if (tp->private)
130cf7f2e2dSJohn Marino     {
131cf7f2e2dSJohn Marino       if (tp->private_dtor)
132cf7f2e2dSJohn Marino 	tp->private_dtor (tp->private);
133cf7f2e2dSJohn Marino       else
1345796c8dcSSimon Schubert 	xfree (tp->private);
135cf7f2e2dSJohn Marino     }
1365796c8dcSSimon Schubert 
137c50c785cSJohn Marino   xfree (tp->name);
1385796c8dcSSimon Schubert   xfree (tp);
1395796c8dcSSimon Schubert }
1405796c8dcSSimon Schubert 
1415796c8dcSSimon Schubert void
init_thread_list(void)1425796c8dcSSimon Schubert init_thread_list (void)
1435796c8dcSSimon Schubert {
1445796c8dcSSimon Schubert   struct thread_info *tp, *tpnext;
1455796c8dcSSimon Schubert 
1465796c8dcSSimon Schubert   highest_thread_num = 0;
1475796c8dcSSimon Schubert 
1485796c8dcSSimon Schubert   if (!thread_list)
1495796c8dcSSimon Schubert     return;
1505796c8dcSSimon Schubert 
1515796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tpnext)
1525796c8dcSSimon Schubert     {
1535796c8dcSSimon Schubert       tpnext = tp->next;
1545796c8dcSSimon Schubert       free_thread (tp);
1555796c8dcSSimon Schubert     }
1565796c8dcSSimon Schubert 
1575796c8dcSSimon Schubert   thread_list = NULL;
1585796c8dcSSimon Schubert }
1595796c8dcSSimon Schubert 
1605796c8dcSSimon Schubert /* Allocate a new thread with target id PTID and add it to the thread
1615796c8dcSSimon Schubert    list.  */
1625796c8dcSSimon Schubert 
1635796c8dcSSimon Schubert static struct thread_info *
new_thread(ptid_t ptid)1645796c8dcSSimon Schubert new_thread (ptid_t ptid)
1655796c8dcSSimon Schubert {
1665796c8dcSSimon Schubert   struct thread_info *tp;
1675796c8dcSSimon Schubert 
1685796c8dcSSimon Schubert   tp = xcalloc (1, sizeof (*tp));
1695796c8dcSSimon Schubert 
1705796c8dcSSimon Schubert   tp->ptid = ptid;
1715796c8dcSSimon Schubert   tp->num = ++highest_thread_num;
1725796c8dcSSimon Schubert   tp->next = thread_list;
1735796c8dcSSimon Schubert   thread_list = tp;
1745796c8dcSSimon Schubert 
1755796c8dcSSimon Schubert   /* Nothing to follow yet.  */
1765796c8dcSSimon Schubert   tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
177a45ae5f8SJohn Marino   tp->state = THREAD_STOPPED;
1785796c8dcSSimon Schubert 
1795796c8dcSSimon Schubert   return tp;
1805796c8dcSSimon Schubert }
1815796c8dcSSimon Schubert 
1825796c8dcSSimon Schubert struct thread_info *
add_thread_silent(ptid_t ptid)1835796c8dcSSimon Schubert add_thread_silent (ptid_t ptid)
1845796c8dcSSimon Schubert {
1855796c8dcSSimon Schubert   struct thread_info *tp;
1865796c8dcSSimon Schubert 
1875796c8dcSSimon Schubert   tp = find_thread_ptid (ptid);
1885796c8dcSSimon Schubert   if (tp)
1895796c8dcSSimon Schubert     /* Found an old thread with the same id.  It has to be dead,
1905796c8dcSSimon Schubert        otherwise we wouldn't be adding a new thread with the same id.
1915796c8dcSSimon Schubert        The OS is reusing this id --- delete it, and recreate a new
1925796c8dcSSimon Schubert        one.  */
1935796c8dcSSimon Schubert     {
1945796c8dcSSimon Schubert       /* In addition to deleting the thread, if this is the current
1955796c8dcSSimon Schubert 	 thread, then we need to take care that delete_thread doesn't
1965796c8dcSSimon Schubert 	 really delete the thread if it is inferior_ptid.  Create a
1975796c8dcSSimon Schubert 	 new template thread in the list with an invalid ptid, switch
1985796c8dcSSimon Schubert 	 to it, delete the original thread, reset the new thread's
1995796c8dcSSimon Schubert 	 ptid, and switch to it.  */
2005796c8dcSSimon Schubert 
2015796c8dcSSimon Schubert       if (ptid_equal (inferior_ptid, ptid))
2025796c8dcSSimon Schubert 	{
203cf7f2e2dSJohn Marino 	  tp = new_thread (null_ptid);
2045796c8dcSSimon Schubert 
2055796c8dcSSimon Schubert 	  /* Make switch_to_thread not read from the thread.  */
206a45ae5f8SJohn Marino 	  tp->state = THREAD_EXITED;
207cf7f2e2dSJohn Marino 	  switch_to_thread (null_ptid);
2085796c8dcSSimon Schubert 
2095796c8dcSSimon Schubert 	  /* Now we can delete it.  */
2105796c8dcSSimon Schubert 	  delete_thread (ptid);
2115796c8dcSSimon Schubert 
2125796c8dcSSimon Schubert 	  /* Now reset its ptid, and reswitch inferior_ptid to it.  */
2135796c8dcSSimon Schubert 	  tp->ptid = ptid;
214a45ae5f8SJohn Marino 	  tp->state = THREAD_STOPPED;
2155796c8dcSSimon Schubert 	  switch_to_thread (ptid);
2165796c8dcSSimon Schubert 
2175796c8dcSSimon Schubert 	  observer_notify_new_thread (tp);
2185796c8dcSSimon Schubert 
2195796c8dcSSimon Schubert 	  /* All done.  */
2205796c8dcSSimon Schubert 	  return tp;
2215796c8dcSSimon Schubert 	}
2225796c8dcSSimon Schubert       else
2235796c8dcSSimon Schubert 	/* Just go ahead and delete it.  */
2245796c8dcSSimon Schubert 	delete_thread (ptid);
2255796c8dcSSimon Schubert     }
2265796c8dcSSimon Schubert 
2275796c8dcSSimon Schubert   tp = new_thread (ptid);
2285796c8dcSSimon Schubert   observer_notify_new_thread (tp);
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert   return tp;
2315796c8dcSSimon Schubert }
2325796c8dcSSimon Schubert 
2335796c8dcSSimon Schubert struct thread_info *
add_thread_with_info(ptid_t ptid,struct private_thread_info * private)2345796c8dcSSimon Schubert add_thread_with_info (ptid_t ptid, struct private_thread_info *private)
2355796c8dcSSimon Schubert {
2365796c8dcSSimon Schubert   struct thread_info *result = add_thread_silent (ptid);
2375796c8dcSSimon Schubert 
2385796c8dcSSimon Schubert   result->private = private;
2395796c8dcSSimon Schubert 
2405796c8dcSSimon Schubert   if (print_thread_events)
2415796c8dcSSimon Schubert     printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
2425796c8dcSSimon Schubert 
2435796c8dcSSimon Schubert   annotate_new_thread ();
2445796c8dcSSimon Schubert   return result;
2455796c8dcSSimon Schubert }
2465796c8dcSSimon Schubert 
2475796c8dcSSimon Schubert struct thread_info *
add_thread(ptid_t ptid)2485796c8dcSSimon Schubert add_thread (ptid_t ptid)
2495796c8dcSSimon Schubert {
2505796c8dcSSimon Schubert   return add_thread_with_info (ptid, NULL);
2515796c8dcSSimon Schubert }
2525796c8dcSSimon Schubert 
2535796c8dcSSimon Schubert /* Delete thread PTID.  If SILENT, don't notify the observer of this
2545796c8dcSSimon Schubert    exit.  */
2555796c8dcSSimon Schubert static void
delete_thread_1(ptid_t ptid,int silent)2565796c8dcSSimon Schubert delete_thread_1 (ptid_t ptid, int silent)
2575796c8dcSSimon Schubert {
2585796c8dcSSimon Schubert   struct thread_info *tp, *tpprev;
2595796c8dcSSimon Schubert 
2605796c8dcSSimon Schubert   tpprev = NULL;
2615796c8dcSSimon Schubert 
2625796c8dcSSimon Schubert   for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
2635796c8dcSSimon Schubert     if (ptid_equal (tp->ptid, ptid))
2645796c8dcSSimon Schubert       break;
2655796c8dcSSimon Schubert 
2665796c8dcSSimon Schubert   if (!tp)
2675796c8dcSSimon Schubert     return;
2685796c8dcSSimon Schubert 
2695796c8dcSSimon Schubert   /* If this is the current thread, or there's code out there that
2705796c8dcSSimon Schubert      relies on it existing (refcount > 0) we can't delete yet.  Mark
2715796c8dcSSimon Schubert      it as exited, and notify it.  */
2725796c8dcSSimon Schubert   if (tp->refcount > 0
2735796c8dcSSimon Schubert       || ptid_equal (tp->ptid, inferior_ptid))
2745796c8dcSSimon Schubert     {
275a45ae5f8SJohn Marino       if (tp->state != THREAD_EXITED)
2765796c8dcSSimon Schubert 	{
2775796c8dcSSimon Schubert 	  observer_notify_thread_exit (tp, silent);
2785796c8dcSSimon Schubert 
2795796c8dcSSimon Schubert 	  /* Tag it as exited.  */
280a45ae5f8SJohn Marino 	  tp->state = THREAD_EXITED;
2815796c8dcSSimon Schubert 
2825796c8dcSSimon Schubert 	  /* Clear breakpoints, etc. associated with this thread.  */
2835796c8dcSSimon Schubert 	  clear_thread_inferior_resources (tp);
2845796c8dcSSimon Schubert 	}
2855796c8dcSSimon Schubert 
2865796c8dcSSimon Schubert        /* Will be really deleted some other time.  */
2875796c8dcSSimon Schubert        return;
2885796c8dcSSimon Schubert      }
2895796c8dcSSimon Schubert 
290a45ae5f8SJohn Marino   /* Notify thread exit, but only if we haven't already.  */
291a45ae5f8SJohn Marino   if (tp->state != THREAD_EXITED)
292a45ae5f8SJohn Marino     observer_notify_thread_exit (tp, silent);
293a45ae5f8SJohn Marino 
294a45ae5f8SJohn Marino   /* Tag it as exited.  */
295a45ae5f8SJohn Marino   tp->state = THREAD_EXITED;
296a45ae5f8SJohn Marino   clear_thread_inferior_resources (tp);
297a45ae5f8SJohn Marino 
2985796c8dcSSimon Schubert   if (tpprev)
2995796c8dcSSimon Schubert     tpprev->next = tp->next;
3005796c8dcSSimon Schubert   else
3015796c8dcSSimon Schubert     thread_list = tp->next;
3025796c8dcSSimon Schubert 
3035796c8dcSSimon Schubert   free_thread (tp);
3045796c8dcSSimon Schubert }
3055796c8dcSSimon Schubert 
3065796c8dcSSimon Schubert /* Delete thread PTID and notify of thread exit.  If this is
3075796c8dcSSimon Schubert    inferior_ptid, don't actually delete it, but tag it as exited and
3085796c8dcSSimon Schubert    do the notification.  If PTID is the user selected thread, clear
3095796c8dcSSimon Schubert    it.  */
3105796c8dcSSimon Schubert void
delete_thread(ptid_t ptid)3115796c8dcSSimon Schubert delete_thread (ptid_t ptid)
3125796c8dcSSimon Schubert {
3135796c8dcSSimon Schubert   delete_thread_1 (ptid, 0 /* not silent */);
3145796c8dcSSimon Schubert }
3155796c8dcSSimon Schubert 
3165796c8dcSSimon Schubert void
delete_thread_silent(ptid_t ptid)3175796c8dcSSimon Schubert delete_thread_silent (ptid_t ptid)
3185796c8dcSSimon Schubert {
3195796c8dcSSimon Schubert   delete_thread_1 (ptid, 1 /* silent */);
3205796c8dcSSimon Schubert }
3215796c8dcSSimon Schubert 
3225796c8dcSSimon Schubert struct thread_info *
find_thread_id(int num)3235796c8dcSSimon Schubert find_thread_id (int num)
3245796c8dcSSimon Schubert {
3255796c8dcSSimon Schubert   struct thread_info *tp;
3265796c8dcSSimon Schubert 
3275796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
3285796c8dcSSimon Schubert     if (tp->num == num)
3295796c8dcSSimon Schubert       return tp;
3305796c8dcSSimon Schubert 
3315796c8dcSSimon Schubert   return NULL;
3325796c8dcSSimon Schubert }
3335796c8dcSSimon Schubert 
3345796c8dcSSimon Schubert /* Find a thread_info by matching PTID.  */
3355796c8dcSSimon Schubert struct thread_info *
find_thread_ptid(ptid_t ptid)3365796c8dcSSimon Schubert find_thread_ptid (ptid_t ptid)
3375796c8dcSSimon Schubert {
3385796c8dcSSimon Schubert   struct thread_info *tp;
3395796c8dcSSimon Schubert 
3405796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
3415796c8dcSSimon Schubert     if (ptid_equal (tp->ptid, ptid))
3425796c8dcSSimon Schubert       return tp;
3435796c8dcSSimon Schubert 
3445796c8dcSSimon Schubert   return NULL;
3455796c8dcSSimon Schubert }
3465796c8dcSSimon Schubert 
3475796c8dcSSimon Schubert /*
3485796c8dcSSimon Schubert  * Thread iterator function.
3495796c8dcSSimon Schubert  *
3505796c8dcSSimon Schubert  * Calls a callback function once for each thread, so long as
3515796c8dcSSimon Schubert  * the callback function returns false.  If the callback function
3525796c8dcSSimon Schubert  * returns true, the iteration will end and the current thread
3535796c8dcSSimon Schubert  * will be returned.  This can be useful for implementing a
3545796c8dcSSimon Schubert  * search for a thread with arbitrary attributes, or for applying
3555796c8dcSSimon Schubert  * some operation to every thread.
3565796c8dcSSimon Schubert  *
3575796c8dcSSimon Schubert  * FIXME: some of the existing functionality, such as
3585796c8dcSSimon Schubert  * "Thread apply all", might be rewritten using this functionality.
3595796c8dcSSimon Schubert  */
3605796c8dcSSimon Schubert 
3615796c8dcSSimon Schubert struct thread_info *
iterate_over_threads(int (* callback)(struct thread_info *,void *),void * data)3625796c8dcSSimon Schubert iterate_over_threads (int (*callback) (struct thread_info *, void *),
3635796c8dcSSimon Schubert 		      void *data)
3645796c8dcSSimon Schubert {
3655796c8dcSSimon Schubert   struct thread_info *tp, *next;
3665796c8dcSSimon Schubert 
3675796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = next)
3685796c8dcSSimon Schubert     {
3695796c8dcSSimon Schubert       next = tp->next;
3705796c8dcSSimon Schubert       if ((*callback) (tp, data))
3715796c8dcSSimon Schubert 	return tp;
3725796c8dcSSimon Schubert     }
3735796c8dcSSimon Schubert 
3745796c8dcSSimon Schubert   return NULL;
3755796c8dcSSimon Schubert }
3765796c8dcSSimon Schubert 
3775796c8dcSSimon Schubert int
thread_count(void)3785796c8dcSSimon Schubert thread_count (void)
3795796c8dcSSimon Schubert {
3805796c8dcSSimon Schubert   int result = 0;
3815796c8dcSSimon Schubert   struct thread_info *tp;
3825796c8dcSSimon Schubert 
3835796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
3845796c8dcSSimon Schubert     ++result;
3855796c8dcSSimon Schubert 
3865796c8dcSSimon Schubert   return result;
3875796c8dcSSimon Schubert }
3885796c8dcSSimon Schubert 
3895796c8dcSSimon Schubert int
valid_thread_id(int num)3905796c8dcSSimon Schubert valid_thread_id (int num)
3915796c8dcSSimon Schubert {
3925796c8dcSSimon Schubert   struct thread_info *tp;
3935796c8dcSSimon Schubert 
3945796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
3955796c8dcSSimon Schubert     if (tp->num == num)
3965796c8dcSSimon Schubert       return 1;
3975796c8dcSSimon Schubert 
3985796c8dcSSimon Schubert   return 0;
3995796c8dcSSimon Schubert }
4005796c8dcSSimon Schubert 
4015796c8dcSSimon Schubert int
pid_to_thread_id(ptid_t ptid)4025796c8dcSSimon Schubert pid_to_thread_id (ptid_t ptid)
4035796c8dcSSimon Schubert {
4045796c8dcSSimon Schubert   struct thread_info *tp;
4055796c8dcSSimon Schubert 
4065796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
4075796c8dcSSimon Schubert     if (ptid_equal (tp->ptid, ptid))
4085796c8dcSSimon Schubert       return tp->num;
4095796c8dcSSimon Schubert 
4105796c8dcSSimon Schubert   return 0;
4115796c8dcSSimon Schubert }
4125796c8dcSSimon Schubert 
4135796c8dcSSimon Schubert ptid_t
thread_id_to_pid(int num)4145796c8dcSSimon Schubert thread_id_to_pid (int num)
4155796c8dcSSimon Schubert {
4165796c8dcSSimon Schubert   struct thread_info *thread = find_thread_id (num);
417cf7f2e2dSJohn Marino 
4185796c8dcSSimon Schubert   if (thread)
4195796c8dcSSimon Schubert     return thread->ptid;
4205796c8dcSSimon Schubert   else
4215796c8dcSSimon Schubert     return pid_to_ptid (-1);
4225796c8dcSSimon Schubert }
4235796c8dcSSimon Schubert 
4245796c8dcSSimon Schubert int
in_thread_list(ptid_t ptid)4255796c8dcSSimon Schubert in_thread_list (ptid_t ptid)
4265796c8dcSSimon Schubert {
4275796c8dcSSimon Schubert   struct thread_info *tp;
4285796c8dcSSimon Schubert 
4295796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
4305796c8dcSSimon Schubert     if (ptid_equal (tp->ptid, ptid))
4315796c8dcSSimon Schubert       return 1;
4325796c8dcSSimon Schubert 
433c50c785cSJohn Marino   return 0;			/* Never heard of 'im.  */
4345796c8dcSSimon Schubert }
4355796c8dcSSimon Schubert 
4365796c8dcSSimon Schubert /* Finds the first thread of the inferior given by PID.  If PID is -1,
4375796c8dcSSimon Schubert    return the first thread in the list.  */
4385796c8dcSSimon Schubert 
4395796c8dcSSimon Schubert struct thread_info *
first_thread_of_process(int pid)4405796c8dcSSimon Schubert first_thread_of_process (int pid)
4415796c8dcSSimon Schubert {
4425796c8dcSSimon Schubert   struct thread_info *tp, *ret = NULL;
4435796c8dcSSimon Schubert 
4445796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
4455796c8dcSSimon Schubert     if (pid == -1 || ptid_get_pid (tp->ptid) == pid)
4465796c8dcSSimon Schubert       if (ret == NULL || tp->num < ret->num)
4475796c8dcSSimon Schubert 	ret = tp;
4485796c8dcSSimon Schubert 
4495796c8dcSSimon Schubert   return ret;
4505796c8dcSSimon Schubert }
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert struct thread_info *
any_thread_of_process(int pid)4535796c8dcSSimon Schubert any_thread_of_process (int pid)
4545796c8dcSSimon Schubert {
4555796c8dcSSimon Schubert   struct thread_info *tp;
4565796c8dcSSimon Schubert 
4575796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
4585796c8dcSSimon Schubert     if (ptid_get_pid (tp->ptid) == pid)
4595796c8dcSSimon Schubert       return tp;
4605796c8dcSSimon Schubert 
4615796c8dcSSimon Schubert   return NULL;
4625796c8dcSSimon Schubert }
4635796c8dcSSimon Schubert 
464cf7f2e2dSJohn Marino struct thread_info *
any_live_thread_of_process(int pid)465cf7f2e2dSJohn Marino any_live_thread_of_process (int pid)
466cf7f2e2dSJohn Marino {
467cf7f2e2dSJohn Marino   struct thread_info *tp;
468c50c785cSJohn Marino   struct thread_info *tp_executing = NULL;
469cf7f2e2dSJohn Marino 
470cf7f2e2dSJohn Marino   for (tp = thread_list; tp; tp = tp->next)
471a45ae5f8SJohn Marino     if (tp->state != THREAD_EXITED && ptid_get_pid (tp->ptid) == pid)
472cf7f2e2dSJohn Marino       {
473a45ae5f8SJohn Marino 	if (tp->executing)
474c50c785cSJohn Marino 	  tp_executing = tp;
475c50c785cSJohn Marino 	else
476cf7f2e2dSJohn Marino 	  return tp;
477cf7f2e2dSJohn Marino       }
478cf7f2e2dSJohn Marino 
479c50c785cSJohn Marino   return tp_executing;
480cf7f2e2dSJohn Marino }
481cf7f2e2dSJohn Marino 
4825796c8dcSSimon Schubert /* Print a list of thread ids currently known, and the total number of
4835796c8dcSSimon Schubert    threads.  To be used from within catch_errors.  */
4845796c8dcSSimon Schubert static int
do_captured_list_thread_ids(struct ui_out * uiout,void * arg)4855796c8dcSSimon Schubert do_captured_list_thread_ids (struct ui_out *uiout, void *arg)
4865796c8dcSSimon Schubert {
4875796c8dcSSimon Schubert   struct thread_info *tp;
4885796c8dcSSimon Schubert   int num = 0;
4895796c8dcSSimon Schubert   struct cleanup *cleanup_chain;
4905796c8dcSSimon Schubert   int current_thread = -1;
4915796c8dcSSimon Schubert 
492cf7f2e2dSJohn Marino   update_thread_list ();
4935796c8dcSSimon Schubert 
4945796c8dcSSimon Schubert   cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "thread-ids");
4955796c8dcSSimon Schubert 
4965796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
4975796c8dcSSimon Schubert     {
498a45ae5f8SJohn Marino       if (tp->state == THREAD_EXITED)
4995796c8dcSSimon Schubert 	continue;
5005796c8dcSSimon Schubert 
5015796c8dcSSimon Schubert       if (ptid_equal (tp->ptid, inferior_ptid))
5025796c8dcSSimon Schubert 	current_thread = tp->num;
5035796c8dcSSimon Schubert 
5045796c8dcSSimon Schubert       num++;
5055796c8dcSSimon Schubert       ui_out_field_int (uiout, "thread-id", tp->num);
5065796c8dcSSimon Schubert     }
5075796c8dcSSimon Schubert 
5085796c8dcSSimon Schubert   do_cleanups (cleanup_chain);
5095796c8dcSSimon Schubert 
5105796c8dcSSimon Schubert   if (current_thread != -1)
5115796c8dcSSimon Schubert     ui_out_field_int (uiout, "current-thread-id", current_thread);
5125796c8dcSSimon Schubert   ui_out_field_int (uiout, "number-of-threads", num);
5135796c8dcSSimon Schubert   return GDB_RC_OK;
5145796c8dcSSimon Schubert }
5155796c8dcSSimon Schubert 
5165796c8dcSSimon Schubert /* Official gdblib interface function to get a list of thread ids and
5175796c8dcSSimon Schubert    the total number.  */
5185796c8dcSSimon Schubert enum gdb_rc
gdb_list_thread_ids(struct ui_out * uiout,char ** error_message)5195796c8dcSSimon Schubert gdb_list_thread_ids (struct ui_out *uiout, char **error_message)
5205796c8dcSSimon Schubert {
5215796c8dcSSimon Schubert   if (catch_exceptions_with_msg (uiout, do_captured_list_thread_ids, NULL,
5225796c8dcSSimon Schubert 				 error_message, RETURN_MASK_ALL) < 0)
5235796c8dcSSimon Schubert     return GDB_RC_FAIL;
5245796c8dcSSimon Schubert   return GDB_RC_OK;
5255796c8dcSSimon Schubert }
5265796c8dcSSimon Schubert 
5275796c8dcSSimon Schubert /* Return true if TP is an active thread.  */
5285796c8dcSSimon Schubert static int
thread_alive(struct thread_info * tp)5295796c8dcSSimon Schubert thread_alive (struct thread_info *tp)
5305796c8dcSSimon Schubert {
531a45ae5f8SJohn Marino   if (tp->state == THREAD_EXITED)
5325796c8dcSSimon Schubert     return 0;
5335796c8dcSSimon Schubert   if (!target_thread_alive (tp->ptid))
5345796c8dcSSimon Schubert     return 0;
5355796c8dcSSimon Schubert   return 1;
5365796c8dcSSimon Schubert }
5375796c8dcSSimon Schubert 
5385796c8dcSSimon Schubert static void
prune_threads(void)5395796c8dcSSimon Schubert prune_threads (void)
5405796c8dcSSimon Schubert {
5415796c8dcSSimon Schubert   struct thread_info *tp, *next;
5425796c8dcSSimon Schubert 
5435796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = next)
5445796c8dcSSimon Schubert     {
5455796c8dcSSimon Schubert       next = tp->next;
5465796c8dcSSimon Schubert       if (!thread_alive (tp))
5475796c8dcSSimon Schubert 	delete_thread (tp->ptid);
5485796c8dcSSimon Schubert     }
5495796c8dcSSimon Schubert }
5505796c8dcSSimon Schubert 
5515796c8dcSSimon Schubert void
thread_change_ptid(ptid_t old_ptid,ptid_t new_ptid)5525796c8dcSSimon Schubert thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
5535796c8dcSSimon Schubert {
5545796c8dcSSimon Schubert   struct inferior *inf;
5555796c8dcSSimon Schubert   struct thread_info *tp;
5565796c8dcSSimon Schubert 
5575796c8dcSSimon Schubert   /* It can happen that what we knew as the target inferior id
5585796c8dcSSimon Schubert      changes.  E.g, target remote may only discover the remote process
5595796c8dcSSimon Schubert      pid after adding the inferior to GDB's list.  */
5605796c8dcSSimon Schubert   inf = find_inferior_pid (ptid_get_pid (old_ptid));
5615796c8dcSSimon Schubert   inf->pid = ptid_get_pid (new_ptid);
5625796c8dcSSimon Schubert 
5635796c8dcSSimon Schubert   tp = find_thread_ptid (old_ptid);
5645796c8dcSSimon Schubert   tp->ptid = new_ptid;
5655796c8dcSSimon Schubert 
5665796c8dcSSimon Schubert   observer_notify_thread_ptid_changed (old_ptid, new_ptid);
5675796c8dcSSimon Schubert }
5685796c8dcSSimon Schubert 
5695796c8dcSSimon Schubert void
set_running(ptid_t ptid,int running)5705796c8dcSSimon Schubert set_running (ptid_t ptid, int running)
5715796c8dcSSimon Schubert {
5725796c8dcSSimon Schubert   struct thread_info *tp;
5735796c8dcSSimon Schubert   int all = ptid_equal (ptid, minus_one_ptid);
5745796c8dcSSimon Schubert 
5755796c8dcSSimon Schubert   /* We try not to notify the observer if no thread has actually changed
5765796c8dcSSimon Schubert      the running state -- merely to reduce the number of messages to
5775796c8dcSSimon Schubert      frontend.  Frontend is supposed to handle multiple *running just fine.  */
5785796c8dcSSimon Schubert   if (all || ptid_is_pid (ptid))
5795796c8dcSSimon Schubert     {
5805796c8dcSSimon Schubert       int any_started = 0;
581cf7f2e2dSJohn Marino 
5825796c8dcSSimon Schubert       for (tp = thread_list; tp; tp = tp->next)
5835796c8dcSSimon Schubert 	if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
5845796c8dcSSimon Schubert 	  {
585a45ae5f8SJohn Marino 	    if (tp->state == THREAD_EXITED)
5865796c8dcSSimon Schubert 	      continue;
587a45ae5f8SJohn Marino 	    if (running && tp->state == THREAD_STOPPED)
5885796c8dcSSimon Schubert 	      any_started = 1;
589a45ae5f8SJohn Marino 	    tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
5905796c8dcSSimon Schubert 	  }
5915796c8dcSSimon Schubert       if (any_started)
5925796c8dcSSimon Schubert 	observer_notify_target_resumed (ptid);
5935796c8dcSSimon Schubert     }
5945796c8dcSSimon Schubert   else
5955796c8dcSSimon Schubert     {
5965796c8dcSSimon Schubert       int started = 0;
597cf7f2e2dSJohn Marino 
5985796c8dcSSimon Schubert       tp = find_thread_ptid (ptid);
5995796c8dcSSimon Schubert       gdb_assert (tp);
600a45ae5f8SJohn Marino       gdb_assert (tp->state != THREAD_EXITED);
601a45ae5f8SJohn Marino       if (running && tp->state == THREAD_STOPPED)
6025796c8dcSSimon Schubert  	started = 1;
603a45ae5f8SJohn Marino       tp->state = running ? THREAD_RUNNING : THREAD_STOPPED;
6045796c8dcSSimon Schubert       if (started)
6055796c8dcSSimon Schubert   	observer_notify_target_resumed (ptid);
6065796c8dcSSimon Schubert     }
6075796c8dcSSimon Schubert }
6085796c8dcSSimon Schubert 
6095796c8dcSSimon Schubert static int
is_thread_state(ptid_t ptid,enum thread_state state)6105796c8dcSSimon Schubert is_thread_state (ptid_t ptid, enum thread_state state)
6115796c8dcSSimon Schubert {
6125796c8dcSSimon Schubert   struct thread_info *tp;
6135796c8dcSSimon Schubert 
6145796c8dcSSimon Schubert   tp = find_thread_ptid (ptid);
6155796c8dcSSimon Schubert   gdb_assert (tp);
616a45ae5f8SJohn Marino   return tp->state == state;
6175796c8dcSSimon Schubert }
6185796c8dcSSimon Schubert 
6195796c8dcSSimon Schubert int
is_stopped(ptid_t ptid)6205796c8dcSSimon Schubert is_stopped (ptid_t ptid)
6215796c8dcSSimon Schubert {
6225796c8dcSSimon Schubert   return is_thread_state (ptid, THREAD_STOPPED);
6235796c8dcSSimon Schubert }
6245796c8dcSSimon Schubert 
6255796c8dcSSimon Schubert int
is_exited(ptid_t ptid)6265796c8dcSSimon Schubert is_exited (ptid_t ptid)
6275796c8dcSSimon Schubert {
6285796c8dcSSimon Schubert   return is_thread_state (ptid, THREAD_EXITED);
6295796c8dcSSimon Schubert }
6305796c8dcSSimon Schubert 
6315796c8dcSSimon Schubert int
is_running(ptid_t ptid)6325796c8dcSSimon Schubert is_running (ptid_t ptid)
6335796c8dcSSimon Schubert {
6345796c8dcSSimon Schubert   return is_thread_state (ptid, THREAD_RUNNING);
6355796c8dcSSimon Schubert }
6365796c8dcSSimon Schubert 
6375796c8dcSSimon Schubert int
any_running(void)6385796c8dcSSimon Schubert any_running (void)
6395796c8dcSSimon Schubert {
6405796c8dcSSimon Schubert   struct thread_info *tp;
6415796c8dcSSimon Schubert 
6425796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
643a45ae5f8SJohn Marino     if (tp->state == THREAD_RUNNING)
6445796c8dcSSimon Schubert       return 1;
6455796c8dcSSimon Schubert 
6465796c8dcSSimon Schubert   return 0;
6475796c8dcSSimon Schubert }
6485796c8dcSSimon Schubert 
6495796c8dcSSimon Schubert int
is_executing(ptid_t ptid)6505796c8dcSSimon Schubert is_executing (ptid_t ptid)
6515796c8dcSSimon Schubert {
6525796c8dcSSimon Schubert   struct thread_info *tp;
6535796c8dcSSimon Schubert 
6545796c8dcSSimon Schubert   tp = find_thread_ptid (ptid);
6555796c8dcSSimon Schubert   gdb_assert (tp);
656a45ae5f8SJohn Marino   return tp->executing;
6575796c8dcSSimon Schubert }
6585796c8dcSSimon Schubert 
6595796c8dcSSimon Schubert void
set_executing(ptid_t ptid,int executing)6605796c8dcSSimon Schubert set_executing (ptid_t ptid, int executing)
6615796c8dcSSimon Schubert {
6625796c8dcSSimon Schubert   struct thread_info *tp;
6635796c8dcSSimon Schubert   int all = ptid_equal (ptid, minus_one_ptid);
6645796c8dcSSimon Schubert 
6655796c8dcSSimon Schubert   if (all || ptid_is_pid (ptid))
6665796c8dcSSimon Schubert     {
6675796c8dcSSimon Schubert       for (tp = thread_list; tp; tp = tp->next)
6685796c8dcSSimon Schubert 	if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
669a45ae5f8SJohn Marino 	  tp->executing = executing;
6705796c8dcSSimon Schubert     }
6715796c8dcSSimon Schubert   else
6725796c8dcSSimon Schubert     {
6735796c8dcSSimon Schubert       tp = find_thread_ptid (ptid);
6745796c8dcSSimon Schubert       gdb_assert (tp);
675a45ae5f8SJohn Marino       tp->executing = executing;
6765796c8dcSSimon Schubert     }
6775796c8dcSSimon Schubert }
6785796c8dcSSimon Schubert 
6795796c8dcSSimon Schubert void
set_stop_requested(ptid_t ptid,int stop)6805796c8dcSSimon Schubert set_stop_requested (ptid_t ptid, int stop)
6815796c8dcSSimon Schubert {
6825796c8dcSSimon Schubert   struct thread_info *tp;
6835796c8dcSSimon Schubert   int all = ptid_equal (ptid, minus_one_ptid);
6845796c8dcSSimon Schubert 
6855796c8dcSSimon Schubert   if (all || ptid_is_pid (ptid))
6865796c8dcSSimon Schubert     {
6875796c8dcSSimon Schubert       for (tp = thread_list; tp; tp = tp->next)
6885796c8dcSSimon Schubert 	if (all || ptid_get_pid (tp->ptid) == ptid_get_pid (ptid))
6895796c8dcSSimon Schubert 	  tp->stop_requested = stop;
6905796c8dcSSimon Schubert     }
6915796c8dcSSimon Schubert   else
6925796c8dcSSimon Schubert     {
6935796c8dcSSimon Schubert       tp = find_thread_ptid (ptid);
6945796c8dcSSimon Schubert       gdb_assert (tp);
6955796c8dcSSimon Schubert       tp->stop_requested = stop;
6965796c8dcSSimon Schubert     }
6975796c8dcSSimon Schubert 
6985796c8dcSSimon Schubert   /* Call the stop requested observer so other components of GDB can
6995796c8dcSSimon Schubert      react to this request.  */
7005796c8dcSSimon Schubert   if (stop)
7015796c8dcSSimon Schubert     observer_notify_thread_stop_requested (ptid);
7025796c8dcSSimon Schubert }
7035796c8dcSSimon Schubert 
7045796c8dcSSimon Schubert void
finish_thread_state(ptid_t ptid)7055796c8dcSSimon Schubert finish_thread_state (ptid_t ptid)
7065796c8dcSSimon Schubert {
7075796c8dcSSimon Schubert   struct thread_info *tp;
7085796c8dcSSimon Schubert   int all;
7095796c8dcSSimon Schubert   int any_started = 0;
7105796c8dcSSimon Schubert 
7115796c8dcSSimon Schubert   all = ptid_equal (ptid, minus_one_ptid);
7125796c8dcSSimon Schubert 
7135796c8dcSSimon Schubert   if (all || ptid_is_pid (ptid))
7145796c8dcSSimon Schubert     {
7155796c8dcSSimon Schubert       for (tp = thread_list; tp; tp = tp->next)
7165796c8dcSSimon Schubert 	{
717a45ae5f8SJohn Marino  	  if (tp->state == THREAD_EXITED)
7185796c8dcSSimon Schubert   	    continue;
7195796c8dcSSimon Schubert 	  if (all || ptid_get_pid (ptid) == ptid_get_pid (tp->ptid))
7205796c8dcSSimon Schubert 	    {
721a45ae5f8SJohn Marino 	      if (tp->executing && tp->state == THREAD_STOPPED)
7225796c8dcSSimon Schubert 		any_started = 1;
723a45ae5f8SJohn Marino 	      tp->state = tp->executing ? THREAD_RUNNING : THREAD_STOPPED;
7245796c8dcSSimon Schubert 	    }
7255796c8dcSSimon Schubert 	}
7265796c8dcSSimon Schubert     }
7275796c8dcSSimon Schubert   else
7285796c8dcSSimon Schubert     {
7295796c8dcSSimon Schubert       tp = find_thread_ptid (ptid);
7305796c8dcSSimon Schubert       gdb_assert (tp);
731a45ae5f8SJohn Marino       if (tp->state != THREAD_EXITED)
7325796c8dcSSimon Schubert 	{
733a45ae5f8SJohn Marino 	  if (tp->executing && tp->state == THREAD_STOPPED)
7345796c8dcSSimon Schubert 	    any_started = 1;
735a45ae5f8SJohn Marino 	  tp->state = tp->executing ? THREAD_RUNNING : THREAD_STOPPED;
7365796c8dcSSimon Schubert 	}
7375796c8dcSSimon Schubert     }
7385796c8dcSSimon Schubert 
7395796c8dcSSimon Schubert   if (any_started)
7405796c8dcSSimon Schubert     observer_notify_target_resumed (ptid);
7415796c8dcSSimon Schubert }
7425796c8dcSSimon Schubert 
7435796c8dcSSimon Schubert void
finish_thread_state_cleanup(void * arg)7445796c8dcSSimon Schubert finish_thread_state_cleanup (void *arg)
7455796c8dcSSimon Schubert {
7465796c8dcSSimon Schubert   ptid_t *ptid_p = arg;
7475796c8dcSSimon Schubert 
7485796c8dcSSimon Schubert   gdb_assert (arg);
7495796c8dcSSimon Schubert 
7505796c8dcSSimon Schubert   finish_thread_state (*ptid_p);
7515796c8dcSSimon Schubert }
7525796c8dcSSimon Schubert 
7535796c8dcSSimon Schubert /* Prints the list of threads and their details on UIOUT.
754c50c785cSJohn Marino    This is a version of 'info_threads_command' suitable for
7555796c8dcSSimon Schubert    use from MI.
7565796c8dcSSimon Schubert    If REQUESTED_THREAD is not -1, it's the GDB id of the thread
7575796c8dcSSimon Schubert    that should be printed.  Otherwise, all threads are
7585796c8dcSSimon Schubert    printed.
7595796c8dcSSimon Schubert    If PID is not -1, only print threads from the process PID.
7605796c8dcSSimon Schubert    Otherwise, threads from all attached PIDs are printed.
7615796c8dcSSimon Schubert    If both REQUESTED_THREAD and PID are not -1, then the thread
7625796c8dcSSimon Schubert    is printed if it belongs to the specified process.  Otherwise,
7635796c8dcSSimon Schubert    an error is raised.  */
7645796c8dcSSimon Schubert void
print_thread_info(struct ui_out * uiout,char * requested_threads,int pid)765c50c785cSJohn Marino print_thread_info (struct ui_out *uiout, char *requested_threads, int pid)
7665796c8dcSSimon Schubert {
7675796c8dcSSimon Schubert   struct thread_info *tp;
7685796c8dcSSimon Schubert   ptid_t current_ptid;
7695796c8dcSSimon Schubert   struct cleanup *old_chain;
770c50c785cSJohn Marino   char *extra_info, *name, *target_id;
7715796c8dcSSimon Schubert   int current_thread = -1;
7725796c8dcSSimon Schubert 
773cf7f2e2dSJohn Marino   update_thread_list ();
7745796c8dcSSimon Schubert   current_ptid = inferior_ptid;
7755796c8dcSSimon Schubert 
7765796c8dcSSimon Schubert   /* We'll be switching threads temporarily.  */
7775796c8dcSSimon Schubert   old_chain = make_cleanup_restore_current_thread ();
7785796c8dcSSimon Schubert 
779c50c785cSJohn Marino   /* For backward compatibility, we make a list for MI.  A table is
780c50c785cSJohn Marino      preferable for the CLI, though, because it shows table
781c50c785cSJohn Marino      headers.  */
782c50c785cSJohn Marino   if (ui_out_is_mi_like_p (uiout))
7835796c8dcSSimon Schubert     make_cleanup_ui_out_list_begin_end (uiout, "threads");
784c50c785cSJohn Marino   else
785c50c785cSJohn Marino     {
786c50c785cSJohn Marino       int n_threads = 0;
787c50c785cSJohn Marino 
788c50c785cSJohn Marino       for (tp = thread_list; tp; tp = tp->next)
789c50c785cSJohn Marino 	{
790c50c785cSJohn Marino 	  if (!number_is_in_list (requested_threads, tp->num))
791c50c785cSJohn Marino 	    continue;
792c50c785cSJohn Marino 
793c50c785cSJohn Marino 	  if (pid != -1 && PIDGET (tp->ptid) != pid)
794c50c785cSJohn Marino 	    continue;
795c50c785cSJohn Marino 
796a45ae5f8SJohn Marino 	  if (tp->state == THREAD_EXITED)
797c50c785cSJohn Marino 	    continue;
798c50c785cSJohn Marino 
799c50c785cSJohn Marino 	  ++n_threads;
800c50c785cSJohn Marino 	}
801c50c785cSJohn Marino 
802c50c785cSJohn Marino       if (n_threads == 0)
803c50c785cSJohn Marino 	{
804c50c785cSJohn Marino 	  if (requested_threads == NULL || *requested_threads == '\0')
805c50c785cSJohn Marino 	    ui_out_message (uiout, 0, _("No threads.\n"));
806c50c785cSJohn Marino 	  else
807c50c785cSJohn Marino 	    ui_out_message (uiout, 0, _("No threads match '%s'.\n"),
808c50c785cSJohn Marino 			    requested_threads);
809c50c785cSJohn Marino 	  do_cleanups (old_chain);
810c50c785cSJohn Marino 	  return;
811c50c785cSJohn Marino 	}
812c50c785cSJohn Marino 
813c50c785cSJohn Marino       make_cleanup_ui_out_table_begin_end (uiout, 4, n_threads, "threads");
814c50c785cSJohn Marino 
815c50c785cSJohn Marino       ui_out_table_header (uiout, 1, ui_left, "current", "");
816c50c785cSJohn Marino       ui_out_table_header (uiout, 4, ui_left, "id", "Id");
817c50c785cSJohn Marino       ui_out_table_header (uiout, 17, ui_left, "target-id", "Target Id");
818c50c785cSJohn Marino       ui_out_table_header (uiout, 1, ui_left, "frame", "Frame");
819c50c785cSJohn Marino       ui_out_table_body (uiout);
820c50c785cSJohn Marino     }
821c50c785cSJohn Marino 
8225796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
8235796c8dcSSimon Schubert     {
8245796c8dcSSimon Schubert       struct cleanup *chain2;
825cf7f2e2dSJohn Marino       int core;
8265796c8dcSSimon Schubert 
827c50c785cSJohn Marino       if (!number_is_in_list (requested_threads, tp->num))
8285796c8dcSSimon Schubert 	continue;
8295796c8dcSSimon Schubert 
8305796c8dcSSimon Schubert       if (pid != -1 && PIDGET (tp->ptid) != pid)
8315796c8dcSSimon Schubert 	{
832c50c785cSJohn Marino 	  if (requested_threads != NULL && *requested_threads != '\0')
8335796c8dcSSimon Schubert 	    error (_("Requested thread not found in requested process"));
8345796c8dcSSimon Schubert 	  continue;
8355796c8dcSSimon Schubert 	}
8365796c8dcSSimon Schubert 
8375796c8dcSSimon Schubert       if (ptid_equal (tp->ptid, current_ptid))
8385796c8dcSSimon Schubert 	current_thread = tp->num;
8395796c8dcSSimon Schubert 
840a45ae5f8SJohn Marino       if (tp->state == THREAD_EXITED)
8415796c8dcSSimon Schubert 	continue;
8425796c8dcSSimon Schubert 
8435796c8dcSSimon Schubert       chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
8445796c8dcSSimon Schubert 
845c50c785cSJohn Marino       if (ui_out_is_mi_like_p (uiout))
846c50c785cSJohn Marino 	{
847c50c785cSJohn Marino 	  /* Compatibility.  */
8485796c8dcSSimon Schubert 	  if (ptid_equal (tp->ptid, current_ptid))
8495796c8dcSSimon Schubert 	    ui_out_text (uiout, "* ");
8505796c8dcSSimon Schubert 	  else
8515796c8dcSSimon Schubert 	    ui_out_text (uiout, "  ");
852c50c785cSJohn Marino 	}
853c50c785cSJohn Marino       else
854c50c785cSJohn Marino 	{
855c50c785cSJohn Marino 	  if (ptid_equal (tp->ptid, current_ptid))
856c50c785cSJohn Marino 	    ui_out_field_string (uiout, "current", "*");
857c50c785cSJohn Marino 	  else
858c50c785cSJohn Marino 	    ui_out_field_skip (uiout, "current");
859c50c785cSJohn Marino 	}
8605796c8dcSSimon Schubert 
8615796c8dcSSimon Schubert       ui_out_field_int (uiout, "id", tp->num);
8625796c8dcSSimon Schubert 
863c50c785cSJohn Marino       /* For the CLI, we stuff everything into the target-id field.
864c50c785cSJohn Marino 	 This is a gross hack to make the output come out looking
865c50c785cSJohn Marino 	 correct.  The underlying problem here is that ui-out has no
866c50c785cSJohn Marino 	 way to specify that a field's space allocation should be
867c50c785cSJohn Marino 	 shared by several fields.  For MI, we do the right thing
868c50c785cSJohn Marino 	 instead.  */
869c50c785cSJohn Marino 
870c50c785cSJohn Marino       target_id = target_pid_to_str (tp->ptid);
8715796c8dcSSimon Schubert       extra_info = target_extra_thread_info (tp);
872c50c785cSJohn Marino       name = tp->name ? tp->name : target_thread_name (tp);
873c50c785cSJohn Marino 
874c50c785cSJohn Marino       if (ui_out_is_mi_like_p (uiout))
8755796c8dcSSimon Schubert 	{
876c50c785cSJohn Marino 	  ui_out_field_string (uiout, "target-id", target_id);
877c50c785cSJohn Marino 	  if (extra_info)
8785796c8dcSSimon Schubert 	    ui_out_field_string (uiout, "details", extra_info);
879c50c785cSJohn Marino 	  if (name)
880c50c785cSJohn Marino 	    ui_out_field_string (uiout, "name", name);
8815796c8dcSSimon Schubert 	}
882c50c785cSJohn Marino       else
883c50c785cSJohn Marino 	{
884c50c785cSJohn Marino 	  struct cleanup *str_cleanup;
885c50c785cSJohn Marino 	  char *contents;
886c50c785cSJohn Marino 
887c50c785cSJohn Marino 	  if (extra_info && name)
888c50c785cSJohn Marino 	    contents = xstrprintf ("%s \"%s\" (%s)", target_id,
889c50c785cSJohn Marino 				   name, extra_info);
890c50c785cSJohn Marino 	  else if (extra_info)
891c50c785cSJohn Marino 	    contents = xstrprintf ("%s (%s)", target_id, extra_info);
892c50c785cSJohn Marino 	  else if (name)
893c50c785cSJohn Marino 	    contents = xstrprintf ("%s \"%s\"", target_id, name);
894c50c785cSJohn Marino 	  else
895c50c785cSJohn Marino 	    contents = xstrdup (target_id);
896c50c785cSJohn Marino 	  str_cleanup = make_cleanup (xfree, contents);
897c50c785cSJohn Marino 
898c50c785cSJohn Marino 	  ui_out_field_string (uiout, "target-id", contents);
899c50c785cSJohn Marino 	  do_cleanups (str_cleanup);
900c50c785cSJohn Marino 	}
9015796c8dcSSimon Schubert 
902a45ae5f8SJohn Marino       if (tp->state == THREAD_RUNNING)
9035796c8dcSSimon Schubert 	ui_out_text (uiout, "(running)\n");
9045796c8dcSSimon Schubert       else
9055796c8dcSSimon Schubert 	{
9065796c8dcSSimon Schubert 	  /* The switch below puts us at the top of the stack (leaf
9075796c8dcSSimon Schubert 	     frame).  */
9085796c8dcSSimon Schubert 	  switch_to_thread (tp->ptid);
9095796c8dcSSimon Schubert 	  print_stack_frame (get_selected_frame (NULL),
9105796c8dcSSimon Schubert 			     /* For MI output, print frame level.  */
9115796c8dcSSimon Schubert 			     ui_out_is_mi_like_p (uiout),
9125796c8dcSSimon Schubert 			     LOCATION);
9135796c8dcSSimon Schubert 	}
9145796c8dcSSimon Schubert 
9155796c8dcSSimon Schubert       if (ui_out_is_mi_like_p (uiout))
9165796c8dcSSimon Schubert 	{
9175796c8dcSSimon Schubert 	  char *state = "stopped";
918cf7f2e2dSJohn Marino 
919a45ae5f8SJohn Marino 	  if (tp->state == THREAD_RUNNING)
9205796c8dcSSimon Schubert 	    state = "running";
9215796c8dcSSimon Schubert 	  ui_out_field_string (uiout, "state", state);
9225796c8dcSSimon Schubert 	}
9235796c8dcSSimon Schubert 
924cf7f2e2dSJohn Marino       core = target_core_of_thread (tp->ptid);
925cf7f2e2dSJohn Marino       if (ui_out_is_mi_like_p (uiout) && core != -1)
926cf7f2e2dSJohn Marino 	ui_out_field_int (uiout, "core", core);
927cf7f2e2dSJohn Marino 
9285796c8dcSSimon Schubert       do_cleanups (chain2);
9295796c8dcSSimon Schubert     }
9305796c8dcSSimon Schubert 
9315796c8dcSSimon Schubert   /* Restores the current thread and the frame selected before
9325796c8dcSSimon Schubert      the "info threads" command.  */
9335796c8dcSSimon Schubert   do_cleanups (old_chain);
9345796c8dcSSimon Schubert 
935c50c785cSJohn Marino   if (pid == -1 && requested_threads == NULL)
9365796c8dcSSimon Schubert     {
9375796c8dcSSimon Schubert       gdb_assert (current_thread != -1
9385796c8dcSSimon Schubert 		  || !thread_list
9395796c8dcSSimon Schubert 		  || ptid_equal (inferior_ptid, null_ptid));
9405796c8dcSSimon Schubert       if (current_thread != -1 && ui_out_is_mi_like_p (uiout))
9415796c8dcSSimon Schubert 	ui_out_field_int (uiout, "current-thread-id", current_thread);
9425796c8dcSSimon Schubert 
9435796c8dcSSimon Schubert       if (current_thread != -1 && is_exited (current_ptid))
9445796c8dcSSimon Schubert 	ui_out_message (uiout, 0, "\n\
9455796c8dcSSimon Schubert The current thread <Thread ID %d> has terminated.  See `help thread'.\n",
9465796c8dcSSimon Schubert 			current_thread);
9475796c8dcSSimon Schubert       else if (thread_list
9485796c8dcSSimon Schubert 	       && current_thread == -1
9495796c8dcSSimon Schubert 	       && ptid_equal (current_ptid, null_ptid))
9505796c8dcSSimon Schubert 	ui_out_message (uiout, 0, "\n\
9515796c8dcSSimon Schubert No selected thread.  See `help thread'.\n");
9525796c8dcSSimon Schubert     }
9535796c8dcSSimon Schubert }
9545796c8dcSSimon Schubert 
9555796c8dcSSimon Schubert /* Print information about currently known threads
9565796c8dcSSimon Schubert 
957c50c785cSJohn Marino    Optional ARG is a thread id, or list of thread ids.
958c50c785cSJohn Marino 
959c50c785cSJohn Marino    Note: this has the drawback that it _really_ switches
960c50c785cSJohn Marino          threads, which frees the frame cache.  A no-side
961c50c785cSJohn Marino          effects info-threads command would be nicer.  */
9625796c8dcSSimon Schubert 
9635796c8dcSSimon Schubert static void
info_threads_command(char * arg,int from_tty)9645796c8dcSSimon Schubert info_threads_command (char *arg, int from_tty)
9655796c8dcSSimon Schubert {
966a45ae5f8SJohn Marino   print_thread_info (current_uiout, arg, -1);
9675796c8dcSSimon Schubert }
9685796c8dcSSimon Schubert 
9695796c8dcSSimon Schubert /* Switch from one thread to another.  */
9705796c8dcSSimon Schubert 
9715796c8dcSSimon Schubert void
switch_to_thread(ptid_t ptid)9725796c8dcSSimon Schubert switch_to_thread (ptid_t ptid)
9735796c8dcSSimon Schubert {
974cf7f2e2dSJohn Marino   /* Switch the program space as well, if we can infer it from the now
975cf7f2e2dSJohn Marino      current thread.  Otherwise, it's up to the caller to select the
976cf7f2e2dSJohn Marino      space it wants.  */
977cf7f2e2dSJohn Marino   if (!ptid_equal (ptid, null_ptid))
978cf7f2e2dSJohn Marino     {
979cf7f2e2dSJohn Marino       struct inferior *inf;
980cf7f2e2dSJohn Marino 
981cf7f2e2dSJohn Marino       inf = find_inferior_pid (ptid_get_pid (ptid));
982cf7f2e2dSJohn Marino       gdb_assert (inf != NULL);
983cf7f2e2dSJohn Marino       set_current_program_space (inf->pspace);
984cf7f2e2dSJohn Marino       set_current_inferior (inf);
985cf7f2e2dSJohn Marino     }
986cf7f2e2dSJohn Marino 
9875796c8dcSSimon Schubert   if (ptid_equal (ptid, inferior_ptid))
9885796c8dcSSimon Schubert     return;
9895796c8dcSSimon Schubert 
9905796c8dcSSimon Schubert   inferior_ptid = ptid;
9915796c8dcSSimon Schubert   reinit_frame_cache ();
9925796c8dcSSimon Schubert 
9935796c8dcSSimon Schubert   /* We don't check for is_stopped, because we're called at times
9945796c8dcSSimon Schubert      while in the TARGET_RUNNING state, e.g., while handling an
9955796c8dcSSimon Schubert      internal event.  */
9965796c8dcSSimon Schubert   if (!ptid_equal (inferior_ptid, null_ptid)
9975796c8dcSSimon Schubert       && !is_exited (ptid)
9985796c8dcSSimon Schubert       && !is_executing (ptid))
9995796c8dcSSimon Schubert     stop_pc = regcache_read_pc (get_thread_regcache (ptid));
10005796c8dcSSimon Schubert   else
10015796c8dcSSimon Schubert     stop_pc = ~(CORE_ADDR) 0;
10025796c8dcSSimon Schubert }
10035796c8dcSSimon Schubert 
10045796c8dcSSimon Schubert static void
restore_current_thread(ptid_t ptid)10055796c8dcSSimon Schubert restore_current_thread (ptid_t ptid)
10065796c8dcSSimon Schubert {
10075796c8dcSSimon Schubert   switch_to_thread (ptid);
10085796c8dcSSimon Schubert }
10095796c8dcSSimon Schubert 
10105796c8dcSSimon Schubert static void
restore_selected_frame(struct frame_id a_frame_id,int frame_level)10115796c8dcSSimon Schubert restore_selected_frame (struct frame_id a_frame_id, int frame_level)
10125796c8dcSSimon Schubert {
10135796c8dcSSimon Schubert   struct frame_info *frame = NULL;
10145796c8dcSSimon Schubert   int count;
10155796c8dcSSimon Schubert 
1016c50c785cSJohn Marino   /* This means there was no selected frame.  */
1017c50c785cSJohn Marino   if (frame_level == -1)
1018c50c785cSJohn Marino     {
1019c50c785cSJohn Marino       select_frame (NULL);
1020c50c785cSJohn Marino       return;
1021c50c785cSJohn Marino     }
1022c50c785cSJohn Marino 
10235796c8dcSSimon Schubert   gdb_assert (frame_level >= 0);
10245796c8dcSSimon Schubert 
10255796c8dcSSimon Schubert   /* Restore by level first, check if the frame id is the same as
10265796c8dcSSimon Schubert      expected.  If that fails, try restoring by frame id.  If that
10275796c8dcSSimon Schubert      fails, nothing to do, just warn the user.  */
10285796c8dcSSimon Schubert 
10295796c8dcSSimon Schubert   count = frame_level;
10305796c8dcSSimon Schubert   frame = find_relative_frame (get_current_frame (), &count);
10315796c8dcSSimon Schubert   if (count == 0
10325796c8dcSSimon Schubert       && frame != NULL
10335796c8dcSSimon Schubert       /* The frame ids must match - either both valid or both outer_frame_id.
10345796c8dcSSimon Schubert 	 The latter case is not failsafe, but since it's highly unlikely
10355796c8dcSSimon Schubert 	 the search by level finds the wrong frame, it's 99.9(9)% of
10365796c8dcSSimon Schubert 	 the time (for all practical purposes) safe.  */
10375796c8dcSSimon Schubert       && frame_id_eq (get_frame_id (frame), a_frame_id))
10385796c8dcSSimon Schubert     {
10395796c8dcSSimon Schubert       /* Cool, all is fine.  */
10405796c8dcSSimon Schubert       select_frame (frame);
10415796c8dcSSimon Schubert       return;
10425796c8dcSSimon Schubert     }
10435796c8dcSSimon Schubert 
10445796c8dcSSimon Schubert   frame = frame_find_by_id (a_frame_id);
10455796c8dcSSimon Schubert   if (frame != NULL)
10465796c8dcSSimon Schubert     {
10475796c8dcSSimon Schubert       /* Cool, refound it.  */
10485796c8dcSSimon Schubert       select_frame (frame);
10495796c8dcSSimon Schubert       return;
10505796c8dcSSimon Schubert     }
10515796c8dcSSimon Schubert 
10525796c8dcSSimon Schubert   /* Nothing else to do, the frame layout really changed.  Select the
10535796c8dcSSimon Schubert      innermost stack frame.  */
10545796c8dcSSimon Schubert   select_frame (get_current_frame ());
10555796c8dcSSimon Schubert 
10565796c8dcSSimon Schubert   /* Warn the user.  */
1057a45ae5f8SJohn Marino   if (frame_level > 0 && !ui_out_is_mi_like_p (current_uiout))
10585796c8dcSSimon Schubert     {
1059c50c785cSJohn Marino       warning (_("Couldn't restore frame #%d in "
1060c50c785cSJohn Marino 		 "current thread, at reparsed frame #0\n"),
10615796c8dcSSimon Schubert 	       frame_level);
10625796c8dcSSimon Schubert       /* For MI, we should probably have a notification about
10635796c8dcSSimon Schubert 	 current frame change.  But this error is not very
10645796c8dcSSimon Schubert 	 likely, so don't bother for now.  */
10655796c8dcSSimon Schubert       print_stack_frame (get_selected_frame (NULL), 1, SRC_LINE);
10665796c8dcSSimon Schubert     }
10675796c8dcSSimon Schubert }
10685796c8dcSSimon Schubert 
10695796c8dcSSimon Schubert struct current_thread_cleanup
10705796c8dcSSimon Schubert {
10715796c8dcSSimon Schubert   ptid_t inferior_ptid;
10725796c8dcSSimon Schubert   struct frame_id selected_frame_id;
10735796c8dcSSimon Schubert   int selected_frame_level;
10745796c8dcSSimon Schubert   int was_stopped;
1075cf7f2e2dSJohn Marino   int inf_id;
1076*ef5ccd6cSJohn Marino   int was_removable;
10775796c8dcSSimon Schubert };
10785796c8dcSSimon Schubert 
10795796c8dcSSimon Schubert static void
do_restore_current_thread_cleanup(void * arg)10805796c8dcSSimon Schubert do_restore_current_thread_cleanup (void *arg)
10815796c8dcSSimon Schubert {
10825796c8dcSSimon Schubert   struct thread_info *tp;
10835796c8dcSSimon Schubert   struct current_thread_cleanup *old = arg;
10845796c8dcSSimon Schubert 
10855796c8dcSSimon Schubert   tp = find_thread_ptid (old->inferior_ptid);
10865796c8dcSSimon Schubert 
10875796c8dcSSimon Schubert   /* If the previously selected thread belonged to a process that has
10885796c8dcSSimon Schubert      in the mean time been deleted (due to normal exit, detach, etc.),
10895796c8dcSSimon Schubert      then don't revert back to it, but instead simply drop back to no
10905796c8dcSSimon Schubert      thread selected.  */
10915796c8dcSSimon Schubert   if (tp
10925796c8dcSSimon Schubert       && find_inferior_pid (ptid_get_pid (tp->ptid)) != NULL)
10935796c8dcSSimon Schubert     restore_current_thread (old->inferior_ptid);
10945796c8dcSSimon Schubert   else
1095cf7f2e2dSJohn Marino     {
10965796c8dcSSimon Schubert       restore_current_thread (null_ptid);
1097cf7f2e2dSJohn Marino       set_current_inferior (find_inferior_id (old->inf_id));
1098cf7f2e2dSJohn Marino     }
10995796c8dcSSimon Schubert 
11005796c8dcSSimon Schubert   /* The running state of the originally selected thread may have
11015796c8dcSSimon Schubert      changed, so we have to recheck it here.  */
11025796c8dcSSimon Schubert   if (!ptid_equal (inferior_ptid, null_ptid)
11035796c8dcSSimon Schubert       && old->was_stopped
11045796c8dcSSimon Schubert       && is_stopped (inferior_ptid)
11055796c8dcSSimon Schubert       && target_has_registers
11065796c8dcSSimon Schubert       && target_has_stack
11075796c8dcSSimon Schubert       && target_has_memory)
11085796c8dcSSimon Schubert     restore_selected_frame (old->selected_frame_id,
11095796c8dcSSimon Schubert 			    old->selected_frame_level);
11105796c8dcSSimon Schubert }
11115796c8dcSSimon Schubert 
11125796c8dcSSimon Schubert static void
restore_current_thread_cleanup_dtor(void * arg)11135796c8dcSSimon Schubert restore_current_thread_cleanup_dtor (void *arg)
11145796c8dcSSimon Schubert {
11155796c8dcSSimon Schubert   struct current_thread_cleanup *old = arg;
11165796c8dcSSimon Schubert   struct thread_info *tp;
1117*ef5ccd6cSJohn Marino   struct inferior *inf;
1118cf7f2e2dSJohn Marino 
11195796c8dcSSimon Schubert   tp = find_thread_ptid (old->inferior_ptid);
11205796c8dcSSimon Schubert   if (tp)
11215796c8dcSSimon Schubert     tp->refcount--;
1122*ef5ccd6cSJohn Marino   inf = find_inferior_id (old->inf_id);
1123*ef5ccd6cSJohn Marino   if (inf != NULL)
1124*ef5ccd6cSJohn Marino     inf->removable = old->was_removable;
11255796c8dcSSimon Schubert   xfree (old);
11265796c8dcSSimon Schubert }
11275796c8dcSSimon Schubert 
11285796c8dcSSimon Schubert struct cleanup *
make_cleanup_restore_current_thread(void)11295796c8dcSSimon Schubert make_cleanup_restore_current_thread (void)
11305796c8dcSSimon Schubert {
11315796c8dcSSimon Schubert   struct thread_info *tp;
11325796c8dcSSimon Schubert   struct frame_info *frame;
11335796c8dcSSimon Schubert   struct current_thread_cleanup *old;
11345796c8dcSSimon Schubert 
11355796c8dcSSimon Schubert   old = xmalloc (sizeof (struct current_thread_cleanup));
11365796c8dcSSimon Schubert   old->inferior_ptid = inferior_ptid;
1137cf7f2e2dSJohn Marino   old->inf_id = current_inferior ()->num;
1138*ef5ccd6cSJohn Marino   old->was_removable = current_inferior ()->removable;
11395796c8dcSSimon Schubert 
11405796c8dcSSimon Schubert   if (!ptid_equal (inferior_ptid, null_ptid))
11415796c8dcSSimon Schubert     {
11425796c8dcSSimon Schubert       old->was_stopped = is_stopped (inferior_ptid);
11435796c8dcSSimon Schubert       if (old->was_stopped
11445796c8dcSSimon Schubert 	  && target_has_registers
11455796c8dcSSimon Schubert 	  && target_has_stack
11465796c8dcSSimon Schubert 	  && target_has_memory)
1147c50c785cSJohn Marino 	{
1148c50c785cSJohn Marino 	  /* When processing internal events, there might not be a
1149c50c785cSJohn Marino 	     selected frame.  If we naively call get_selected_frame
1150c50c785cSJohn Marino 	     here, then we can end up reading debuginfo for the
1151c50c785cSJohn Marino 	     current frame, but we don't generally need the debuginfo
1152c50c785cSJohn Marino 	     at this point.  */
1153c50c785cSJohn Marino 	  frame = get_selected_frame_if_set ();
1154c50c785cSJohn Marino 	}
11555796c8dcSSimon Schubert       else
11565796c8dcSSimon Schubert 	frame = NULL;
11575796c8dcSSimon Schubert 
11585796c8dcSSimon Schubert       old->selected_frame_id = get_frame_id (frame);
11595796c8dcSSimon Schubert       old->selected_frame_level = frame_relative_level (frame);
11605796c8dcSSimon Schubert 
11615796c8dcSSimon Schubert       tp = find_thread_ptid (inferior_ptid);
11625796c8dcSSimon Schubert       if (tp)
11635796c8dcSSimon Schubert 	tp->refcount++;
11645796c8dcSSimon Schubert     }
11655796c8dcSSimon Schubert 
1166*ef5ccd6cSJohn Marino   current_inferior ()->removable = 0;
1167*ef5ccd6cSJohn Marino 
11685796c8dcSSimon Schubert   return make_cleanup_dtor (do_restore_current_thread_cleanup, old,
11695796c8dcSSimon Schubert 			    restore_current_thread_cleanup_dtor);
11705796c8dcSSimon Schubert }
11715796c8dcSSimon Schubert 
11725796c8dcSSimon Schubert /* Apply a GDB command to a list of threads.  List syntax is a whitespace
11735796c8dcSSimon Schubert    seperated list of numbers, or ranges, or the keyword `all'.  Ranges consist
11745796c8dcSSimon Schubert    of two numbers seperated by a hyphen.  Examples:
11755796c8dcSSimon Schubert 
11765796c8dcSSimon Schubert    thread apply 1 2 7 4 backtrace       Apply backtrace cmd to threads 1,2,7,4
11775796c8dcSSimon Schubert    thread apply 2-7 9 p foo(1)  Apply p foo(1) cmd to threads 2->7 & 9
1178c50c785cSJohn Marino    thread apply all p x/i $pc   Apply x/i $pc cmd to all threads.  */
11795796c8dcSSimon Schubert 
11805796c8dcSSimon Schubert static void
thread_apply_all_command(char * cmd,int from_tty)11815796c8dcSSimon Schubert thread_apply_all_command (char *cmd, int from_tty)
11825796c8dcSSimon Schubert {
11835796c8dcSSimon Schubert   struct thread_info *tp;
11845796c8dcSSimon Schubert   struct cleanup *old_chain;
11855796c8dcSSimon Schubert   char *saved_cmd;
11865796c8dcSSimon Schubert 
11875796c8dcSSimon Schubert   if (cmd == NULL || *cmd == '\000')
11885796c8dcSSimon Schubert     error (_("Please specify a command following the thread ID list"));
11895796c8dcSSimon Schubert 
1190cf7f2e2dSJohn Marino   update_thread_list ();
11915796c8dcSSimon Schubert 
11925796c8dcSSimon Schubert   old_chain = make_cleanup_restore_current_thread ();
11935796c8dcSSimon Schubert 
11945796c8dcSSimon Schubert   /* Save a copy of the command in case it is clobbered by
1195c50c785cSJohn Marino      execute_command.  */
11965796c8dcSSimon Schubert   saved_cmd = xstrdup (cmd);
11975796c8dcSSimon Schubert   make_cleanup (xfree, saved_cmd);
11985796c8dcSSimon Schubert   for (tp = thread_list; tp; tp = tp->next)
11995796c8dcSSimon Schubert     if (thread_alive (tp))
12005796c8dcSSimon Schubert       {
12015796c8dcSSimon Schubert 	switch_to_thread (tp->ptid);
12025796c8dcSSimon Schubert 
12035796c8dcSSimon Schubert 	printf_filtered (_("\nThread %d (%s):\n"),
12045796c8dcSSimon Schubert 			 tp->num, target_pid_to_str (inferior_ptid));
12055796c8dcSSimon Schubert 	execute_command (cmd, from_tty);
1206c50c785cSJohn Marino 	strcpy (cmd, saved_cmd);	/* Restore exact command used
1207c50c785cSJohn Marino 					   previously.  */
12085796c8dcSSimon Schubert       }
12095796c8dcSSimon Schubert 
12105796c8dcSSimon Schubert   do_cleanups (old_chain);
12115796c8dcSSimon Schubert }
12125796c8dcSSimon Schubert 
12135796c8dcSSimon Schubert static void
thread_apply_command(char * tidlist,int from_tty)12145796c8dcSSimon Schubert thread_apply_command (char *tidlist, int from_tty)
12155796c8dcSSimon Schubert {
12165796c8dcSSimon Schubert   char *cmd;
12175796c8dcSSimon Schubert   struct cleanup *old_chain;
12185796c8dcSSimon Schubert   char *saved_cmd;
1219c50c785cSJohn Marino   struct get_number_or_range_state state;
12205796c8dcSSimon Schubert 
12215796c8dcSSimon Schubert   if (tidlist == NULL || *tidlist == '\000')
12225796c8dcSSimon Schubert     error (_("Please specify a thread ID list"));
12235796c8dcSSimon Schubert 
12245796c8dcSSimon Schubert   for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++);
12255796c8dcSSimon Schubert 
12265796c8dcSSimon Schubert   if (*cmd == '\000')
12275796c8dcSSimon Schubert     error (_("Please specify a command following the thread ID list"));
12285796c8dcSSimon Schubert 
12295796c8dcSSimon Schubert   /* Save a copy of the command in case it is clobbered by
1230c50c785cSJohn Marino      execute_command.  */
12315796c8dcSSimon Schubert   saved_cmd = xstrdup (cmd);
12325796c8dcSSimon Schubert   old_chain = make_cleanup (xfree, saved_cmd);
1233c50c785cSJohn Marino 
1234c50c785cSJohn Marino   init_number_or_range (&state, tidlist);
1235c50c785cSJohn Marino   while (!state.finished && state.string < cmd)
12365796c8dcSSimon Schubert     {
12375796c8dcSSimon Schubert       struct thread_info *tp;
1238c50c785cSJohn Marino       int start;
12395796c8dcSSimon Schubert 
1240c50c785cSJohn Marino       start = get_number_or_range (&state);
12415796c8dcSSimon Schubert 
12425796c8dcSSimon Schubert       make_cleanup_restore_current_thread ();
12435796c8dcSSimon Schubert 
12445796c8dcSSimon Schubert       tp = find_thread_id (start);
12455796c8dcSSimon Schubert 
12465796c8dcSSimon Schubert       if (!tp)
12475796c8dcSSimon Schubert 	warning (_("Unknown thread %d."), start);
12485796c8dcSSimon Schubert       else if (!thread_alive (tp))
12495796c8dcSSimon Schubert 	warning (_("Thread %d has terminated."), start);
12505796c8dcSSimon Schubert       else
12515796c8dcSSimon Schubert 	{
12525796c8dcSSimon Schubert 	  switch_to_thread (tp->ptid);
12535796c8dcSSimon Schubert 
12545796c8dcSSimon Schubert 	  printf_filtered (_("\nThread %d (%s):\n"), tp->num,
12555796c8dcSSimon Schubert 			   target_pid_to_str (inferior_ptid));
12565796c8dcSSimon Schubert 	  execute_command (cmd, from_tty);
12575796c8dcSSimon Schubert 
12585796c8dcSSimon Schubert 	  /* Restore exact command used previously.  */
12595796c8dcSSimon Schubert 	  strcpy (cmd, saved_cmd);
12605796c8dcSSimon Schubert 	}
12615796c8dcSSimon Schubert     }
12625796c8dcSSimon Schubert 
12635796c8dcSSimon Schubert   do_cleanups (old_chain);
12645796c8dcSSimon Schubert }
12655796c8dcSSimon Schubert 
12665796c8dcSSimon Schubert /* Switch to the specified thread.  Will dispatch off to thread_apply_command
12675796c8dcSSimon Schubert    if prefix of arg is `apply'.  */
12685796c8dcSSimon Schubert 
12695796c8dcSSimon Schubert static void
thread_command(char * tidstr,int from_tty)12705796c8dcSSimon Schubert thread_command (char *tidstr, int from_tty)
12715796c8dcSSimon Schubert {
12725796c8dcSSimon Schubert   if (!tidstr)
12735796c8dcSSimon Schubert     {
12745796c8dcSSimon Schubert       if (ptid_equal (inferior_ptid, null_ptid))
12755796c8dcSSimon Schubert 	error (_("No thread selected"));
12765796c8dcSSimon Schubert 
12775796c8dcSSimon Schubert       if (target_has_stack)
12785796c8dcSSimon Schubert 	{
12795796c8dcSSimon Schubert 	  if (is_exited (inferior_ptid))
12805796c8dcSSimon Schubert 	    printf_filtered (_("[Current thread is %d (%s) (exited)]\n"),
12815796c8dcSSimon Schubert 			     pid_to_thread_id (inferior_ptid),
12825796c8dcSSimon Schubert 			     target_pid_to_str (inferior_ptid));
12835796c8dcSSimon Schubert 	  else
12845796c8dcSSimon Schubert 	    printf_filtered (_("[Current thread is %d (%s)]\n"),
12855796c8dcSSimon Schubert 			     pid_to_thread_id (inferior_ptid),
12865796c8dcSSimon Schubert 			     target_pid_to_str (inferior_ptid));
12875796c8dcSSimon Schubert 	}
12885796c8dcSSimon Schubert       else
12895796c8dcSSimon Schubert 	error (_("No stack."));
12905796c8dcSSimon Schubert       return;
12915796c8dcSSimon Schubert     }
12925796c8dcSSimon Schubert 
1293a45ae5f8SJohn Marino   gdb_thread_select (current_uiout, tidstr, NULL);
12945796c8dcSSimon Schubert }
12955796c8dcSSimon Schubert 
1296c50c785cSJohn Marino /* Implementation of `thread name'.  */
1297c50c785cSJohn Marino 
1298c50c785cSJohn Marino static void
thread_name_command(char * arg,int from_tty)1299c50c785cSJohn Marino thread_name_command (char *arg, int from_tty)
1300c50c785cSJohn Marino {
1301c50c785cSJohn Marino   struct thread_info *info;
1302c50c785cSJohn Marino 
1303c50c785cSJohn Marino   if (ptid_equal (inferior_ptid, null_ptid))
1304c50c785cSJohn Marino     error (_("No thread selected"));
1305c50c785cSJohn Marino 
1306*ef5ccd6cSJohn Marino   arg = skip_spaces (arg);
1307c50c785cSJohn Marino 
1308c50c785cSJohn Marino   info = inferior_thread ();
1309c50c785cSJohn Marino   xfree (info->name);
1310c50c785cSJohn Marino   info->name = arg ? xstrdup (arg) : NULL;
1311c50c785cSJohn Marino }
1312c50c785cSJohn Marino 
1313c50c785cSJohn Marino /* Find thread ids with a name, target pid, or extra info matching ARG.  */
1314c50c785cSJohn Marino 
1315c50c785cSJohn Marino static void
thread_find_command(char * arg,int from_tty)1316c50c785cSJohn Marino thread_find_command (char *arg, int from_tty)
1317c50c785cSJohn Marino {
1318c50c785cSJohn Marino   struct thread_info *tp;
1319c50c785cSJohn Marino   char *tmp;
1320c50c785cSJohn Marino   unsigned long match = 0;
1321c50c785cSJohn Marino 
1322c50c785cSJohn Marino   if (arg == NULL || *arg == '\0')
1323c50c785cSJohn Marino     error (_("Command requires an argument."));
1324c50c785cSJohn Marino 
1325c50c785cSJohn Marino   tmp = re_comp (arg);
1326c50c785cSJohn Marino   if (tmp != 0)
1327c50c785cSJohn Marino     error (_("Invalid regexp (%s): %s"), tmp, arg);
1328c50c785cSJohn Marino 
1329c50c785cSJohn Marino   update_thread_list ();
1330c50c785cSJohn Marino   for (tp = thread_list; tp; tp = tp->next)
1331c50c785cSJohn Marino     {
1332c50c785cSJohn Marino       if (tp->name != NULL && re_exec (tp->name))
1333c50c785cSJohn Marino 	{
1334c50c785cSJohn Marino 	  printf_filtered (_("Thread %d has name '%s'\n"),
1335c50c785cSJohn Marino 			   tp->num, tp->name);
1336c50c785cSJohn Marino 	  match++;
1337c50c785cSJohn Marino 	}
1338c50c785cSJohn Marino 
1339c50c785cSJohn Marino       tmp = target_thread_name (tp);
1340c50c785cSJohn Marino       if (tmp != NULL && re_exec (tmp))
1341c50c785cSJohn Marino 	{
1342c50c785cSJohn Marino 	  printf_filtered (_("Thread %d has target name '%s'\n"),
1343c50c785cSJohn Marino 			   tp->num, tmp);
1344c50c785cSJohn Marino 	  match++;
1345c50c785cSJohn Marino 	}
1346c50c785cSJohn Marino 
1347c50c785cSJohn Marino       tmp = target_pid_to_str (tp->ptid);
1348c50c785cSJohn Marino       if (tmp != NULL && re_exec (tmp))
1349c50c785cSJohn Marino 	{
1350c50c785cSJohn Marino 	  printf_filtered (_("Thread %d has target id '%s'\n"),
1351c50c785cSJohn Marino 			   tp->num, tmp);
1352c50c785cSJohn Marino 	  match++;
1353c50c785cSJohn Marino 	}
1354c50c785cSJohn Marino 
1355c50c785cSJohn Marino       tmp = target_extra_thread_info (tp);
1356c50c785cSJohn Marino       if (tmp != NULL && re_exec (tmp))
1357c50c785cSJohn Marino 	{
1358c50c785cSJohn Marino 	  printf_filtered (_("Thread %d has extra info '%s'\n"),
1359c50c785cSJohn Marino 			   tp->num, tmp);
1360c50c785cSJohn Marino 	  match++;
1361c50c785cSJohn Marino 	}
1362c50c785cSJohn Marino     }
1363c50c785cSJohn Marino   if (!match)
1364c50c785cSJohn Marino     printf_filtered (_("No threads match '%s'\n"), arg);
1365c50c785cSJohn Marino }
1366c50c785cSJohn Marino 
13675796c8dcSSimon Schubert /* Print notices when new threads are attached and detached.  */
13685796c8dcSSimon Schubert int print_thread_events = 1;
13695796c8dcSSimon Schubert static void
show_print_thread_events(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)13705796c8dcSSimon Schubert show_print_thread_events (struct ui_file *file, int from_tty,
13715796c8dcSSimon Schubert                           struct cmd_list_element *c, const char *value)
13725796c8dcSSimon Schubert {
1373c50c785cSJohn Marino   fprintf_filtered (file,
1374c50c785cSJohn Marino 		    _("Printing of thread events is %s.\n"),
13755796c8dcSSimon Schubert                     value);
13765796c8dcSSimon Schubert }
13775796c8dcSSimon Schubert 
13785796c8dcSSimon Schubert static int
do_captured_thread_select(struct ui_out * uiout,void * tidstr)13795796c8dcSSimon Schubert do_captured_thread_select (struct ui_out *uiout, void *tidstr)
13805796c8dcSSimon Schubert {
13815796c8dcSSimon Schubert   int num;
13825796c8dcSSimon Schubert   struct thread_info *tp;
13835796c8dcSSimon Schubert 
13845796c8dcSSimon Schubert   num = value_as_long (parse_and_eval (tidstr));
13855796c8dcSSimon Schubert 
13865796c8dcSSimon Schubert   tp = find_thread_id (num);
13875796c8dcSSimon Schubert 
13885796c8dcSSimon Schubert   if (!tp)
13895796c8dcSSimon Schubert     error (_("Thread ID %d not known."), num);
13905796c8dcSSimon Schubert 
13915796c8dcSSimon Schubert   if (!thread_alive (tp))
13925796c8dcSSimon Schubert     error (_("Thread ID %d has terminated."), num);
13935796c8dcSSimon Schubert 
13945796c8dcSSimon Schubert   switch_to_thread (tp->ptid);
13955796c8dcSSimon Schubert 
13965796c8dcSSimon Schubert   annotate_thread_changed ();
13975796c8dcSSimon Schubert 
13985796c8dcSSimon Schubert   ui_out_text (uiout, "[Switching to thread ");
13995796c8dcSSimon Schubert   ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
14005796c8dcSSimon Schubert   ui_out_text (uiout, " (");
14015796c8dcSSimon Schubert   ui_out_text (uiout, target_pid_to_str (inferior_ptid));
14025796c8dcSSimon Schubert   ui_out_text (uiout, ")]");
14035796c8dcSSimon Schubert 
14045796c8dcSSimon Schubert   /* Note that we can't reach this with an exited thread, due to the
14055796c8dcSSimon Schubert      thread_alive check above.  */
1406a45ae5f8SJohn Marino   if (tp->state == THREAD_RUNNING)
14075796c8dcSSimon Schubert     ui_out_text (uiout, "(running)\n");
14085796c8dcSSimon Schubert   else
1409c50c785cSJohn Marino     {
1410c50c785cSJohn Marino       ui_out_text (uiout, "\n");
14115796c8dcSSimon Schubert       print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
1412c50c785cSJohn Marino     }
14135796c8dcSSimon Schubert 
14145796c8dcSSimon Schubert   /* Since the current thread may have changed, see if there is any
14155796c8dcSSimon Schubert      exited thread we can now delete.  */
14165796c8dcSSimon Schubert   prune_threads ();
14175796c8dcSSimon Schubert 
14185796c8dcSSimon Schubert   return GDB_RC_OK;
14195796c8dcSSimon Schubert }
14205796c8dcSSimon Schubert 
14215796c8dcSSimon Schubert enum gdb_rc
gdb_thread_select(struct ui_out * uiout,char * tidstr,char ** error_message)14225796c8dcSSimon Schubert gdb_thread_select (struct ui_out *uiout, char *tidstr, char **error_message)
14235796c8dcSSimon Schubert {
14245796c8dcSSimon Schubert   if (catch_exceptions_with_msg (uiout, do_captured_thread_select, tidstr,
14255796c8dcSSimon Schubert 				 error_message, RETURN_MASK_ALL) < 0)
14265796c8dcSSimon Schubert     return GDB_RC_FAIL;
14275796c8dcSSimon Schubert   return GDB_RC_OK;
14285796c8dcSSimon Schubert }
14295796c8dcSSimon Schubert 
1430cf7f2e2dSJohn Marino void
update_thread_list(void)1431cf7f2e2dSJohn Marino update_thread_list (void)
1432cf7f2e2dSJohn Marino {
1433cf7f2e2dSJohn Marino   prune_threads ();
1434cf7f2e2dSJohn Marino   target_find_new_threads ();
1435cf7f2e2dSJohn Marino }
1436cf7f2e2dSJohn Marino 
1437cf7f2e2dSJohn Marino /* Return a new value for the selected thread's id.  Return a value of 0 if
1438cf7f2e2dSJohn Marino    no thread is selected, or no threads exist.  */
1439cf7f2e2dSJohn Marino 
1440cf7f2e2dSJohn Marino static struct value *
thread_id_make_value(struct gdbarch * gdbarch,struct internalvar * var,void * ignore)1441*ef5ccd6cSJohn Marino thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
1442*ef5ccd6cSJohn Marino 		      void *ignore)
1443cf7f2e2dSJohn Marino {
1444cf7f2e2dSJohn Marino   struct thread_info *tp = find_thread_ptid (inferior_ptid);
1445cf7f2e2dSJohn Marino 
1446cf7f2e2dSJohn Marino   return value_from_longest (builtin_type (gdbarch)->builtin_int,
1447cf7f2e2dSJohn Marino 			     (tp ? tp->num : 0));
1448cf7f2e2dSJohn Marino }
1449cf7f2e2dSJohn Marino 
14505796c8dcSSimon Schubert /* Commands with a prefix of `thread'.  */
14515796c8dcSSimon Schubert struct cmd_list_element *thread_cmd_list = NULL;
14525796c8dcSSimon Schubert 
1453*ef5ccd6cSJohn Marino /* Implementation of `thread' variable.  */
1454*ef5ccd6cSJohn Marino 
1455*ef5ccd6cSJohn Marino static const struct internalvar_funcs thread_funcs =
1456*ef5ccd6cSJohn Marino {
1457*ef5ccd6cSJohn Marino   thread_id_make_value,
1458*ef5ccd6cSJohn Marino   NULL,
1459*ef5ccd6cSJohn Marino   NULL
1460*ef5ccd6cSJohn Marino };
1461*ef5ccd6cSJohn Marino 
14625796c8dcSSimon Schubert void
_initialize_thread(void)14635796c8dcSSimon Schubert _initialize_thread (void)
14645796c8dcSSimon Schubert {
14655796c8dcSSimon Schubert   static struct cmd_list_element *thread_apply_list = NULL;
14665796c8dcSSimon Schubert 
14675796c8dcSSimon Schubert   add_info ("threads", info_threads_command,
1468c50c785cSJohn Marino 	    _("Display currently known threads.\n\
1469c50c785cSJohn Marino Usage: info threads [ID]...\n\
1470c50c785cSJohn Marino Optional arguments are thread IDs with spaces between.\n\
1471c50c785cSJohn Marino If no arguments, all threads are displayed."));
14725796c8dcSSimon Schubert 
14735796c8dcSSimon Schubert   add_prefix_cmd ("thread", class_run, thread_command, _("\
14745796c8dcSSimon Schubert Use this command to switch between threads.\n\
14755796c8dcSSimon Schubert The new thread ID must be currently known."),
14765796c8dcSSimon Schubert 		  &thread_cmd_list, "thread ", 1, &cmdlist);
14775796c8dcSSimon Schubert 
14785796c8dcSSimon Schubert   add_prefix_cmd ("apply", class_run, thread_apply_command,
14795796c8dcSSimon Schubert 		  _("Apply a command to a list of threads."),
14805796c8dcSSimon Schubert 		  &thread_apply_list, "thread apply ", 1, &thread_cmd_list);
14815796c8dcSSimon Schubert 
14825796c8dcSSimon Schubert   add_cmd ("all", class_run, thread_apply_all_command,
14835796c8dcSSimon Schubert 	   _("Apply a command to all threads."), &thread_apply_list);
14845796c8dcSSimon Schubert 
1485c50c785cSJohn Marino   add_cmd ("name", class_run, thread_name_command,
1486c50c785cSJohn Marino 	   _("Set the current thread's name.\n\
1487c50c785cSJohn Marino Usage: thread name [NAME]\n\
1488c50c785cSJohn Marino If NAME is not given, then any existing name is removed."), &thread_cmd_list);
1489c50c785cSJohn Marino 
1490c50c785cSJohn Marino   add_cmd ("find", class_run, thread_find_command, _("\
1491c50c785cSJohn Marino Find threads that match a regular expression.\n\
1492c50c785cSJohn Marino Usage: thread find REGEXP\n\
1493c50c785cSJohn Marino Will display thread ids whose name, target ID, or extra info matches REGEXP."),
1494c50c785cSJohn Marino 	   &thread_cmd_list);
1495c50c785cSJohn Marino 
14965796c8dcSSimon Schubert   if (!xdb_commands)
14975796c8dcSSimon Schubert     add_com_alias ("t", "thread", class_run, 1);
14985796c8dcSSimon Schubert 
14995796c8dcSSimon Schubert   add_setshow_boolean_cmd ("thread-events", no_class,
15005796c8dcSSimon Schubert          &print_thread_events, _("\
15015796c8dcSSimon Schubert Set printing of thread events (such as thread start and exit)."), _("\
15025796c8dcSSimon Schubert Show printing of thread events (such as thread start and exit)."), NULL,
15035796c8dcSSimon Schubert          NULL,
15045796c8dcSSimon Schubert          show_print_thread_events,
15055796c8dcSSimon Schubert          &setprintlist, &showprintlist);
1506cf7f2e2dSJohn Marino 
1507*ef5ccd6cSJohn Marino   create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
15085796c8dcSSimon Schubert }
1509