mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-10-16 12:24:19 +08:00
Implement MI notification for new threads.
* doc/observer.texi (new_thread): Document. * observer.sh: Forward declare struct thread_info. * thread.c (add_thread): Notify observer. * interps.h (interp_init_ftype): New parameter top_level. (interp_set): Likewise. (top_level_interpreter_data): Declare. * interps.c (interp_set): New parameter top_level. Pass it to interpreter's init function. Remember top level interpreter. (interpreter_exec_cmd): Adjust. (top_level_interpreter_data): New. * main.c (captured_main): Pass 1 for top_level parameter of interp_set. * cli/cli-interp.c (cli_interpreter_init): New parameter top_level. * tui/tui-interp.c (tui_init): New parameter top_level. * mi/mi-interp.c (mi_new_thread): New. (mi_interpreter_init): If top level, register observer for new threads. * Makefile.in (mi-interp.o, thread.o): Update dependencies.
This commit is contained in:
@ -1,3 +1,31 @@
|
|||||||
|
2008-03-14 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
|
Implement MI notification for new threads.
|
||||||
|
* doc/observer.texi (new_thread): Document.
|
||||||
|
* observer.sh: Forward declare struct thread_info.
|
||||||
|
* thread.c (add_thread): Notify observer.
|
||||||
|
|
||||||
|
* interps.h (interp_init_ftype): New parameter
|
||||||
|
top_level.
|
||||||
|
(interp_set): Likewise.
|
||||||
|
(top_level_interpreter_data): Declare.
|
||||||
|
* interps.c (interp_set): New parameter top_level.
|
||||||
|
Pass it to interpreter's init function. Remember
|
||||||
|
top level interpreter.
|
||||||
|
(interpreter_exec_cmd): Adjust.
|
||||||
|
(top_level_interpreter_data): New.
|
||||||
|
* main.c (captured_main): Pass 1 for top_level
|
||||||
|
parameter of interp_set.
|
||||||
|
* cli/cli-interp.c (cli_interpreter_init): New
|
||||||
|
parameter top_level.
|
||||||
|
* tui/tui-interp.c (tui_init): New parameter top_level.
|
||||||
|
|
||||||
|
* mi/mi-interp.c (mi_new_thread): New.
|
||||||
|
(mi_interpreter_init): If top level, register
|
||||||
|
observer for new threads.
|
||||||
|
|
||||||
|
* Makefile.in (mi-interp.o, thread.o): Update dependencies.
|
||||||
|
|
||||||
2008-03-14 Pedro Alves <pedro@codesourcery.com>
|
2008-03-14 Pedro Alves <pedro@codesourcery.com>
|
||||||
|
|
||||||
* top.c (execute_command): Disable break and stop
|
* top.c (execute_command): Disable break and stop
|
||||||
|
@ -2883,7 +2883,7 @@ target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \
|
|||||||
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
|
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
|
||||||
$(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_h) \
|
$(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_h) \
|
||||||
$(command_h) $(gdbcmd_h) $(regcache_h) $(gdb_h) $(gdb_string_h) \
|
$(command_h) $(gdbcmd_h) $(regcache_h) $(gdb_h) $(gdb_string_h) \
|
||||||
$(ui_out_h)
|
$(ui_out_h) $(observer_h)
|
||||||
top.o: top.c $(defs_h) $(gdbcmd_h) $(call_cmds_h) $(cli_cmds_h) \
|
top.o: top.c $(defs_h) $(gdbcmd_h) $(call_cmds_h) $(cli_cmds_h) \
|
||||||
$(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_h) \
|
$(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_h) \
|
||||||
$(inferior_h) $(exceptions_h) $(target_h) $(breakpoint_h) \
|
$(inferior_h) $(exceptions_h) $(target_h) $(breakpoint_h) \
|
||||||
@ -3228,7 +3228,7 @@ mi-getopt.o: $(srcdir)/mi/mi-getopt.c $(defs_h) $(mi_getopt_h) \
|
|||||||
mi-interp.o: $(srcdir)/mi/mi-interp.c $(defs_h) $(gdb_string_h) $(interps_h) \
|
mi-interp.o: $(srcdir)/mi/mi-interp.c $(defs_h) $(gdb_string_h) $(interps_h) \
|
||||||
$(event_top_h) $(event_loop_h) $(inferior_h) $(ui_out_h) $(top_h) \
|
$(event_top_h) $(event_loop_h) $(inferior_h) $(ui_out_h) $(top_h) \
|
||||||
$(exceptions_h) $(mi_main_h) $(mi_cmds_h) $(mi_out_h) \
|
$(exceptions_h) $(mi_main_h) $(mi_cmds_h) $(mi_out_h) \
|
||||||
$(mi_console_h)
|
$(mi_console_h) $(observer_h) $(gdbthread_h)
|
||||||
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-interp.c
|
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-interp.c
|
||||||
mi-main.o: $(srcdir)/mi/mi-main.c $(defs_h) $(target_h) $(inferior_h) \
|
mi-main.o: $(srcdir)/mi/mi-main.c $(defs_h) $(target_h) $(inferior_h) \
|
||||||
$(gdb_string_h) $(exceptions_h) $(top_h) $(gdbthread_h) $(mi_cmds_h) \
|
$(gdb_string_h) $(exceptions_h) $(top_h) $(gdbthread_h) $(mi_cmds_h) \
|
||||||
|
@ -43,7 +43,7 @@ struct captured_execute_command_args
|
|||||||
/* These implement the cli out interpreter: */
|
/* These implement the cli out interpreter: */
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
cli_interpreter_init (void)
|
cli_interpreter_init (int top_level)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -129,3 +129,7 @@ Called with @var{objfile} equal to @code{NULL} to indicate
|
|||||||
previously loaded symbol table data has now been invalidated.
|
previously loaded symbol table data has now been invalidated.
|
||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
|
@deftypefun void new_thread (struct thread_info *@var{t})
|
||||||
|
The thread specified by @var{t} has been created.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ void _initialize_interpreter (void);
|
|||||||
|
|
||||||
static struct interp *interp_list = NULL;
|
static struct interp *interp_list = NULL;
|
||||||
static struct interp *current_interpreter = NULL;
|
static struct interp *current_interpreter = NULL;
|
||||||
|
static struct interp *top_level_interpreter = NULL;
|
||||||
|
|
||||||
static int interpreter_initialized = 0;
|
static int interpreter_initialized = 0;
|
||||||
|
|
||||||
@ -124,16 +125,27 @@ interp_add (struct interp *interp)
|
|||||||
init proc is successful, return 1, if it fails, set the old
|
init proc is successful, return 1, if it fails, set the old
|
||||||
interpreter back in place and return 0. If we can't restore the
|
interpreter back in place and return 0. If we can't restore the
|
||||||
old interpreter, then raise an internal error, since we are in
|
old interpreter, then raise an internal error, since we are in
|
||||||
pretty bad shape at this point. */
|
pretty bad shape at this point.
|
||||||
|
|
||||||
|
The TOP_LEVEL parameter tells if this new interpreter is
|
||||||
|
the top-level one. The top-level is what is requested
|
||||||
|
on the command line, and is responsible for reporting general
|
||||||
|
notification about target state changes. For example, if
|
||||||
|
MI is the top-level interpreter, then it will always report
|
||||||
|
events such as target stops and new thread creation, even if they
|
||||||
|
are caused by CLI commands. */
|
||||||
int
|
int
|
||||||
interp_set (struct interp *interp)
|
interp_set (struct interp *interp, int top_level)
|
||||||
{
|
{
|
||||||
struct interp *old_interp = current_interpreter;
|
struct interp *old_interp = current_interpreter;
|
||||||
int first_time = 0;
|
int first_time = 0;
|
||||||
|
|
||||||
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
|
|
||||||
|
/* If we already have an interpreter, then trying to
|
||||||
|
set top level interpreter is kinda pointless. */
|
||||||
|
gdb_assert (!top_level || !current_interpreter);
|
||||||
|
gdb_assert (!top_level || !top_level_interpreter);
|
||||||
|
|
||||||
if (current_interpreter != NULL)
|
if (current_interpreter != NULL)
|
||||||
{
|
{
|
||||||
do_all_continuations ();
|
do_all_continuations ();
|
||||||
@ -152,6 +164,8 @@ interp_set (struct interp *interp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_interpreter = interp;
|
current_interpreter = interp;
|
||||||
|
if (top_level)
|
||||||
|
top_level_interpreter = interp;
|
||||||
|
|
||||||
/* We use interpreter_p for the "set interpreter" variable, so we need
|
/* We use interpreter_p for the "set interpreter" variable, so we need
|
||||||
to make sure we have a malloc'ed copy for the set command to free. */
|
to make sure we have a malloc'ed copy for the set command to free. */
|
||||||
@ -171,7 +185,7 @@ interp_set (struct interp *interp)
|
|||||||
{
|
{
|
||||||
if (interp->procs->init_proc != NULL)
|
if (interp->procs->init_proc != NULL)
|
||||||
{
|
{
|
||||||
interp->data = interp->procs->init_proc ();
|
interp->data = interp->procs->init_proc (top_level);
|
||||||
}
|
}
|
||||||
interp->inited = 1;
|
interp->inited = 1;
|
||||||
}
|
}
|
||||||
@ -182,7 +196,7 @@ interp_set (struct interp *interp)
|
|||||||
if (interp->procs->resume_proc != NULL
|
if (interp->procs->resume_proc != NULL
|
||||||
&& (!interp->procs->resume_proc (interp->data)))
|
&& (!interp->procs->resume_proc (interp->data)))
|
||||||
{
|
{
|
||||||
if (old_interp == NULL || !interp_set (old_interp))
|
if (old_interp == NULL || !interp_set (old_interp, 0))
|
||||||
internal_error (__FILE__, __LINE__,
|
internal_error (__FILE__, __LINE__,
|
||||||
_("Failed to initialize new interp \"%s\" %s"),
|
_("Failed to initialize new interp \"%s\" %s"),
|
||||||
interp->name, "and could not restore old interp!\n");
|
interp->name, "and could not restore old interp!\n");
|
||||||
@ -390,7 +404,7 @@ interpreter_exec_cmd (char *args, int from_tty)
|
|||||||
old_quiet = interp_set_quiet (old_interp, 1);
|
old_quiet = interp_set_quiet (old_interp, 1);
|
||||||
use_quiet = interp_set_quiet (interp_to_use, 1);
|
use_quiet = interp_set_quiet (interp_to_use, 1);
|
||||||
|
|
||||||
if (!interp_set (interp_to_use))
|
if (!interp_set (interp_to_use, 0))
|
||||||
error (_("Could not switch to interpreter \"%s\"."), prules[0]);
|
error (_("Could not switch to interpreter \"%s\"."), prules[0]);
|
||||||
|
|
||||||
for (i = 1; i < nrules; i++)
|
for (i = 1; i < nrules; i++)
|
||||||
@ -398,14 +412,14 @@ interpreter_exec_cmd (char *args, int from_tty)
|
|||||||
struct gdb_exception e = interp_exec (interp_to_use, prules[i]);
|
struct gdb_exception e = interp_exec (interp_to_use, prules[i]);
|
||||||
if (e.reason < 0)
|
if (e.reason < 0)
|
||||||
{
|
{
|
||||||
interp_set (old_interp);
|
interp_set (old_interp, 0);
|
||||||
interp_set_quiet (interp_to_use, use_quiet);
|
interp_set_quiet (interp_to_use, use_quiet);
|
||||||
interp_set_quiet (old_interp, old_quiet);
|
interp_set_quiet (old_interp, old_quiet);
|
||||||
error (_("error in command: \"%s\"."), prules[i]);
|
error (_("error in command: \"%s\"."), prules[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interp_set (old_interp);
|
interp_set (old_interp, 0);
|
||||||
interp_set_quiet (interp_to_use, use_quiet);
|
interp_set_quiet (interp_to_use, use_quiet);
|
||||||
interp_set_quiet (old_interp, old_quiet);
|
interp_set_quiet (old_interp, old_quiet);
|
||||||
}
|
}
|
||||||
@ -462,6 +476,13 @@ interpreter_completer (char *text, char *word)
|
|||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void *
|
||||||
|
top_level_interpreter_data (void)
|
||||||
|
{
|
||||||
|
gdb_assert (top_level_interpreter);
|
||||||
|
return top_level_interpreter->data;
|
||||||
|
}
|
||||||
|
|
||||||
/* This just adds the "interpreter-exec" command. */
|
/* This just adds the "interpreter-exec" command. */
|
||||||
void
|
void
|
||||||
_initialize_interpreter (void)
|
_initialize_interpreter (void)
|
||||||
|
@ -35,7 +35,7 @@ extern struct gdb_exception interp_exec (struct interp *interp,
|
|||||||
const char *command);
|
const char *command);
|
||||||
extern int interp_quiet_p (struct interp *interp);
|
extern int interp_quiet_p (struct interp *interp);
|
||||||
|
|
||||||
typedef void *(interp_init_ftype) (void);
|
typedef void *(interp_init_ftype) (int top_level);
|
||||||
typedef int (interp_resume_ftype) (void *data);
|
typedef int (interp_resume_ftype) (void *data);
|
||||||
typedef int (interp_suspend_ftype) (void *data);
|
typedef int (interp_suspend_ftype) (void *data);
|
||||||
typedef int (interp_prompt_p_ftype) (void *data);
|
typedef int (interp_prompt_p_ftype) (void *data);
|
||||||
@ -57,13 +57,15 @@ extern struct interp *interp_new (const char *name, void *data,
|
|||||||
struct ui_out *uiout,
|
struct ui_out *uiout,
|
||||||
const struct interp_procs *procs);
|
const struct interp_procs *procs);
|
||||||
extern void interp_add (struct interp *interp);
|
extern void interp_add (struct interp *interp);
|
||||||
extern int interp_set (struct interp *interp);
|
extern int interp_set (struct interp *interp, int top_level);
|
||||||
extern struct interp *interp_lookup (const char *name);
|
extern struct interp *interp_lookup (const char *name);
|
||||||
extern struct ui_out *interp_ui_out (struct interp *interp);
|
extern struct ui_out *interp_ui_out (struct interp *interp);
|
||||||
|
|
||||||
extern int current_interp_named_p (const char *name);
|
extern int current_interp_named_p (const char *name);
|
||||||
extern int current_interp_display_prompt_p (void);
|
extern int current_interp_display_prompt_p (void);
|
||||||
extern void current_interp_command_loop (void);
|
extern void current_interp_command_loop (void);
|
||||||
|
/* Returns opaque data associated with the top-level interpreter. */
|
||||||
|
extern void *top_level_interpreter_data (void);
|
||||||
|
|
||||||
extern void clear_interpreter_hooks (void);
|
extern void clear_interpreter_hooks (void);
|
||||||
|
|
||||||
|
@ -649,7 +649,7 @@ Excess command line arguments ignored. (%s%s)\n"),
|
|||||||
if (interp == NULL)
|
if (interp == NULL)
|
||||||
error (_("Interpreter `%s' unrecognized"), interpreter_p);
|
error (_("Interpreter `%s' unrecognized"), interpreter_p);
|
||||||
/* Install it. */
|
/* Install it. */
|
||||||
if (!interp_set (interp))
|
if (!interp_set (interp, 1))
|
||||||
{
|
{
|
||||||
fprintf_unfiltered (gdb_stderr,
|
fprintf_unfiltered (gdb_stderr,
|
||||||
"Interpreter `%s' failed to initialize.\n",
|
"Interpreter `%s' failed to initialize.\n",
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include "mi-cmds.h"
|
#include "mi-cmds.h"
|
||||||
#include "mi-out.h"
|
#include "mi-out.h"
|
||||||
#include "mi-console.h"
|
#include "mi-console.h"
|
||||||
|
#include "observer.h"
|
||||||
|
#include "gdbthread.h"
|
||||||
|
|
||||||
struct mi_interp
|
struct mi_interp
|
||||||
{
|
{
|
||||||
@ -64,8 +66,10 @@ static void mi1_command_loop (void);
|
|||||||
static void mi_insert_notify_hooks (void);
|
static void mi_insert_notify_hooks (void);
|
||||||
static void mi_remove_notify_hooks (void);
|
static void mi_remove_notify_hooks (void);
|
||||||
|
|
||||||
|
static void mi_new_thread (struct thread_info *t);
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
mi_interpreter_init (void)
|
mi_interpreter_init (int top_level)
|
||||||
{
|
{
|
||||||
struct mi_interp *mi = XMALLOC (struct mi_interp);
|
struct mi_interp *mi = XMALLOC (struct mi_interp);
|
||||||
|
|
||||||
@ -83,6 +87,9 @@ mi_interpreter_init (void)
|
|||||||
mi->targ = mi_console_file_new (raw_stdout, "@", '"');
|
mi->targ = mi_console_file_new (raw_stdout, "@", '"');
|
||||||
mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
|
mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
|
||||||
|
|
||||||
|
if (top_level)
|
||||||
|
observer_attach_new_thread (mi_new_thread);
|
||||||
|
|
||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +321,15 @@ mi_command_loop (int mi_version)
|
|||||||
start_event_loop ();
|
start_event_loop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mi_new_thread (struct thread_info *t)
|
||||||
|
{
|
||||||
|
struct mi_interp *mi = top_level_interpreter_data ();
|
||||||
|
|
||||||
|
fprintf_unfiltered (mi->event_channel, "thread-created,id=%d", t->num);
|
||||||
|
gdb_flush (mi->event_channel);
|
||||||
|
}
|
||||||
|
|
||||||
extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
|
extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -62,6 +62,7 @@ struct observer;
|
|||||||
struct bpstats;
|
struct bpstats;
|
||||||
struct so_list;
|
struct so_list;
|
||||||
struct objfile;
|
struct objfile;
|
||||||
|
struct thread_info;
|
||||||
EOF
|
EOF
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "ui-out.h"
|
#include "ui-out.h"
|
||||||
|
#include "observer.h"
|
||||||
|
|
||||||
/* Definition of struct thread_info exported to gdbthread.h */
|
/* Definition of struct thread_info exported to gdbthread.h */
|
||||||
|
|
||||||
@ -137,6 +138,8 @@ add_thread (ptid_t ptid)
|
|||||||
|
|
||||||
if (print_thread_events)
|
if (print_thread_events)
|
||||||
printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
|
printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
|
||||||
|
|
||||||
|
observer_notify_new_thread (result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ tui_exit (void)
|
|||||||
/* These implement the TUI interpreter. */
|
/* These implement the TUI interpreter. */
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
tui_init (void)
|
tui_init (int top_level)
|
||||||
{
|
{
|
||||||
/* Install exit handler to leave the screen in a good shape. */
|
/* Install exit handler to leave the screen in a good shape. */
|
||||||
atexit (tui_exit);
|
atexit (tui_exit);
|
||||||
|
Reference in New Issue
Block a user