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.
This commit is contained in:
parent
8dd4f202ec
commit
66bb093b5f
|
@ -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>
|
2008-11-17 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
Implement continue/interrupt of thread groups.
|
Implement continue/interrupt of thread groups.
|
||||||
|
|
|
@ -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>
|
2008-11-17 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
* observer.texi (new_inferior, inferior_exit): New observers.
|
* observer.texi (new_inferior, inferior_exit): New observers.
|
||||||
|
|
|
@ -19273,6 +19273,19 @@ A signal was received by the inferior.
|
||||||
@itemx =thread-exited,id="@var{id}"
|
@itemx =thread-exited,id="@var{id}"
|
||||||
A thread either was created, or has exited. The @var{id} field
|
A thread either was created, or has exited. The @var{id} field
|
||||||
contains the @value{GDBN} identifier of the thread.
|
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
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,4 +41,19 @@ enum async_reply_reason
|
||||||
|
|
||||||
const char *async_reason_lookup (enum async_reply_reason 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
|
#endif
|
||||||
|
|
|
@ -31,24 +31,10 @@
|
||||||
#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 "mi-common.h"
|
||||||
#include "observer.h"
|
#include "observer.h"
|
||||||
#include "gdbthread.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 */
|
/* These are the interpreter setup, etc. functions for the MI interpreter */
|
||||||
static void mi_execute_command_wrapper (char *cmd);
|
static void mi_execute_command_wrapper (char *cmd);
|
||||||
static void mi_command_loop (int mi_version);
|
static void mi_command_loop (int mi_version);
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "gdb.h"
|
#include "gdb.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "mi-main.h"
|
#include "mi-main.h"
|
||||||
|
#include "mi-common.h"
|
||||||
#include "language.h"
|
#include "language.h"
|
||||||
#include "valprint.h"
|
#include "valprint.h"
|
||||||
#include "inferior.h"
|
#include "inferior.h"
|
||||||
|
@ -1203,6 +1204,7 @@ mi_execute_command (char *cmd, int from_tty)
|
||||||
if (command != NULL)
|
if (command != NULL)
|
||||||
{
|
{
|
||||||
struct gdb_exception result;
|
struct gdb_exception result;
|
||||||
|
ptid_t previous_ptid = inferior_ptid;
|
||||||
|
|
||||||
if (do_timings)
|
if (do_timings)
|
||||||
{
|
{
|
||||||
|
@ -1227,6 +1229,41 @@ mi_execute_command (char *cmd, int from_tty)
|
||||||
mi_out_rewind (uiout);
|
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);
|
mi_parse_free (command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
2008-11-17 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
* gdb.mi/mi-nonstop.exp: Expect 'group-id' field.
|
* gdb.mi/mi-nonstop.exp: Expect 'group-id' field.
|
||||||
|
|
|
@ -55,6 +55,12 @@ proc check_mi_thread_command_set {} {
|
||||||
"\\^done,new-thread-id=\"$thread\",frame={.*}(,line=\"(-)?\[0-9\]+\",file=\".*\")?" \
|
"\\^done,new-thread-id=\"$thread\",frame={.*}(,line=\"(-)?\[0-9\]+\",file=\".*\")?" \
|
||||||
"check_mi_thread_command_set: -thread-select $thread"
|
"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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -30,6 +30,8 @@ global mi_inferior_tty_name
|
||||||
|
|
||||||
set MIFLAGS "-i=mi"
|
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
|
# mi_gdb_exit -- exit the GDB, killing the target program if necessary
|
||||||
#
|
#
|
||||||
|
@ -775,6 +777,7 @@ proc mi_run_cmd {args} {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
global mi_gdb_prompt
|
global mi_gdb_prompt
|
||||||
|
global thread_selected_re
|
||||||
|
|
||||||
if [target_info exists gdb_init_command] {
|
if [target_info exists gdb_init_command] {
|
||||||
send_gdb "[target_info gdb_init_command]\n";
|
send_gdb "[target_info gdb_init_command]\n";
|
||||||
|
@ -816,7 +819,7 @@ proc mi_run_cmd {args} {
|
||||||
|
|
||||||
send_gdb "220-exec-run $args\n"
|
send_gdb "220-exec-run $args\n"
|
||||||
gdb_expect {
|
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 {
|
timeout {
|
||||||
perror "Unable to start target"
|
perror "Unable to start target"
|
||||||
|
@ -954,6 +957,7 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||||
global decimal
|
global decimal
|
||||||
global fullname_syntax
|
global fullname_syntax
|
||||||
global async
|
global async
|
||||||
|
global thread_selected_re
|
||||||
|
|
||||||
set after_stopped ""
|
set after_stopped ""
|
||||||
set after_reason ""
|
set after_reason ""
|
||||||
|
@ -1014,9 +1018,9 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||||
|
|
||||||
set any "\[^\n\]*"
|
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 {
|
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"
|
pass "$test"
|
||||||
return $expect_out(2,string)
|
return $expect_out(2,string)
|
||||||
}
|
}
|
||||||
|
@ -1430,10 +1434,11 @@ proc mi_tbreak {location} {
|
||||||
proc mi_send_resuming_command_raw {command test} {
|
proc mi_send_resuming_command_raw {command test} {
|
||||||
|
|
||||||
global mi_gdb_prompt
|
global mi_gdb_prompt
|
||||||
|
global thread_selected_re
|
||||||
|
|
||||||
send_gdb "$command\n"
|
send_gdb "$command\n"
|
||||||
gdb_expect {
|
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
|
# Note that lack of 'pass' call here -- this works around limitation
|
||||||
# in DejaGNU xfail mechanism. mi-until.exp has this:
|
# in DejaGNU xfail mechanism. mi-until.exp has this:
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in New Issue