Implement =thread-selected notification.
authorVladimir Prus <vladimir@codesourcery.com>
Mon, 17 Nov 2008 16:43:34 +0000 (16:43 +0000)
committerVladimir Prus <vladimir@codesourcery.com>
Mon, 17 Nov 2008 16:43:34 +0000 (16:43 +0000)
        * mi/mi-common.h (struct mi_interp): New, moved from ...
        * mi/mi-interp.c: ...here.
        * mi/mi-main.c (mi_execute_command): If the thread changed
        as result of command, report that.

gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/mi/mi-common.h
gdb/mi/mi-interp.c
gdb/mi/mi-main.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.mi/mi-pthreads.exp
gdb/testsuite/lib/mi-support.exp

index 03b066089e19379670612646b170369ea9e1e469..2327ee17e901b4ad8532ff6b377f180c782e15e9 100644 (file)
@@ -1,3 +1,12 @@
+2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
+
+       Implement =thread-selected notification.
+
+        * mi/mi-common.h (struct mi_interp): New, moved from ...
+        * mi/mi-interp.c: ...here.
+        * mi/mi-main.c (mi_execute_command): If the thread changed
+        as result of command, report that.
+
 2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
 
        Implement continue/interrupt of thread groups.
index 18f665000c175f8f783d9a21233bbba4651f44a4..e0b6aa41bce4b0f17eb47f39715d7472f8b454ed 100644 (file)
@@ -1,3 +1,8 @@
+2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
+
+       * gdb.texinfo (GDB/MI Async Records): Document
+        =thread-selected.
+       
 2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
 
         * observer.texi (new_inferior, inferior_exit): New observers.
index 261d1c7e7b979d2f29caa6af99e07c5946eae1ee..26cf4b64cf25bd89bff25b43357e27a4587df78c 100644 (file)
@@ -19273,6 +19273,19 @@ A signal was received by the inferior.
 @itemx =thread-exited,id="@var{id}"
 A thread either was created, or has exited.  The @var{id} field
 contains the @value{GDBN} identifier of the thread.
+
+@item =thread-selected,id="@var{id}"
+Informs that the selected thread was changed as result of the last
+command.  This notification is not emitted as result of @code{-thread-select}
+command but is emitted whenever an MI command that is not documented
+to change the selected thread actually changes it.  In particular,
+invoking, directly or indirectly (via user-defined command), the CLI
+@code{thread} command, will generate this notification.
+
+We suggest that in response to this notification, front ends
+highlight the selected thread and cause subsequent commands to apply to
+that thread.
+
 @end table
 
 
index e47afd1ca3031896d765bbebad79f74254dea38e..8778e745a8d45e283bc015eac73023d5ddd58ffb 100644 (file)
@@ -41,4 +41,19 @@ enum async_reply_reason
 
 const char *async_reason_lookup (enum async_reply_reason reason);
 
+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;
+};
+
 #endif
index e05b1ad5e2baa4d3926100fd96f0e3e4f3429881..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);
index 6e5511fee99cc742204dddbd83e55a09e14724f4..7f5ec2f6778e4fe7217749327a54849541a8cd52 100644 (file)
@@ -44,6 +44,7 @@
 #include "gdb.h"
 #include "frame.h"
 #include "mi-main.h"
+#include "mi-common.h"
 #include "language.h"
 #include "valprint.h"
 #include "inferior.h"
@@ -1203,6 +1204,7 @@ mi_execute_command (char *cmd, int from_tty)
   if (command != NULL)
     {
       struct gdb_exception result;
+      ptid_t previous_ptid = inferior_ptid;
 
       if (do_timings)
        {
@@ -1227,6 +1229,41 @@ mi_execute_command (char *cmd, int from_tty)
          mi_out_rewind (uiout);
        }
 
+      if (/* The notifications are only output when the top-level
+            interpreter (specified on the command line) is MI.  */      
+         ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ()))
+         /* Don't try report anything if there are no threads -- 
+            the program is dead.  */
+         && thread_count () != 0
+         /* -thread-select explicitly changes thread. If frontend uses that
+            internally, we don't want to emit =thread-selected, since
+            =thread-selected is supposed to indicate user's intentions.  */
+         && strcmp (command->command, "thread-select") != 0)
+       {
+         struct mi_interp *mi = top_level_interpreter_data ();
+         struct thread_info *ti = inferior_thread ();
+         int report_change;
+
+         if (command->thread == -1)
+           {
+             report_change = !ptid_equal (previous_ptid, null_ptid)
+               && !ptid_equal (inferior_ptid, previous_ptid);
+           }
+         else
+           {
+             report_change = (ti->num != command->thread);
+           }
+
+         if (report_change)
+           {     
+             target_terminal_ours ();
+             fprintf_unfiltered (mi->event_channel, 
+                                 "thread-selected,id=\"%d\"",
+                                 ti->num);
+             gdb_flush (mi->event_channel);
+           }
+       }
+
       mi_parse_free (command);
     }
 
