Implement 'task apply'
This adds a 'task apply' command, which is the Ada tasking analogue of 'thread apply'. Unlike 'thread apply', it doesn't offer the 'ascending' flag; but otherwise it's essentially the same.
This commit is contained in:
parent
8a18382f94
commit
bc75fb44c5
3
gdb/NEWS
3
gdb/NEWS
@ -24,6 +24,9 @@ show varsize-limit
|
||||
These are now deprecated aliases for "set max-value-size" and
|
||||
"show max-value-size".
|
||||
|
||||
task apply [all | TASK-IDS...] [FLAG]... COMMAND
|
||||
Like "thread apply", but applies COMMAND to Ada tasks.
|
||||
|
||||
watch [...] task ID
|
||||
Watchpoints can now be restricted to a specific Ada task.
|
||||
|
||||
|
204
gdb/ada-tasks.c
204
gdb/ada-tasks.c
@ -1472,6 +1472,163 @@ ada_tasks_new_objfile_observer (struct objfile *objfile)
|
||||
ada_tasks_invalidate_inferior_data (inf);
|
||||
}
|
||||
|
||||
/* The qcs command line flags for the "task apply" commands. Keep
|
||||
this in sync with the "frame apply" commands. */
|
||||
|
||||
using qcs_flag_option_def
|
||||
= gdb::option::flag_option_def<qcs_flags>;
|
||||
|
||||
static const gdb::option::option_def task_qcs_flags_option_defs[] = {
|
||||
qcs_flag_option_def {
|
||||
"q", [] (qcs_flags *opt) { return &opt->quiet; },
|
||||
N_("Disables printing the task information."),
|
||||
},
|
||||
|
||||
qcs_flag_option_def {
|
||||
"c", [] (qcs_flags *opt) { return &opt->cont; },
|
||||
N_("Print any error raised by COMMAND and continue."),
|
||||
},
|
||||
|
||||
qcs_flag_option_def {
|
||||
"s", [] (qcs_flags *opt) { return &opt->silent; },
|
||||
N_("Silently ignore any errors or empty output produced by COMMAND."),
|
||||
},
|
||||
};
|
||||
|
||||
/* Create an option_def_group for the "task apply all" options, with
|
||||
FLAGS as context. */
|
||||
|
||||
static inline std::array<gdb::option::option_def_group, 1>
|
||||
make_task_apply_all_options_def_group (qcs_flags *flags)
|
||||
{
|
||||
return {{
|
||||
{ {task_qcs_flags_option_defs}, flags },
|
||||
}};
|
||||
}
|
||||
|
||||
/* Create an option_def_group for the "task apply" options, with
|
||||
FLAGS as context. */
|
||||
|
||||
static inline gdb::option::option_def_group
|
||||
make_task_apply_options_def_group (qcs_flags *flags)
|
||||
{
|
||||
return {{task_qcs_flags_option_defs}, flags};
|
||||
}
|
||||
|
||||
/* Implementation of 'task apply all'. */
|
||||
|
||||
static void
|
||||
task_apply_all_command (const char *cmd, int from_tty)
|
||||
{
|
||||
qcs_flags flags;
|
||||
|
||||
auto group = make_task_apply_all_options_def_group (&flags);
|
||||
gdb::option::process_options
|
||||
(&cmd, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group);
|
||||
|
||||
validate_flags_qcs ("task apply all", &flags);
|
||||
|
||||
if (cmd == nullptr || *cmd == '\0')
|
||||
error (_("Please specify a command at the end of 'task apply all'"));
|
||||
|
||||
update_thread_list ();
|
||||
ada_build_task_list ();
|
||||
|
||||
inferior *inf = current_inferior ();
|
||||
struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
|
||||
|
||||
/* Save a copy of the thread list and increment each thread's
|
||||
refcount while executing the command in the context of each
|
||||
thread, in case the command affects this. */
|
||||
std::vector<std::pair<int, thread_info_ref>> thr_list_cpy;
|
||||
|
||||
for (int i = 1; i <= data->task_list.size (); ++i)
|
||||
{
|
||||
ada_task_info &task = data->task_list[i - 1];
|
||||
if (!ada_task_is_alive (&task))
|
||||
continue;
|
||||
|
||||
thread_info *tp = find_thread_ptid (inf, task.ptid);
|
||||
if (tp == nullptr)
|
||||
warning (_("Unable to compute thread ID for task %s.\n"
|
||||
"Cannot switch to this task."),
|
||||
task_to_str (i, &task).c_str ());
|
||||
else
|
||||
thr_list_cpy.emplace_back (i, thread_info_ref::new_reference (tp));
|
||||
}
|
||||
|
||||
scoped_restore_current_thread restore_thread;
|
||||
|
||||
for (const auto &info : thr_list_cpy)
|
||||
if (switch_to_thread_if_alive (info.second.get ()))
|
||||
thread_try_catch_cmd (info.second.get (), info.first, cmd,
|
||||
from_tty, flags);
|
||||
}
|
||||
|
||||
/* Implementation of 'task apply'. */
|
||||
|
||||
static void
|
||||
task_apply_command (const char *tidlist, int from_tty)
|
||||
{
|
||||
|
||||
if (tidlist == nullptr || *tidlist == '\0')
|
||||
error (_("Please specify a task ID list"));
|
||||
|
||||
update_thread_list ();
|
||||
ada_build_task_list ();
|
||||
|
||||
inferior *inf = current_inferior ();
|
||||
struct ada_tasks_inferior_data *data = get_ada_tasks_inferior_data (inf);
|
||||
|
||||
/* Save a copy of the thread list and increment each thread's
|
||||
refcount while executing the command in the context of each
|
||||
thread, in case the command affects this. */
|
||||
std::vector<std::pair<int, thread_info_ref>> thr_list_cpy;
|
||||
|
||||
number_or_range_parser parser (tidlist);
|
||||
while (!parser.finished ())
|
||||
{
|
||||
int num = parser.get_number ();
|
||||
|
||||
if (num < 1 || num - 1 >= data->task_list.size ())
|
||||
warning (_("no Ada Task with number %d"), num);
|
||||
else
|
||||
{
|
||||
ada_task_info &task = data->task_list[num - 1];
|
||||
if (!ada_task_is_alive (&task))
|
||||
continue;
|
||||
|
||||
thread_info *tp = find_thread_ptid (inf, task.ptid);
|
||||
if (tp == nullptr)
|
||||
warning (_("Unable to compute thread ID for task %s.\n"
|
||||
"Cannot switch to this task."),
|
||||
task_to_str (num, &task).c_str ());
|
||||
else
|
||||
thr_list_cpy.emplace_back (num,
|
||||
thread_info_ref::new_reference (tp));
|
||||
}
|
||||
}
|
||||
|
||||
qcs_flags flags;
|
||||
const char *cmd = parser.cur_tok ();
|
||||
|
||||
auto group = make_task_apply_options_def_group (&flags);
|
||||
gdb::option::process_options
|
||||
(&cmd, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group);
|
||||
|
||||
validate_flags_qcs ("task apply", &flags);
|
||||
|
||||
if (*cmd == '\0')
|
||||
error (_("Please specify a command following the task ID list"));
|
||||
|
||||
scoped_restore_current_thread restore_thread;
|
||||
|
||||
for (const auto &info : thr_list_cpy)
|
||||
if (switch_to_thread_if_alive (info.second.get ()))
|
||||
thread_try_catch_cmd (info.second.get (), info.first, cmd,
|
||||
from_tty, flags);
|
||||
}
|
||||
|
||||
void _initialize_tasks ();
|
||||
void
|
||||
_initialize_tasks ()
|
||||
@ -1482,11 +1639,52 @@ _initialize_tasks ()
|
||||
gdb::observers::new_objfile.attach (ada_tasks_new_objfile_observer,
|
||||
"ada-tasks");
|
||||
|
||||
static struct cmd_list_element *task_cmd_list;
|
||||
static struct cmd_list_element *task_apply_list;
|
||||
|
||||
|
||||
/* Some new commands provided by this module. */
|
||||
add_info ("tasks", info_tasks_command,
|
||||
_("Provide information about all known Ada tasks."));
|
||||
add_cmd ("task", class_run, task_command,
|
||||
_("Use this command to switch between Ada tasks.\n\
|
||||
|
||||
add_prefix_cmd ("task", class_run, task_command,
|
||||
_("Use this command to switch between Ada tasks.\n\
|
||||
Without argument, this command simply prints the current task ID."),
|
||||
&cmdlist);
|
||||
&task_cmd_list, 1, &cmdlist);
|
||||
|
||||
#define TASK_APPLY_OPTION_HELP "\
|
||||
Prints per-inferior task number followed by COMMAND output.\n\
|
||||
\n\
|
||||
By default, an error raised during the execution of COMMAND\n\
|
||||
aborts \"task apply\".\n\
|
||||
\n\
|
||||
Options:\n\
|
||||
%OPTIONS%"
|
||||
|
||||
static const auto task_apply_opts
|
||||
= make_task_apply_options_def_group (nullptr);
|
||||
|
||||
static std::string task_apply_help = gdb::option::build_help (_("\
|
||||
Apply a command to a list of tasks.\n\
|
||||
Usage: task apply ID... [OPTION]... COMMAND\n\
|
||||
ID is a space-separated list of IDs of tasks to apply COMMAND on.\n"
|
||||
TASK_APPLY_OPTION_HELP), task_apply_opts);
|
||||
|
||||
add_prefix_cmd ("apply", class_run,
|
||||
task_apply_command,
|
||||
task_apply_help.c_str (),
|
||||
&task_apply_list, 1,
|
||||
&task_cmd_list);
|
||||
|
||||
static const auto task_apply_all_opts
|
||||
= make_task_apply_all_options_def_group (nullptr);
|
||||
|
||||
static std::string task_apply_all_help = gdb::option::build_help (_("\
|
||||
Apply a command to all tasks in the current inferior.\n\
|
||||
\n\
|
||||
Usage: task apply all [OPTION]... COMMAND\n"
|
||||
TASK_APPLY_OPTION_HELP), task_apply_all_opts);
|
||||
|
||||
add_cmd ("all", class_run, task_apply_all_command,
|
||||
task_apply_all_help.c_str (), &task_apply_list);
|
||||
}
|
||||
|
@ -18537,6 +18537,41 @@ from the current task to the given task.
|
||||
#4 0x804aacc in un () at un.adb:5
|
||||
@end smallexample
|
||||
|
||||
@item task apply [@var{task-id-list} | all] [@var{flag}]@dots{} @var{command}
|
||||
The @code{task apply} command is the Ada tasking analogue of
|
||||
@code{thread apply} (@pxref{Threads}). It allows you to apply the
|
||||
named @var{command} to one or more tasks. Specify the tasks that you
|
||||
want affected using a list of task IDs, or specify @code{all} to apply
|
||||
to all tasks.
|
||||
|
||||
The @var{flag} arguments control what output to produce and how to
|
||||
handle errors raised when applying @var{command} to a task.
|
||||
@var{flag} must start with a @code{-} directly followed by one letter
|
||||
in @code{qcs}. If several flags are provided, they must be given
|
||||
individually, such as @code{-c -q}.
|
||||
|
||||
By default, @value{GDBN} displays some task information before the
|
||||
output produced by @var{command}, and an error raised during the
|
||||
execution of a @var{command} will abort @code{task apply}. The
|
||||
following flags can be used to fine-tune this behavior:
|
||||
|
||||
@table @code
|
||||
@item -c
|
||||
The flag @code{-c}, which stands for @samp{continue}, causes any
|
||||
errors in @var{command} to be displayed, and the execution of
|
||||
@code{task apply} then continues.
|
||||
@item -s
|
||||
The flag @code{-s}, which stands for @samp{silent}, causes any errors
|
||||
or empty output produced by a @var{command} to be silently ignored.
|
||||
That is, the execution continues, but the task information and errors
|
||||
are not printed.
|
||||
@item -q
|
||||
The flag @code{-q} (@samp{quiet}) disables printing the task
|
||||
information.
|
||||
@end table
|
||||
|
||||
Flags @code{-c} and @code{-s} cannot be used together.
|
||||
|
||||
@item break @var{location} task @var{taskno}
|
||||
@itemx break @var{location} task @var{taskno} if @dots{}
|
||||
@cindex breakpoints and tasks, in Ada
|
||||
|
@ -975,4 +975,21 @@ extern void thread_select (const char *tidstr, class thread_info *thr);
|
||||
target to get the name. May return nullptr. */
|
||||
extern const char *thread_name (thread_info *thread);
|
||||
|
||||
/* Switch to thread TP if it is alive. Returns true if successfully
|
||||
switched, false otherwise. */
|
||||
|
||||
extern bool switch_to_thread_if_alive (thread_info *thr);
|
||||
|
||||
/* Assuming that THR is the current thread, execute CMD.
|
||||
If ADA_TASK is not empty, it is the Ada task ID, and will
|
||||
be printed instead of the thread information.
|
||||
FLAGS.QUIET controls the printing of the thread information.
|
||||
FLAGS.CONT and FLAGS.SILENT control how to handle errors. Can throw an
|
||||
exception if !FLAGS.SILENT and !FLAGS.CONT and CMD fails. */
|
||||
|
||||
extern void thread_try_catch_cmd (thread_info *thr,
|
||||
gdb::optional<int> ada_task,
|
||||
const char *cmd, int from_tty,
|
||||
const qcs_flags &flags);
|
||||
|
||||
#endif /* GDBTHREAD_H */
|
||||
|
@ -35,3 +35,8 @@ runto "break_me"
|
||||
gdb_test "task 2" \
|
||||
[join {"\\\[Switching to task 2 \"mit\"\\\].*" \
|
||||
".*foo\\.t \\(.*\\).*foo\\.adb:.*"} ""]
|
||||
|
||||
gdb_test "task apply 1 -q frame" ".*pck\\.break_me.*"
|
||||
|
||||
gdb_test "task apply all frame" \
|
||||
"Task ID 1:.*pck\\.break_me.*Task ID 2:.*"
|
||||
|
31
gdb/thread.c
31
gdb/thread.c
@ -662,10 +662,9 @@ thread_alive (thread_info *tp)
|
||||
return target_thread_alive (tp->ptid);
|
||||
}
|
||||
|
||||
/* Switch to thread TP if it is alive. Returns true if successfully
|
||||
switched, false otherwise. */
|
||||
/* See gdbthreads.h. */
|
||||
|
||||
static bool
|
||||
bool
|
||||
switch_to_thread_if_alive (thread_info *thr)
|
||||
{
|
||||
scoped_restore_current_thread restore_thread;
|
||||
@ -1428,23 +1427,25 @@ tp_array_compar_descending (const thread_info_ref &a, const thread_info_ref &b)
|
||||
return (a->per_inf_num > b->per_inf_num);
|
||||
}
|
||||
|
||||
/* Assuming that THR is the current thread, execute CMD.
|
||||
FLAGS.QUIET controls the printing of the thread information.
|
||||
FLAGS.CONT and FLAGS.SILENT control how to handle errors. Can throw an
|
||||
exception if !FLAGS.SILENT and !FLAGS.CONT and CMD fails. */
|
||||
/* See gdbthread.h. */
|
||||
|
||||
static void
|
||||
thr_try_catch_cmd (thread_info *thr, const char *cmd, int from_tty,
|
||||
const qcs_flags &flags)
|
||||
void
|
||||
thread_try_catch_cmd (thread_info *thr, gdb::optional<int> ada_task,
|
||||
const char *cmd, int from_tty,
|
||||
const qcs_flags &flags)
|
||||
{
|
||||
gdb_assert (is_current_thread (thr));
|
||||
|
||||
/* The thread header is computed before running the command since
|
||||
the command can change the inferior, which is not permitted
|
||||
by thread_target_id_str. */
|
||||
std::string thr_header =
|
||||
string_printf (_("\nThread %s (%s):\n"), print_thread_id (thr),
|
||||
thread_target_id_str (thr).c_str ());
|
||||
std::string thr_header;
|
||||
if (ada_task.has_value ())
|
||||
thr_header = string_printf (_("\nTask ID %d:\n"), *ada_task);
|
||||
else
|
||||
thr_header = string_printf (_("\nThread %s (%s):\n"),
|
||||
print_thread_id (thr),
|
||||
thread_target_id_str (thr).c_str ());
|
||||
|
||||
try
|
||||
{
|
||||
@ -1576,7 +1577,7 @@ thread_apply_all_command (const char *cmd, int from_tty)
|
||||
|
||||
for (thread_info_ref &thr : thr_list_cpy)
|
||||
if (switch_to_thread_if_alive (thr.get ()))
|
||||
thr_try_catch_cmd (thr.get (), cmd, from_tty, flags);
|
||||
thread_try_catch_cmd (thr.get (), {}, cmd, from_tty, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1738,7 +1739,7 @@ thread_apply_command (const char *tidlist, int from_tty)
|
||||
continue;
|
||||
}
|
||||
|
||||
thr_try_catch_cmd (tp, cmd, from_tty, flags);
|
||||
thread_try_catch_cmd (tp, {}, cmd, from_tty, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user