Use observers to report stop events in MI.

* mi/mi-interp.c (mi_on_normal_stop): New.
        (mi_interpreter_init): Register mi_on_normal_stop.
        (mi_interpreter_exec_continuation): Remove.
        (mi_cmd_interpreter_exec): Don't register the above.
        * mi/mi-main.c (captured_mi_execute_command): Don't care
        about sync_execution.
        (mi_execute_async_cli_command): Don't install continuation.  Don't
        print *stopped.
        (mi_exec_async_cli_cmd_continuation): Remove.
This commit is contained in:
Vladimir Prus 2008-06-10 09:35:09 +00:00
parent f5871ec07b
commit f7f9a841a3
9 changed files with 114 additions and 89 deletions

View File

@ -1,3 +1,16 @@
2008-06-10 Vladimir Prus <vladimir@codesourcery.com>
Use observers to report stop events in MI.
* mi/mi-interp.c (mi_on_normal_stop): New.
(mi_interpreter_init): Register mi_on_normal_stop.
(mi_interpreter_exec_continuation): Remove.
(mi_cmd_interpreter_exec): Don't register the above.
* mi/mi-main.c (captured_mi_execute_command): Don't care
about sync_execution.
(mi_execute_async_cli_command): Don't install continuation. Don't
print *stopped.
(mi_exec_async_cli_cmd_continuation): Remove.
2008-06-10 Vladimir Prus <vladimir@codesourcery.com>
Suppress normal stop observer when it's problematic.

View File

@ -1383,10 +1383,7 @@ finish_command (char *arg, int from_tty)
arg1->data.pointer = breakpoint;
arg2->data.pointer = function;
add_continuation (finish_command_continuation, arg1);
/* Do this only if not running asynchronously or if the target
cannot do async execution. Otherwise, complete this command when
the target actually stops, in fetch_inferior_event. */
discard_cleanups (old_chain);
if (!target_can_async_p ())
do_all_continuations (0);

View File

@ -65,6 +65,7 @@ static void mi1_command_loop (void);
static void mi_insert_notify_hooks (void);
static void mi_remove_notify_hooks (void);
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);
@ -92,6 +93,7 @@ mi_interpreter_init (int top_level)
{
observer_attach_new_thread (mi_new_thread);
observer_attach_thread_exit (mi_thread_exit);
observer_attach_normal_stop (mi_on_normal_stop);
}
return mi;
@ -171,26 +173,6 @@ mi_interpreter_prompt_p (void *data)
return 0;
}
static void
mi_interpreter_exec_continuation (struct continuation_arg *arg, int error_p)
{
bpstat_do_actions (&stop_bpstat);
/* It's not clear what to do in the case of errror -- should we assume that
the target is stopped, or that it still runs? */
if (!target_executing)
{
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
else if (target_can_async_p ())
{
add_continuation (mi_interpreter_exec_continuation, NULL);
}
}
enum mi_cmd_result
mi_cmd_interpreter_exec (char *command, char **argv, int argc)
{
@ -241,7 +223,6 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
if (target_can_async_p () && target_executing)
{
fputs_unfiltered ("^running\n", raw_stdout);
add_continuation (mi_interpreter_exec_continuation, NULL);
}
if (mi_error_message != NULL)
@ -325,12 +306,27 @@ static void
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);
gdb_flush (mi->event_channel);
}
static void
mi_on_normal_stop (struct bpstats *bs)
{
/* Since this can be called when CLI command is executing,
using cli interpreter, be sure to use MI uiout for output,
not the current one. */
struct ui_out *uiout = interp_ui_out (top_level_interpreter ());
struct mi_interp *mi = top_level_interpreter_data ();
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
fputs_unfiltered ("\n", raw_stdout);
gdb_flush (raw_stdout);
}
extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
void

View File