index 1c66e082afa8a43a1a5daebc370ad94c990ca8cd..58b2a2a176ed7892edce10a2179b6518fc1604e9 100644 (file)
@@ -1,3 +1,11 @@
+2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
+
+       * gdb.mi/mi-pthreads.exp (check_mi_thread_command_set): Make sure
+        "thread N" results in =thread-selected.
+        * lib/mi-support (mi_run_cmd, mi_expect_stop)
+        (mi_send_resuming_command_raw): Be prepared for
+        =thread-selected.
+       
 2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
 
         * gdb.mi/mi-nonstop.exp: Expect 'group-id' field.
index dbb3ece3ffa5d467885a616366b81b76885b190b..0ab57158798280656fd4244b2c3af6115050d641 100644 (file)
@@ -55,6 +55,12 @@ proc check_mi_thread_command_set {} {
       "\\^done,new-thread-id=\"$thread\",frame={.*}(,line=\"(-)?\[0-9\]+\",file=\".*\")?" \
       "check_mi_thread_command_set: -thread-select $thread"
   }
+
+  foreach thread $thread_list {
+      mi_gdb_test "-interpreter-exec console \"thread $thread\"" \
+          ".*\\^done\r\n=thread-selected,id=\"$thread\"" \
+          "check =thread-selected: thread $thread"
+  }
 }
 
 #
index 39db896306e831008def4e560ea92d589949fb06..56c1b9fd5102227eb60fb25df3477746196eeb93 100644 (file)
@@ -30,6 +30,8 @@ global mi_inferior_tty_name
 
 set MIFLAGS "-i=mi"
 
+set thread_selected_re "=thread-selected,id=\"\[0-9+\]\"\r\n"
+
 #
 # mi_gdb_exit -- exit the GDB, killing the target program if necessary
 #
@@ -775,6 +777,7 @@ proc mi_run_cmd {args} {
        return -1
     }
     global mi_gdb_prompt
+    global thread_selected_re
 
     if [target_info exists gdb_init_command] {
        send_gdb "[target_info gdb_init_command]\n";
@@ -816,7 +819,7 @@ proc mi_run_cmd {args} {
 
     send_gdb "220-exec-run $args\n"
     gdb_expect {
-       -re "220\\^running\r\n(\\*running,thread-id=\"\[^\"\]+\"\r\n|=thread-created,id=\"1\",group-id=\"\[0-9\]+\"\r\n)*${mi_gdb_prompt}" {
+       -re "220\\^running\r\n(\\*running,thread-id=\"\[^\"\]+\"\r\n|=thread-created,id=\"1\",group-id=\"\[0-9\]+\"\r\n)*(${thread_selected_re})?${mi_gdb_prompt}" {
        }
        timeout {
            perror "Unable to start target"
@@ -954,6 +957,7 @@ proc mi_expect_stop { reason func args file line extra test } {
     global decimal
     global fullname_syntax
     global async
+    global thread_selected_re
 
     set after_stopped ""
     set after_reason ""
@@ -1014,9 +1018,9 @@ proc mi_expect_stop { reason func args file line extra test } {
 
     set any "\[^\n\]*"
 
-    verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}\r\n$after_stopped$prompt_re"
+    verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n($thread_selected_re)?$prompt_re"
     gdb_expect {
-       -re "\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n$prompt_re" {
+       -re "\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=$any,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n($thread_selected_re)?$prompt_re" {
            pass "$test"
             return $expect_out(2,string)
        }
@@ -1430,10 +1434,11 @@ proc mi_tbreak {location} {
 proc mi_send_resuming_command_raw {command test} {
 
     global mi_gdb_prompt
+    global thread_selected_re
 
     send_gdb "$command\n"
     gdb_expect {
-        -re "\\^running\r\n\\*running,thread-id=\"\[^\"\]+\"\r\n${mi_gdb_prompt}" {
+        -re "\\^running\r\n\\*running,thread-id=\"\[^\"\]+\"\r\n($thread_selected_re)?${mi_gdb_prompt}" {
             # Note that lack of 'pass' call here -- this works around limitation
             # in DejaGNU xfail mechanism. mi-until.exp has this:
             #