From 66bb093b5faddd76e3e307ce59024ac703e8b892 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 17 Nov 2008 16:43:34 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 9 +++++++ gdb/doc/ChangeLog | 5 ++++ gdb/doc/gdb.texinfo | 13 ++++++++++ gdb/mi/mi-common.h | 15 +++++++++++ gdb/mi/mi-interp.c | 16 +----------- gdb/mi/mi-main.c | 37 ++++++++++++++++++++++++++++ gdb/testsuite/ChangeLog | 8 ++++++ gdb/testsuite/gdb.mi/mi-pthreads.exp | 6 +++++ gdb/testsuite/lib/mi-support.exp | 13 +++++++--- 9 files changed, 103 insertions(+), 19 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 03b066089e1..2327ee17e90 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2008-11-17 Vladimir Prus + + 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 Implement continue/interrupt of thread groups. diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 18f665000c1..e0b6aa41bce 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2008-11-17 Vladimir Prus + + * gdb.texinfo (GDB/MI Async Records): Document + =thread-selected. + 2008-11-17 Vladimir Prus * observer.texi (new_inferior, inferior_exit): New observers. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 261d1c7e7b9..26cf4b64cf2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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 diff --git a/gdb/mi/mi-common.h b/gdb/mi/mi-common.h index e47afd1ca30..8778e745a8d 100644 --- a/gdb/mi/mi-common.h +++ b/gdb/mi/mi-common.h @@ -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 diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c index e05b1ad5e2b..5aa0e6c8255 100644 --- a/gdb/mi/mi-interp.c +++ b/gdb/mi/mi-interp.c @@ -31,24 +31,10 @@ #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); diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 6e5511fee99..7f5ec2f6778 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -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); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1c66e082afa..58b2a2a176e 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2008-11-17 Vladimir Prus + + * 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 * gdb.mi/mi-nonstop.exp: Expect 'group-id' field. diff --git a/gdb/testsuite/gdb.mi/mi-pthreads.exp b/gdb/testsuite/gdb.mi/mi-pthreads.exp index dbb3ece3ffa..0ab57158798 100644 --- a/gdb/testsuite/gdb.mi/mi-pthreads.exp +++ b/gdb/testsuite/gdb.mi/mi-pthreads.exp @@ -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" + } } # diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp index 39db896306e..56c1b9fd510 100644 --- a/gdb/testsuite/lib/mi-support.exp +++ b/gdb/testsuite/lib/mi-support.exp @@ -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: # -- 2.30.2