/* Multi-process/thread control for GDB, the GNU debugger.
- Copyright (C) 1986-2016 Free Software Foundation, Inc.
+ Copyright (C) 1986-2017 Free Software Foundation, Inc.
Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
{
if (thr->thread_fsm != NULL)
{
- thread_fsm_clean_up (thr->thread_fsm);
+ thread_fsm_clean_up (thr->thread_fsm, thr);
thread_fsm_delete (thr->thread_fsm);
thr->thread_fsm = NULL;
}
thread_cancel_execution_command (tp);
}
+/* Set the TP's state as exited. */
+
static void
-free_thread (struct thread_info *tp)
+set_thread_exited (thread_info *tp, int silent)
{
- if (tp->priv)
+ /* Dead threads don't need to step-over. Remove from queue. */
+ if (tp->step_over_next != NULL)
+ thread_step_over_chain_remove (tp);
+
+ if (tp->state != THREAD_EXITED)
{
- if (tp->private_dtor)
- tp->private_dtor (tp->priv);
- else
- xfree (tp->priv);
- }
+ observer_notify_thread_exit (tp, silent);
+
+ /* Tag it as exited. */
+ tp->state = THREAD_EXITED;
- xfree (tp->name);
- xfree (tp);
+ /* Clear breakpoints, etc. associated with this thread. */
+ clear_thread_inferior_resources (tp);
+ }
}
void
for (tp = thread_list; tp; tp = tpnext)
{
tpnext = tp->next;
- free_thread (tp);
+ if (tp->deletable ())
+ delete tp;
+ else
+ set_thread_exited (tp, 1);
}
thread_list = NULL;
static struct thread_info *
new_thread (struct inferior *inf, ptid_t ptid)
{
- struct thread_info *tp;
-
- gdb_assert (inf != NULL);
-
- tp = XCNEW (struct thread_info);
-
- tp->ptid = ptid;
- tp->global_num = ++highest_thread_num;
- tp->inf = inf;
- tp->per_inf_num = ++inf->highest_thread_num;
+ thread_info *tp = new thread_info (inf, ptid);
if (thread_list == NULL)
thread_list = tp;
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;
}
to it, delete the original thread, reset the new thread's
ptid, and switch to it. */
- if (ptid_equal (inferior_ptid, ptid))
+ if (inferior_ptid == ptid)
{
tp = new_thread (inf, null_ptid);
return add_thread_with_info (ptid, NULL);
}
+thread_info::thread_info (struct inferior *inf_, ptid_t ptid_)
+ : ptid (ptid_), inf (inf_)
+{
+ gdb_assert (inf_ != NULL);
+
+ this->global_num = ++highest_thread_num;
+ this->per_inf_num = ++inf_->highest_thread_num;
+
+ /* Nothing to follow yet. */
+ memset (&this->pending_follow, 0, sizeof (this->pending_follow));
+ this->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+ this->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
+}
+
+thread_info::~thread_info ()
+{
+ if (this->priv)
+ {
+ if (this->private_dtor)
+ this->private_dtor (this->priv);
+ else
+ xfree (this->priv);
+ }
+
+ xfree (this->name);
+}
+
/* Add TP to the end of the step-over chain LIST_P. */
static void
tpprev = NULL;
for (tp = thread_list; tp; tpprev = tp, tp = tp->next)
- if (ptid_equal (tp->ptid, ptid))
+ if (tp->ptid == ptid)
break;
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);
+ set_thread_exited (tp, silent);
- /* 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. */
- if (tp->refcount > 0
- || ptid_equal (tp->ptid, inferior_ptid))
+ if (!tp->deletable ())
{
- if (tp->state != THREAD_EXITED)
- {
- observer_notify_thread_exit (tp, silent);
-
- /* Tag it as exited. */
- tp->state = THREAD_EXITED;
-
- /* Clear breakpoints, etc. associated with this thread. */
- clear_thread_inferior_resources (tp);
- }
-
/* Will be really deleted some other time. */
return;
}
- /* Notify thread exit, but only if we haven't already. */
- if (tp->state != THREAD_EXITED)
- observer_notify_thread_exit (tp, silent);
-
- /* Tag it as exited. */
- tp->state = THREAD_EXITED;
- clear_thread_inferior_resources (tp);
-
if (tpprev)
tpprev->next = tp->next;
else
thread_list = tp->next;
- free_thread (tp);
+ delete tp;
}
/* Delete thread PTID and notify of thread exit. If this is
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (ptid_equal (tp->ptid, ptid))
+ if (tp->ptid == ptid)
return tp;
return NULL;
* Calls a callback function once for each thread, so long as
* the callback function returns false. If the callback function
* returns true, the iteration will end and the current thread
- * will be returned. This can be useful for implementing a
+ * will be returned. This can be useful for implementing a
* search for a thread with arbitrary attributes, or for applying
* some operation to every thread.
*
- * FIXME: some of the existing functionality, such as
+ * FIXME: some of the existing functionality, such as
* "Thread apply all", might be rewritten using this functionality.
*/
for (tp = thread_list; tp; tp = tp->next)
++result;
- return result;
+ return result;
}
int
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (ptid_equal (tp->ptid, ptid))
+ if (tp->ptid == ptid)
return tp->global_num;
return 0;
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
- if (ptid_equal (tp->ptid, ptid))
+ if (tp->ptid == ptid)
return 1;
return 0; /* Never heard of 'im. */
if (tp->state == THREAD_EXITED)
continue;
- if (ptid_equal (tp->ptid, inferior_ptid))
+ if (tp->ptid == inferior_ptid)
current_thread = tp->global_num;
num++;
- ui_out_field_int (uiout, "thread-id", tp->global_num);
+ uiout->field_int ("thread-id", tp->global_num);
}
do_cleanups (cleanup_chain);
if (current_thread != -1)
- ui_out_field_int (uiout, "current-thread-id", current_thread);
- ui_out_field_int (uiout, "number-of-threads", num);
+ uiout->field_int ("current-thread-id", current_thread);
+ uiout->field_int ("number-of-threads", num);
return GDB_RC_OK;
}
set_resumed (ptid_t ptid, int resumed)
{
struct thread_info *tp;
- int all = ptid_equal (ptid, minus_one_ptid);
+ int all = ptid == minus_one_ptid;
if (all || ptid_is_pid (ptid))
{
set_running (ptid_t ptid, int running)
{
struct thread_info *tp;
- int all = ptid_equal (ptid, minus_one_ptid);
+ int all = 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
+ /* 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))
{
set_executing (ptid_t ptid, int executing)
{
struct thread_info *tp;
- int all = ptid_equal (ptid, minus_one_ptid);
+ int all = ptid == minus_one_ptid;
if (all || ptid_is_pid (ptid))
{
threads_executing = 1;
/* Only clear the flag if the caller is telling us everything is
stopped. */
- else if (ptid_equal (minus_one_ptid, ptid))
+ else if (minus_one_ptid == ptid)
threads_executing = 0;
}
set_stop_requested (ptid_t ptid, int stop)
{
struct thread_info *tp;
- int all = ptid_equal (ptid, minus_one_ptid);
+ int all = ptid == minus_one_ptid;
if (all || ptid_is_pid (ptid))
{
int all;
int any_started = 0;
- all = ptid_equal (ptid, minus_one_ptid);
+ all = ptid == minus_one_ptid;
if (all || ptid_is_pid (ptid))
{
for (tp = thread_list; tp; tp = tp->next)
{
- if (tp->state == THREAD_EXITED)
- continue;
+ if (tp->state == THREAD_EXITED)
+ continue;
if (all || ptid_get_pid (ptid) == ptid_get_pid (tp->ptid))
{
if (set_running_thread (tp, tp->executing))
validate_registers_access (void)
{
/* No selected thread, no registers. */
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
error (_("No thread selected."));
/* Don't try to read from a dead thread. */
error (_("Selected thread is running."));
}
+/* See gdbthread.h. */
+
+bool
+can_access_registers_ptid (ptid_t ptid)
+{
+ /* No thread, no registers. */
+ if (ptid == null_ptid)
+ return false;
+
+ /* Don't try to read from a dead thread. */
+ if (is_exited (ptid))
+ return false;
+
+ /* ... or from a spinning thread. FIXME: see validate_registers_access. */
+ if (is_executing (ptid))
+ return false;
+
+ return true;
+}
+
int
pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread)
{
ptid_t current_ptid;
struct cleanup *old_chain;
const char *extra_info, *name, *target_id;
- int current_thread = -1;
struct inferior *inf;
int default_inf_num = current_inferior ()->num;
/* For backward compatibility, we make a list for MI. A table is
preferable for the CLI, though, because it shows table
headers. */
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
make_cleanup_ui_out_list_begin_end (uiout, "threads");
else
{
if (n_threads == 0)
{
if (requested_threads == NULL || *requested_threads == '\0')
- ui_out_message (uiout, 0, _("No threads.\n"));
+ uiout->message (_("No threads.\n"));
else
- ui_out_message (uiout, 0, _("No threads match '%s'.\n"),
+ uiout->message (_("No threads match '%s'.\n"),
requested_threads);
do_cleanups (old_chain);
return;
}
- if (show_global_ids || ui_out_is_mi_like_p (uiout))
+ if (show_global_ids || uiout->is_mi_like_p ())
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", "");
+ uiout->table_header (1, ui_left, "current", "");
- 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);
+ if (!uiout->is_mi_like_p ())
+ uiout->table_header (4, ui_left, "id-in-tg", "Id");
+ if (show_global_ids || uiout->is_mi_like_p ())
+ uiout->table_header (4, ui_left, "id", "GId");
+ uiout->table_header (17, ui_left, "target-id", "Target Id");
+ uiout->table_header (1, ui_left, "frame", "Frame");
+ uiout->table_body ();
}
ALL_THREADS_BY_INFERIOR (inf, tp)
struct cleanup *chain2;
int core;
- if (ptid_equal (tp->ptid, current_ptid))
- current_thread = tp->global_num;
-
if (!should_print_thread (requested_threads, default_inf_num,
global_ids, pid, tp))
continue;
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
{
/* Compatibility. */
- if (ptid_equal (tp->ptid, current_ptid))
- ui_out_text (uiout, "* ");
+ if (tp->ptid == current_ptid)
+ uiout->text ("* ");
else
- ui_out_text (uiout, " ");
+ uiout->text (" ");
}
else
{
- if (ptid_equal (tp->ptid, current_ptid))
- ui_out_field_string (uiout, "current", "*");
+ if (tp->ptid == current_ptid)
+ uiout->field_string ("current", "*");
else
- ui_out_field_skip (uiout, "current");
+ uiout->field_skip ("current");
}
- if (!ui_out_is_mi_like_p (uiout))
- ui_out_field_string (uiout, "id-in-tg", print_thread_id (tp));
+ if (!uiout->is_mi_like_p ())
+ uiout->field_string ("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);
+ if (show_global_ids || uiout->is_mi_like_p ())
+ uiout->field_int ("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
extra_info = target_extra_thread_info (tp);
name = tp->name ? tp->name : target_thread_name (tp);
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
{
- ui_out_field_string (uiout, "target-id", target_id);
+ uiout->field_string ("target-id", target_id);
if (extra_info)
- ui_out_field_string (uiout, "details", extra_info);
+ uiout->field_string ("details", extra_info);
if (name)
- ui_out_field_string (uiout, "name", name);
+ uiout->field_string ("name", name);
}
else
{
contents = xstrdup (target_id);
str_cleanup = make_cleanup (xfree, contents);
- ui_out_field_string (uiout, "target-id", contents);
+ uiout->field_string ("target-id", contents);
do_cleanups (str_cleanup);
}
if (tp->state == THREAD_RUNNING)
- ui_out_text (uiout, "(running)\n");
+ uiout->text ("(running)\n");
else
{
/* The switch below puts us at the top of the stack (leaf
switch_to_thread (tp->ptid);
print_stack_frame (get_selected_frame (NULL),
/* For MI output, print frame level. */
- ui_out_is_mi_like_p (uiout),
+ uiout->is_mi_like_p (),
LOCATION, 0);
}
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
{
- char *state = "stopped";
+ const char *state = "stopped";
if (tp->state == THREAD_RUNNING)
state = "running";
- ui_out_field_string (uiout, "state", state);
+ uiout->field_string ("state", state);
}
core = target_core_of_thread (tp->ptid);
- if (ui_out_is_mi_like_p (uiout) && core != -1)
- ui_out_field_int (uiout, "core", core);
+ if (uiout->is_mi_like_p () && core != -1)
+ uiout->field_int ("core", core);
do_cleanups (chain2);
}
if (pid == -1 && requested_threads == NULL)
{
- if (ui_out_is_mi_like_p (uiout)
- && !ptid_equal (inferior_ptid, null_ptid))
+ if (uiout->is_mi_like_p ()
+ && inferior_ptid != null_ptid)
{
int num = ptid_to_global_thread_id (inferior_ptid);
gdb_assert (num != 0);
- ui_out_field_int (uiout, "current-thread-id", num);
+ uiout->field_int ("current-thread-id", num);
}
- if (!ptid_equal (inferior_ptid, null_ptid) && is_exited (inferior_ptid))
- ui_out_message (uiout, 0, "\n\
+ if (inferior_ptid != null_ptid && is_exited (inferior_ptid))
+ uiout->message ("\n\
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\
+ else if (thread_list != NULL && inferior_ptid == null_ptid)
+ uiout->message ("\n\
No selected thread. See `help thread'.\n");
}
}
/* Implementation of the "info threads" command.
Note: this has the drawback that it _really_ switches
- threads, which frees the frame cache. A no-side
- effects info-threads command would be nicer. */
+ threads, which frees the frame cache. A no-side
+ effects info-threads command would be nicer. */
static void
info_threads_command (char *arg, int from_tty)
/* Switch the program space as well, if we can infer it from the now
current thread. Otherwise, it's up to the caller to select the
space it wants. */
- if (!ptid_equal (ptid, null_ptid))
+ if (ptid != null_ptid)
{
struct inferior *inf;
set_current_inferior (inf);
}
- if (ptid_equal (ptid, inferior_ptid))
+ if (ptid == inferior_ptid)
return;
inferior_ptid = ptid;
/* We don't check for is_stopped, because we're called at times
while in the TARGET_RUNNING state, e.g., while handling an
internal event. */
- if (!ptid_equal (inferior_ptid, null_ptid)
+ if (inferior_ptid != null_ptid
&& !is_exited (ptid)
&& !is_executing (ptid))
stop_pc = regcache_read_pc (get_thread_regcache (ptid));
select_frame (get_current_frame ());
/* Warn the user. */
- if (frame_level > 0 && !ui_out_is_mi_like_p (current_uiout))
+ if (frame_level > 0 && !current_uiout->is_mi_like_p ())
{
warning (_("Couldn't restore frame #%d in "
"current thread. Bottom (innermost) frame selected:"),
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;
+ thread_info *thread;
struct frame_id selected_frame_id;
int selected_frame_level;
int was_stopped;
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 = (struct current_thread_cleanup *) arg;
- tp = find_thread_ptid (old->inferior_ptid);
-
- /* If the previously selected thread belonged to a process that has
- in the mean time been deleted (due to normal exit, detach, etc.),
- then don't revert back to it, but instead simply drop back to no
- thread selected. */
- if (tp
- && find_inferior_ptid (tp->ptid) != NULL)
- restore_current_thread (old->inferior_ptid);
+ /* If an entry of thread_info was previously selected, it won't be
+ deleted because we've increased its refcount. The thread represented
+ by this thread_info entry may have already exited (due to normal exit,
+ detach, etc), so the thread_info.state is THREAD_EXITED. */
+ if (old->thread != NULL
+ /* If the previously selected thread belonged to a process that has
+ in the mean time exited (or killed, detached, etc.), then don't revert
+ back to it, but instead simply drop back to no thread selected. */
+ && find_inferior_ptid (old->thread->ptid) != NULL)
+ restore_current_thread (old->thread->ptid);
else
{
restore_current_thread (null_ptid);
/* The running state of the originally selected thread may have
changed, so we have to recheck it here. */
- if (!ptid_equal (inferior_ptid, null_ptid)
+ if (inferior_ptid != null_ptid
&& old->was_stopped
&& is_stopped (inferior_ptid)
&& target_has_registers
struct thread_info *tp;
struct inferior *inf;
- current_thread_cleanup_chain = current_thread_cleanup_chain->next;
+ if (old->thread != NULL)
+ old->thread->decref ();
- tp = find_thread_ptid (old->inferior_ptid);
- if (tp)
- tp->refcount--;
inf = find_inferior_id (old->inf_id);
if (inf != NULL)
inf->removable = old->was_removable;
= (struct thread_array_cleanup *) data;
for (k = 0; k != ta_cleanup->count; k++)
- ta_cleanup->tp_array[k]->refcount--;
+ ta_cleanup->tp_array[k]->decref ();
}
struct cleanup *
make_cleanup_restore_current_thread (void)
{
- struct thread_info *tp;
- struct frame_info *frame;
struct current_thread_cleanup *old = XNEW (struct current_thread_cleanup);
- old->inferior_ptid = inferior_ptid;
+ old->thread = NULL;
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))
+ if (inferior_ptid != null_ptid)
{
+ struct frame_info *frame;
+
old->was_stopped = is_stopped (inferior_ptid);
if (old->was_stopped
&& target_has_registers
old->selected_frame_id = get_frame_id (frame);
old->selected_frame_level = frame_relative_level (frame);
- tp = find_thread_ptid (inferior_ptid);
+ struct thread_info *tp = find_thread_ptid (inferior_ptid);
+
if (tp)
- tp->refcount++;
+ tp->incref ();
+ old->thread = tp;
}
current_inferior ()->removable = 0;
/* See gdbthread.h. */
+int
+show_thread_that_caused_stop (void)
+{
+ return highest_thread_num > 1;
+}
+
+/* See gdbthread.h. */
+
int
show_inferior_qualified_tids (void)
{
if (a->inf->num != b->inf->num)
{
- return ((a->inf->num > b->inf->num) - (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));
}
int i = 0, k;
/* Save a copy of the thread_list in case we execute detach
- command. */
+ 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++;
- }
+ {
+ tp_array[i] = tp;
+ tp->incref ();
+ 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);
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"),
+ 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);
+ execute_command (cmd, from_tty);
- /* Restore exact command used previously. */
- strcpy (cmd, saved_cmd);
+ /* Restore exact command used previously. */
+ strcpy (cmd, saved_cmd);
}
}
static void
thread_apply_command (char *tidlist, int from_tty)
{
- char *cmd;
+ char *cmd = NULL;
struct cleanup *old_chain;
char *saved_cmd;
- struct tid_range_parser parser;
+ tid_range_parser parser;
if (tidlist == NULL || *tidlist == '\000')
error (_("Please specify a thread ID list"));
- for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++);
+ parser.init (tidlist, current_inferior ()->num);
+ while (!parser.finished ())
+ {
+ int inf_num, thr_start, thr_end;
- if (*cmd == '\000')
+ if (!parser.get_tid_range (&inf_num, &thr_start, &thr_end))
+ {
+ cmd = (char *) parser.cur_tok ();
+ break;
+ }
+ }
+
+ if (cmd == NULL)
error (_("Please specify a command following the thread ID list"));
+ if (tidlist == cmd || !isalpha (cmd[0]))
+ invalid_thread_id_error (cmd);
+
/* Save a copy of the command in case it is clobbered by
execute_command. */
saved_cmd = xstrdup (cmd);
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)
+ parser.init (tidlist, current_inferior ()->num);
+ while (!parser.finished () && parser.cur_tok () < cmd)
{
struct thread_info *tp = NULL;
struct inferior *inf;
int inf_num, thr_num;
- tid_range_parser_get_tid (&parser, &inf_num, &thr_num);
+ parser.get_tid (&inf_num, &thr_num);
inf = find_inferior_id (inf_num);
if (inf != NULL)
tp = find_thread_id (inf, thr_num);
+
+ if (parser.in_star_range ())
+ {
+ if (inf == NULL)
+ {
+ warning (_("Unknown inferior %d"), inf_num);
+ parser.skip_range ();
+ continue;
+ }
+
+ /* No use looking for threads past the highest thread number
+ the inferior ever had. */
+ if (thr_num >= inf->highest_thread_num)
+ parser.skip_range ();
+
+ /* Be quiet about unknown threads numbers. */
+ if (tp == NULL)
+ continue;
+ }
+
if (tp == NULL)
{
- if (show_inferior_qualified_tids ()
- || tid_range_parser_qualified (&parser))
+ if (show_inferior_qualified_tids () || parser.tid_is_qualified ())
warning (_("Unknown thread %d.%d"), inf_num, thr_num);
else
warning (_("Unknown thread %d"), thr_num);
void
thread_command (char *tidstr, int from_tty)
{
- if (!tidstr)
+ if (tidstr == NULL)
{
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
error (_("No thread selected"));
if (target_has_stack)
}
else
error (_("No stack."));
- return;
}
+ else
+ {
+ ptid_t previous_ptid = inferior_ptid;
+ enum gdb_rc result;
+
+ result = gdb_thread_select (current_uiout, tidstr, NULL);
- gdb_thread_select (current_uiout, tidstr, NULL);
+ /* If thread switch did not succeed don't notify or print. */
+ if (result == GDB_RC_FAIL)
+ return;
+
+ /* Print if the thread has not changed, otherwise an event will
+ be sent. */
+ if (inferior_ptid == previous_ptid)
+ {
+ print_selected_thread_frame (current_uiout,
+ USER_SELECTED_THREAD
+ | USER_SELECTED_FRAME);
+ }
+ else
+ {
+ observer_notify_user_selected_context_changed (USER_SELECTED_THREAD
+ | USER_SELECTED_FRAME);
+ }
+ }
}
/* Implementation of `thread name'. */
{
struct thread_info *info;
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
error (_("No thread selected"));
arg = skip_spaces (arg);
int print_thread_events = 1;
static void
show_print_thread_events (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
+ struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file,
_("Printing of thread events is %s.\n"),
- value);
+ value);
}
static int
const char *tidstr = (const char *) tidstr_v;
struct thread_info *tp;
- if (ui_out_is_mi_like_p (uiout))
+ if (uiout->is_mi_like_p ())
{
int num = value_as_long (parse_and_eval (tidstr));
annotate_thread_changed ();
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_int (uiout, "new-thread-id", inferior_thread ()->global_num);
- else
+ /* Since the current thread may have changed, see if there is any
+ exited thread we can now delete. */
+ prune_threads ();
+
+ return GDB_RC_OK;
+}
+
+/* Print thread and frame switch command response. */
+
+void
+print_selected_thread_frame (struct ui_out *uiout,
+ user_selected_what selection)
+{
+ struct thread_info *tp = inferior_thread ();
+ struct inferior *inf = current_inferior ();
+
+ if (selection & USER_SELECTED_THREAD)
{
- 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, ")]");
+ if (uiout->is_mi_like_p ())
+ {
+ uiout->field_int ("new-thread-id",
+ inferior_thread ()->global_num);
+ }
+ else
+ {
+ uiout->text ("[Switching to thread ");
+ uiout->field_string ("new-thread-id", print_thread_id (tp));
+ uiout->text (" (");
+ uiout->text (target_pid_to_str (inferior_ptid));
+ uiout->text (")]");
+ }
}
- /* Note that we can't reach this with an exited thread, due to the
- thread_alive check above. */
if (tp->state == THREAD_RUNNING)
- ui_out_text (uiout, "(running)\n");
- else
{
- ui_out_text (uiout, "\n");
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
+ if (selection & USER_SELECTED_THREAD)
+ uiout->text ("(running)\n");
}
+ else if (selection & USER_SELECTED_FRAME)
+ {
+ if (selection & USER_SELECTED_THREAD)
+ uiout->text ("\n");
- /* Since the current thread may have changed, see if there is any
- exited thread we can now delete. */
- prune_threads ();
-
- return GDB_RC_OK;
+ if (has_stack_frames ())
+ print_stack_frame_to_uiout (uiout, get_selected_frame (NULL),
+ 1, SRC_AND_LOC, 1);
+ }
}
enum gdb_rc
threads exist. */
static struct value *
-thread_id_per_inf_num_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+thread_id_per_inf_num_make_value (struct gdbarch *gdbarch,
+ struct internalvar *var,
void *ignore)
{
return thread_num_make_value_helper (gdbarch, 0);
{
static struct cmd_list_element *thread_apply_list = NULL;
- add_info ("threads", info_threads_command,
+ add_info ("threads", info_threads_command,
_("Display currently known threads.\n\
Usage: info threads [-gid] [ID]...\n\
-gid: Show global thread IDs.\n\
add_com_alias ("t", "thread", class_run, 1);
add_setshow_boolean_cmd ("thread-events", no_class,
- &print_thread_events, _("\
+ &print_thread_events, _("\
Set printing of thread events (such as thread start and exit)."), _("\
Show printing of thread events (such as thread start and exit)."), NULL,
- NULL,
- show_print_thread_events,
- &setprintlist, &showprintlist);
+ NULL,
+ show_print_thread_events,
+ &setprintlist, &showprintlist);
create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
create_internalvar_type_lazy ("_gthread", >hread_funcs, NULL);
-
- observer_attach_thread_ptid_changed (restore_current_thread_ptid_changed);
}