Implement =thread-selected notification.
[deliverable/binutils-gdb.git] / gdb / mi / mi-interp.c
index 583c288a76d5e26a159a2c4ad4bf62cbc0b22d9b..5aa0e6c82551dcfd849283c54d4002032ea30db3 100644 (file)
 #include "mi-cmds.h"
 #include "mi-out.h"
 #include "mi-console.h"
+#include "mi-common.h"
 #include "observer.h"
 #include "gdbthread.h"
 
-struct mi_interp
-{
-  /* MI's output channels */
-  struct ui_file *out;
-  struct ui_file *err;
-  struct ui_file *log;
-  struct ui_file *targ;
-  struct ui_file *event_channel;
-
-  /* This is the interpreter for the mi... */
-  struct interp *mi2_interp;
-  struct interp *mi1_interp;
-  struct interp *mi_interp;
-};
-
 /* These are the interpreter setup, etc. functions for the MI interpreter */
 static void mi_execute_command_wrapper (char *cmd);
 static void mi_command_loop (int mi_version);
@@ -69,6 +55,9 @@ static void mi_on_normal_stop (struct bpstats *bs);
 
 static void mi_new_thread (struct thread_info *t);
 static void mi_thread_exit (struct thread_info *t);
+static void mi_new_inferior (int pid);
+static void mi_inferior_exit (int pid);
+static void mi_on_resume (ptid_t ptid);
 
 static void *
 mi_interpreter_init (int top_level)
@@ -93,7 +82,10 @@ mi_interpreter_init (int top_level)
     {
       observer_attach_new_thread (mi_new_thread);
       observer_attach_thread_exit (mi_thread_exit);
+      observer_attach_new_inferior (mi_new_inferior);
+      observer_attach_inferior_exit (mi_inferior_exit);
       observer_attach_normal_stop (mi_on_normal_stop);
+      observer_attach_target_resumed (mi_on_resume);
     }
 
   return mi;
@@ -173,7 +165,7 @@ mi_interpreter_prompt_p (void *data)
   return 0;
 }
 
-enum mi_cmd_result
+void
 mi_cmd_interpreter_exec (char *command, char **argv, int argc)
 {
   struct interp *interp_to_use;
@@ -215,20 +207,9 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
 
   mi_remove_notify_hooks ();
 
-  /* Okay, now let's see if the command set the inferior going...
-     Tricky point - have to do this AFTER resetting the interpreter, since
-     changing the interpreter will clear out all the continuations for
-     that interpreter... */
-
-  if (target_can_async_p () && target_executing)
-    {
-      fputs_unfiltered ("^running\n", raw_stdout);
-    }
-
   if (mi_error_message != NULL)
     error ("%s", mi_error_message);
   do_cleanups (old_chain);
-  return MI_CMD_DONE;
 }
 
 /*
@@ -298,7 +279,9 @@ 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);
+  fprintf_unfiltered (mi->event_channel, 
+                     "thread-created,id=\"%d\",group-id=\"%d\"", 
+                     t->num, t->ptid.pid);
   gdb_flush (mi->event_channel);
 }
 
@@ -307,10 +290,32 @@ mi_thread_exit (struct thread_info *t)
 {
   struct mi_interp *mi = top_level_interpreter_data ();
   target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel, "thread-exited,id=\"%d\"", t->num);
+  fprintf_unfiltered (mi->event_channel, 
+                     "thread-exited,id=\"%d\",group-id=\"%d\"", 
+                     t->num,t->ptid.pid);
   gdb_flush (mi->event_channel);
 }
 
+static void
+mi_new_inferior (int pid)
+{
+  struct mi_interp *mi = top_level_interpreter_data ();
+  target_terminal_ours ();
+  fprintf_unfiltered (mi->event_channel, "thread-group-created,id=\"%d\"", 
+                     pid);
+  gdb_flush (mi->event_channel);
+}
+
+static void
+mi_inferior_exit (int pid)
+{
+  struct mi_interp *mi = top_level_interpreter_data ();
+  target_terminal_ours ();
+  fprintf_unfiltered (mi->event_channel, "thread-group-exited,id=\"%d\"", 
+                     pid);
+  gdb_flush (mi->event_channel);  
+}
+
 static void
 mi_on_normal_stop (struct bpstats *bs)
 {
@@ -327,6 +332,53 @@ mi_on_normal_stop (struct bpstats *bs)
   gdb_flush (raw_stdout);
 }
 
+static void
+mi_on_resume (ptid_t ptid)
+{
+  /* To cater for older frontends, emit ^running, but do it only once
+     per each command.  We do it here, since at this point we know
+     that the target was successfully resumed, and in non-async mode,
+     we won't return back to MI interpreter code until the target
+     is done running, so delaying the output of "^running" until then
+     will make it impossible for frontend to know what's going on.
+
+     In future (MI3), we'll be outputting "^done" here.  */
+  if (!running_result_record_printed)
+    {
+      if (current_token)
+       fputs_unfiltered (current_token, raw_stdout);
+      fputs_unfiltered ("^running\n", raw_stdout);
+    }
+
+  if (PIDGET (ptid) == -1)
+    fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
+  else if (thread_count () == 0)
+    {
+      /* This is a target where for single-threaded programs the thread
+        table has zero threads.  Don't print any thread-id field.  */
+      fprintf_unfiltered (raw_stdout, "*running\n");
+    }
+  else
+    {
+      struct thread_info *ti = find_thread_pid (ptid);
+      gdb_assert (ti);
+      fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n", ti->num);
+    }
+
+  if (!running_result_record_printed)
+    {
+      running_result_record_printed = 1;
+      /* This is what gdb used to do historically -- printing prompt even if
+        it cannot actually accept any input.  This will be surely removed
+        for MI3, and may be removed even earler.  */
+      /* FIXME: review the use of target_is_async_p here -- is that
+        what we want? */
+      if (!target_is_async_p ())
+       fputs_unfiltered ("(gdb) \n", raw_stdout);
+    }
+  gdb_flush (raw_stdout);
+}
+
 extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
 
 void
This page took 0.02634 seconds and 4 git commands to generate.