@ -103,10 +103,6 @@ static void mi_execute_cli_command (const char *cmd, int args_p,
const char *args);
static enum mi_cmd_result mi_execute_async_cli_command (char *cli_command,
char **argv, int argc);
static void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg,
int error_p);
static int register_changed_p (int regnum, struct regcache *,
struct regcache *);
static void get_register (int regnum, int format);
@ -1087,15 +1083,11 @@ captured_mi_execute_command (struct ui_out *uiout, void *data)
fputs_unfiltered ("\n", raw_stdout);
}
else
/* The command does not want anything to be printed. In that
case, the command probably should not have written anything
to uiout, but in case it has written something, discard it. */
mi_out_rewind (uiout);
}
else if (sync_execution)
{
/* Don't print the prompt. We are executing the target in
synchronous mode. */
args->action = EXECUTE_COMMAND_SUPPRESS_PROMPT;
return;
}
break;
case CLI_COMMAND:
@ -1311,12 +1303,6 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc)
fputs_unfiltered (current_token, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
/* Ideally, we should be intalling continuation only when
the target is already running. However, this will break right now,
because continuation installed by the 'finish' command must be after
the continuation that prints *stopped. This issue will be
fixed soon. */
add_continuation (mi_exec_async_cli_cmd_continuation, NULL);
}
execute_command ( /*ui */ run, 0 /*from_tty */ );
@ -1332,30 +1318,13 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc)
/* Do this before doing any printing. It would appear that some
print code leaves garbage around in the buffer. */
do_cleanups (old_cleanups);
/* If the target was doing the operation synchronously we fake
the stopped message. */
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
if (do_timings)
print_diff_now (current_command_ts);
fputs_unfiltered ("\n", raw_stdout);
return MI_CMD_QUIET;
}
return MI_CMD_DONE;
}
void
mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg, int error_p)
{
/* Assume 'error' means that target is stopped, too. */
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
void
mi_load_progress (const char *section_name,
unsigned long sent_so_far,

View File

@ -1,3 +1,14 @@
2008-06-10 Vladimir Prus <vladimir@codesourcery.com>
* gdb.mi/mi-break.exp (test_ignore_count): Adjust stopped pattern.
* gdb.mi/mi-syn-frame.exp: Use mi_expect_stop instead of direct
testing of stopped.
* gdb.mi/mi2-syn-frame.exp: Likewise.
* lib/mi-support.exp (default_mi_gdb_start): Call detect_async.
(async, detect_async): New.
(mi_expect_stop, mi_continue_to_line): Adjust expectation
depending on if we're running in sync or async mode.
2008-06-09 Tom Tromey <tromey@redhat.com>
* gdb.base/completion.exp: New tests for field name completion

View File

@ -159,7 +159,7 @@ proc test_ignore_count {} {
mi_run_cmd
gdb_expect {
-re ".*func=\"callme\".*args=\\\[\{name=\"i\",value=\"2\"\}\\\].*\r\n$mi_gdb_prompt$" {
-re ".*\\*stopped.*func=\"callme\".*args=\\\[\{name=\"i\",value=\"2\"\}\\\].*\r\n($mi_gdb_prompt)?$" {
pass "run to breakpoint with ignore count"
}
-re ".*$mi_gdb_prompt$" {

View File

@ -58,9 +58,7 @@ mi_gdb_test "403-exec-continue" \
"403\\^running" \
"testing exec continue"
# Presently, the *stopped notification for this case does not include
# any information. This can be considered a bug.
mi_gdb_test "" "\\*stopped" "finished exec continue"
mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue"
mi_gdb_test "404-stack-list-frames 0 0" \
"404\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \
@ -88,7 +86,7 @@ mi_gdb_test "407-stack-list-frames" \
mi_gdb_test "408-exec-continue" "408\\^running"
mi_gdb_test "" ".*\\*stopped.*" "finished exec continue"
mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue"
mi_gdb_test "409-stack-list-frames 0 0" \
"409\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \

View File

@ -56,15 +56,11 @@ mi_gdb_test "402-stack-list-frames" "402\\^done,stack=\\\[frame=\{level=\"0\",ad
# Continue back to main()
#
send_gdb "403-exec-continue\n"
gdb_expect {
-re "403\\^running\[\r\n\]+${my_mi_gdb_prompt}.*\\\*stopped\[\r\n\]+${my_mi_gdb_prompt}$" {
pass "403-exec-continue"
}
timeout {
fail "403-exec-continue"
}
}
mi_gdb_test "403-exec-continue" \
"403\\^running" \
"testing exec continue"
mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue"
mi_gdb_test "404-stack-list-frames 0 0" \
"404\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \
@ -89,16 +85,9 @@ mi_gdb_test "407-stack-list-frames" \
"407\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"subroutine\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"handler\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"<signal handler called>\"\},.*frame=\{level=\"$decimal\",addr=\"$hex\",func=\"have_a_very_merry_interrupt\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\},frame=\{level=\"$decimal\",addr=\"$hex\",func=\"<function called from gdb>\"\},frame=\{level=\"$decimal\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",line=\"$decimal\"\}.*\\\]" \
"list stack frames"
mi_gdb_test "408-exec-continue" "408\\^running"
send_gdb "408-exec-continue\n"
gdb_expect {
-re "408\\^running\[\r\n\]+${my_mi_gdb_prompt}.*\\\*stopped\[\r\n\]+${my_mi_gdb_prompt}$" {
pass "408-exec-continue"
}
timeout {
fail "408-exec-continue"
}
}
mi_expect_stop "really-no-reason" "" "" "" "" "" "finished exec continue"
mi_gdb_test "409-stack-list-frames 0 0" \
"409\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"main\",file=\".*mi-syn-frame.c\",fullname=\"${fullname_syntax}${srcfile}\",line=\"$decimal\"\}.*\\\]" \

View File

@ -227,6 +227,8 @@ proc default_mi_gdb_start { args } {
}
}
detect_async
return 0;
}
@ -911,6 +913,30 @@ proc mi_step { test } {
return [mi_step_to {.*} {.*} {.*} {.*} $test]
}
set async "unknown"
proc detect_async {} {
global async
global mi_gdb_prompt
if { $async == "unknown" } {
send_gdb "maint show linux-async\n"
gdb_expect {
-re ".*Controlling the GNU/Linux inferior in asynchronous mode is on...*$mi_gdb_prompt$" {
set async 1
}
-re ".*$mi_gdb_prompt$" {
set async 0
}
timeout {
set async 0
}
}
}
return $async
}
# Wait for MI *stopped notification to appear.
# The REASON, FUNC, ARGS, FILE and LINE are regular expressions
# to match against whatever is output in *stopped. ARGS should
@ -933,6 +959,7 @@ proc mi_expect_stop { reason func args file line extra test } {
global hex
global decimal
global fullname_syntax
global async
set after_stopped ""
set after_reason ""
@ -944,10 +971,28 @@ proc mi_expect_stop { reason func args file line extra test } {
set after_stopped [lindex $extra 0]
}
if {$async} {
set prompt_re ""
} else {
set prompt_re "$mi_gdb_prompt"
}
if { $reason == "really-no-reason" } {
gdb_expect {
-re "\\*stopped\r\n$prompt_re$" {
pass "$test"
}
timeout {
fail "$test (unknown output after running)"
}
}
return
}
if { $reason == "exited-normally" } {
gdb_expect {
-re "\\*stopped,reason=\"exited-normally\"\r\n$mi_gdb_prompt$" {
-re "\\*stopped,reason=\"exited-normally\"\r\n$prompt_re$" {
pass "$test"
}
-re ".*$mi_gdb_prompt$" {fail "continue to end (2)"}
@ -973,17 +1018,17 @@ proc mi_expect_stop { reason func args file line extra test } {
set a $after_reason
verbose -log "mi_expect_stop: expecting: .*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n$mi_gdb_prompt$"
verbose -log "mi_expect_stop: expecting: .*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n$prompt_re$"
gdb_expect {
-re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n$mi_gdb_prompt$" {
-re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n$prompt_re$" {
pass "$test"
return $expect_out(2,string)
}
-re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",fullname=\"${fullname_syntax}.*\",line=\"\[0-9\]*\"\}.*\r\n$mi_gdb_prompt$" {
-re ".*\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",fullname=\"${fullname_syntax}.*\",line=\"\[0-9\]*\"\}.*\r\n$prompt_re$" {
fail "$test (stopped at wrong place)"
return -1
}
-re ".*\r\n${mi_gdb_prompt}$" {
-re ".*\r\n$mi_gdb_prompt$" {
fail "$test (unknown output after running)"
return -1
}
@ -1388,9 +1433,16 @@ proc mi_continue_to_line {location test} {
proc mi_get_stop_line {test} {
global mi_gdb_prompt
global async
if {$async} {
set prompt_re ""
} else {
set prompt_re "$mi_gdb_prompt"
}
gdb_expect {
-re ".*line=\"(.*)\".*\r\n$mi_gdb_prompt$" {
-re ".*line=\"(.*)\".*\r\n$prompt_re$" {
return $expect_out(1,string)
}
-re ".*$mi_gdb_prompt$" {