Implement MI notification for new threads.
authorVladimir Prus <vladimir@codesourcery.com>
Fri, 14 Mar 2008 17:21:08 +0000 (17:21 +0000)
committerVladimir Prus <vladimir@codesourcery.com>
Fri, 14 Mar 2008 17:21:08 +0000 (17:21 +0000)
        * 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.

gdb/ChangeLog
gdb/Makefile.in
gdb/cli/cli-interp.c
gdb/doc/observer.texi
gdb/interps.c
gdb/interps.h
gdb/main.c
gdb/mi/mi-interp.c
gdb/observer.sh
gdb/thread.c
gdb/tui/tui-interp.c

index d02d4a96e4f37be4f9b6deff7e828f035f5c7b8c..dd9e8b201cddf020956d68f322498c726ef4a906 100644 (file)
@@ -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>
 
        * top.c (execute_command): Disable break and stop
index 00aecb9139757f306c87b8a1d6188e97b12e4ebe..04db23391acfaf31818b1b89e57add3579c9905c 100644 (file)
@@ -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) \
        $(environ_h) $(value_h) $(target_h) $(gdbthread_h) $(exceptions_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) \
        $(cli_script_h) $(cli_setshow_h) $(cli_decode_h) $(symtab_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) \
        $(event_top_h) $(event_loop_h) $(inferior_h) $(ui_out_h) $(top_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
 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) \
index 2761b1ca9b31e4bc65c13dada439353f8ebe172c..34a48cb8d7501d325dab323a3f2ec8b9e49dafe9 100644 (file)
@@ -43,7 +43,7 @@ struct captured_execute_command_args
 /* These implement the cli out interpreter: */
 
 static void *
-cli_interpreter_init (void)
+cli_interpreter_init (int top_level)
 {
   return NULL;
 }
index e4c99d8e0863b2e7eea766cb3de5124883d14132..5bcc76c6560cb200d77584a4847d97b0c2ec5d54 100644 (file)
@@ -129,3 +129,7 @@ Called with @var{objfile} equal to @code{NULL} to indicate
 previously loaded symbol table data has now been invalidated.
 @end deftypefun
 
+@deftypefun void new_thread (struct thread_info *@var{t})
+The thread specified by @var{t} has been created.
+@end deftypefun
+
index c855374dc36b1d3549810d80389214aee2e3c14c..7f48ef8233299a3297e2fd54803f7e96525eb84b 100644 (file)
@@ -81,6 +81,7 @@ void _initialize_interpreter (void);
 
 static struct interp *interp_list = NULL;
 static struct interp *current_interpreter = NULL;
+static struct interp *top_level_interpreter = NULL;
 
 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
    interpreter back in place and return 0.  If we can't restore the
    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
-interp_set (struct interp *interp)
+interp_set (struct interp *interp, int top_level)
 {
   struct interp *old_interp = current_interpreter;
   int first_time = 0;
-
-
   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)
     {
       do_all_continuations ();
@@ -152,6 +164,8 @@ interp_set (struct interp *interp)
     }
 
   current_interpreter = interp;
+  if (top_level)
+    top_level_interpreter = interp;
 
   /* 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. */
@@ -171,7 +185,7 @@ interp_set (struct interp *interp)
     {
       if (interp->procs->init_proc != NULL)
        {
-         interp->data = interp->procs->init_proc ();
+         interp->data = interp->procs->init_proc (top_level);
        }
       interp->inited = 1;
     }
@@ -182,7 +196,7 @@ interp_set (struct interp *interp)
   if (interp->procs->resume_proc != NULL
       && (!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__,
                        _("Failed to initialize new interp \"%s\" %s"),
                        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);
   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]);
 
   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]);
       if (e.reason < 0)
        {
-         interp_set (old_interp);
+         interp_set (old_interp, 0);
          interp_set_quiet (interp_to_use, use_quiet);
          interp_set_quiet (old_interp, old_quiet);
          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 (old_interp, old_quiet);
 }
@@ -462,6 +476,13 @@ interpreter_completer (char *text, char *word)
   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.  */
 void
 _initialize_interpreter (void)
index e1286be5a0de75cf9db00636bf6a5dddef5ada5a..e1030fa8b7d26996055e695148b494afae7111f1 100644 (file)
@@ -35,7 +35,7 @@ extern struct gdb_exception interp_exec (struct interp *interp,
                                         const char *command);
 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_suspend_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,
                                  const struct interp_procs *procs);
 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 ui_out *interp_ui_out (struct interp *interp);
 
 extern int current_interp_named_p (const char *name);
 extern int current_interp_display_prompt_p (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);
 
index eb7ad5a5e178a4689a8453ffca2ee429e36e58f4..df3e48ac445415912b06521f7edf3f4e84bc27e3 100644 (file)
@@ -649,7 +649,7 @@ Excess command line arguments ignored. (%s%s)\n"),
     if (interp == NULL)
       error (_("Interpreter `%s' unrecognized"), interpreter_p);
     /* Install it.  */
-    if (!interp_set (interp))
+    if (!interp_set (interp, 1))
       {
         fprintf_unfiltered (gdb_stderr,
                            "Interpreter `%s' failed to initialize.\n",
index eb924cd3e51fd6516dc04f14d1d14a77a6e8be11..96229a01d29a804d250a1751c3395f5459d3d075 100644 (file)
@@ -31,6 +31,8 @@
 #include "mi-cmds.h"
 #include "mi-out.h"
 #include "mi-console.h"
+#include "observer.h"
+#include "gdbthread.h"
 
 struct mi_interp
 {
@@ -64,8 +66,10 @@ static void mi1_command_loop (void);
 static void mi_insert_notify_hooks (void);
 static void mi_remove_notify_hooks (void);
 
+static void mi_new_thread (struct thread_info *t);
+
 static void *
-mi_interpreter_init (void)
+mi_interpreter_init (int top_level)
 {
   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->event_channel = mi_console_file_new (raw_stdout, "=", 0);
 
+  if (top_level)
+    observer_attach_new_thread (mi_new_thread);
+
   return mi;
 }
 
@@ -314,6 +321,15 @@ mi_command_loop (int mi_version)
   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 */
 
 void
index 96700b04ed0e68e210277efe522a1b71137a2dbc..2b2eb159cca6d92e39081570f4d9730db1aeebc9 100755 (executable)
@@ -62,6 +62,7 @@ struct observer;
 struct bpstats;
 struct so_list;
 struct objfile;
+struct thread_info;
 EOF
         ;;
 esac
index 40b7b3dbe864d7e9a90a5703f713b7831f38d0a1..97facd2e6b69a5f618d88272348f12cd5efd60ff 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/types.h>
 #include <signal.h>
 #include "ui-out.h"
+#include "observer.h"
 
 /* Definition of struct thread_info exported to gdbthread.h */
 
@@ -137,6 +138,8 @@ add_thread (ptid_t ptid)
 
   if (print_thread_events)
     printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
+
+  observer_notify_new_thread (result);
   
   return result;
 }
index 9abecd4c0b4afef2430cb41f90c068a562342649..ca2e7436beaf1ddd55123893f903edc3c871d8ec 100644 (file)
@@ -48,7 +48,7 @@ tui_exit (void)
 /* These implement the TUI interpreter.  */
 
 static void *
-tui_init (void)
+tui_init (int top_level)
 {
   /* Install exit handler to leave the screen in a good shape.  */
   atexit (tui_exit);