diff options
author | Yao Qi <yao@codesourcery.com> | 2012-12-15 03:50:22 +0000 |
---|---|---|
committer | Yao Qi <yao@codesourcery.com> | 2012-12-15 03:50:22 +0000 |
commit | 722247f1cb9ab5678ad078ba0ba02070cb03a34b (patch) | |
tree | a2f4c7ea5d329c76827c2b97ff93953609b8785e /gdb/remote.c | |
parent | 5f4cf0bb27e5c49c5581c104e24770bde830af85 (diff) | |
download | gdb-722247f1cb9ab5678ad078ba0ba02070cb03a34b.zip gdb-722247f1cb9ab5678ad078ba0ba02070cb03a34b.tar.gz gdb-722247f1cb9ab5678ad078ba0ba02070cb03a34b.tar.bz2 |
gdb/
2012-12-15 Yao Qi <yao@codesourcery.com>
* Makefile.in (REMOTE_OBS): Add "remote-notif.o".
(SFILES): Add "remote-notif.c".
(HFILES_NO_SRCDIR): Add "remote-notif.h" and "common/queue.h".
* remote-notif.c: New. Factored out from remote.c.
* remote-notif.h: New.
* remote.c: Include "remote-notif.h".
(stop_reply_xmalloc, do_stop_reply_xfree):
(remote_parse_stop_reply, remote_get_pending_stop_replies):
(remote_async_get_pending_events_handler): Remove declarations.
(remote_parse_stop_reply): Declare.
(pending_stop_reply): Remove.
(remote_async_get_pending_events_token): Move to
remote-notif.c.
(remote_close): Replace 'delete_async_event_handler' with
remote_notif_unregister_async_event_handler.
Don't call discard_pending_stop_replies.
(remote_start_remote): Replace code with remote_notif_parse
and remote_notif_get_pending_replies.
(remote_open_1): Replace 'create_async_event_handler' with
remote_notif_register_async_event_handler.
(extended_remote_attach_1): Call remote_notif_parse and
notif_stop_reply_push.
(struct stop_reply) <next>: Remove.
<base>: New field.
Callers update.
(stop_reply_queue): Change its type.
(stop_reply_xmalloc, do_stop_reply_xfree): Remove.
(remote_notif_remove_all): New.
(discard_pending_stop_replies): Update.
(remote_notif_stop_ack, stop_reply_dtr): New.
(remote_notif_stop_alloc_event): New.
(notif_client_stop): New variable.
(stop_reply_match_ptid, stop_reply_match_ptid_and_ws: New.
(queued_stop_reply, peek_stop_reply): Adjust.
(remote_get_pending_stop_replies): Rename to
remote_notif_get_pending_events.
(handle_notification): Move to remote-notif.c.
(remote_async_get_pending_events_handler): Likewise.
(remote_wait_as): Adjust to call remote_notif_parse.
Call 'getpkt_or_notif_sane' instead of 'getpkt_sane'.
Return minus_one_ptid early if gets a notification.
(remote_wait): Call QUEUE_is_empty (notif_reply_p).
(_initialize_remote): Call QUEUE_alloc. Update caller.
(remote_resume): Call 'remote_notif_process' in all-stop mode.
* remote.h: Include "remote-notif.h".
(remote_notif_get_pending_replies): Declare.
Diffstat (limited to 'gdb/remote.c')
-rw-r--r-- | gdb/remote.c | 462 |
1 files changed, 245 insertions, 217 deletions
diff --git a/gdb/remote.c b/gdb/remote.c index 3f44367..a6a6227 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -34,6 +34,7 @@ #include "gdb-stabs.h" #include "gdbthread.h" #include "remote.h" +#include "remote-notif.h" #include "regcache.h" #include "value.h" #include "gdb_assert.h" @@ -223,17 +224,13 @@ static void remote_check_symbols (struct objfile *objfile); void _initialize_remote (void); struct stop_reply; -static struct stop_reply *stop_reply_xmalloc (void); static void stop_reply_xfree (struct stop_reply *); -static void do_stop_reply_xfree (void *arg); -static void remote_parse_stop_reply (char *buf, struct stop_reply *); +static void remote_parse_stop_reply (char *, struct stop_reply *); static void push_stop_reply (struct stop_reply *); -static void remote_get_pending_stop_replies (void); static void discard_pending_stop_replies (struct inferior *); static int peek_stop_reply (ptid_t ptid); static void remote_async_inferior_event_handler (gdb_client_data); -static void remote_async_get_pending_events_handler (gdb_client_data); static void remote_terminal_ours (void); @@ -245,11 +242,6 @@ static int remote_supports_cond_breakpoints (void); static int remote_can_run_breakpoint_commands (void); -/* The non-stop remote protocol provisions for one pending stop reply. - This is where we keep it until it is acknowledged. */ - -static struct stop_reply *pending_stop_reply = NULL; - /* For "remote". */ static struct cmd_list_element *remote_cmdlist; @@ -1402,12 +1394,6 @@ static struct async_signal_handler *sigint_remote_token; static struct async_event_handler *remote_async_inferior_event_token; -/* Asynchronous signal handle registered as event loop source for when - the remote sent us a %Stop notification. The registered callback - will do a vStopped sequence to pull the rest of the events out of - the remote side into our event queue. */ - -static struct async_event_handler *remote_async_get_pending_events_token; static ptid_t magic_null_ptid; @@ -3030,8 +3016,8 @@ remote_close (int quitting) if (remote_async_inferior_event_token) delete_async_event_handler (&remote_async_inferior_event_token); - if (remote_async_get_pending_events_token) - delete_async_event_handler (&remote_async_get_pending_events_token); + + remote_notif_unregister_async_event_handler (); } /* Query the remote side for the text, data and bss offsets. */ @@ -3453,19 +3439,13 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) mechanism. */ if (strcmp (rs->buf, "OK") != 0) { - struct stop_reply *stop_reply; - struct cleanup *old_chain; + struct notif_client *notif = ¬if_client_stop; - stop_reply = stop_reply_xmalloc (); - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - - remote_parse_stop_reply (rs->buf, stop_reply); - discard_cleanups (old_chain); - - /* get_pending_stop_replies acks this one, and gets the rest - out. */ - pending_stop_reply = stop_reply; - remote_get_pending_stop_replies (); + /* remote_notif_get_pending_replies acks this one, and gets + the rest out. */ + notif_client_stop.pending_event + = remote_notif_parse (notif, rs->buf); + remote_notif_get_pending_events (notif); /* Make sure that threads that were stopped remain stopped. */ @@ -4225,9 +4205,7 @@ remote_open_1 (char *name, int from_tty, remote_async_inferior_event_token = create_async_event_handler (remote_async_inferior_event_handler, NULL); - remote_async_get_pending_events_token - = create_async_event_handler (remote_async_get_pending_events_handler, - NULL); + remote_notif_register_async_event_handler (); /* Reset the target state; these things will be queried either by remote_query_supported or as they are needed. */ @@ -4482,14 +4460,10 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty) if (target_can_async_p ()) { - struct stop_reply *stop_reply; - struct cleanup *old_chain; + struct notif_event *reply + = remote_notif_parse (¬if_client_stop, wait_status); - stop_reply = stop_reply_xmalloc (); - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - remote_parse_stop_reply (wait_status, stop_reply); - discard_cleanups (old_chain); - push_stop_reply (stop_reply); + push_stop_reply ((struct stop_reply *) reply); target_async (inferior_event_handler, 0); } @@ -4783,6 +4757,15 @@ remote_resume (struct target_ops *ops, struct remote_state *rs = get_remote_state (); char *buf; + /* In all-stop, we can't mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN + (explained in remote-notif.c:handle_notification) so + remote_notif_process is not called. We need find a place where + it is safe to start a 'vNotif' sequence. It is good to do it + before resuming inferior, because inferior was stopped and no RSP + traffic at that moment. */ + if (!non_stop) + remote_notif_process (¬if_client_stop); + last_sent_signal = siggnal; last_sent_step = step; @@ -5116,10 +5099,11 @@ typedef struct cached_reg DEF_VEC_O(cached_reg_t); -struct stop_reply +typedef struct stop_reply { - struct stop_reply *next; + struct notif_event base; + /* The identifier of the thread about this event */ ptid_t ptid; struct target_waitstatus ws; @@ -5137,19 +5121,18 @@ struct stop_reply int replay_event; int core; -}; - -/* The list of already fetched and acknowledged stop events. */ -static struct stop_reply *stop_reply_queue; - -static struct stop_reply * -stop_reply_xmalloc (void) -{ - struct stop_reply *r = XMALLOC (struct stop_reply); +} *stop_reply_p; - r->next = NULL; - return r; -} +DECLARE_QUEUE_P (stop_reply_p); +DEFINE_QUEUE_P (stop_reply_p); +/* The list of already fetched and acknowledged stop events. This + queue is used for notification Stop, and other notifications + don't need queue for their events, because the notification events + of Stop can't be consumed immediately, so that events should be + queued first, and be consumed by remote_wait_{ns,as} one per + time. Other notifications can consume their events immediately, + so queue is not needed for them. */ +static QUEUE (stop_reply_p) *stop_reply_queue; static void stop_reply_xfree (struct stop_reply *r) @@ -5161,51 +5144,169 @@ stop_reply_xfree (struct stop_reply *r) } } +static void +remote_notif_stop_parse (struct notif_client *self, char *buf, + struct notif_event *event) +{ + remote_parse_stop_reply (buf, (struct stop_reply *) event); +} + +static void +remote_notif_stop_ack (struct notif_client *self, char *buf, + struct notif_event *event) +{ + struct stop_reply *stop_reply = (struct stop_reply *) event; + + /* acknowledge */ + putpkt ((char *) self->ack_command); + + if (stop_reply->ws.kind == TARGET_WAITKIND_IGNORE) + /* We got an unknown stop reply. */ + error (_("Unknown stop reply")); + + push_stop_reply (stop_reply); +} + +static int +remote_notif_stop_can_get_pending_events (struct notif_client *self) +{ + /* We can't get pending events in remote_notif_process for + notification stop, and we have to do this in remote_wait_ns + instead. If we fetch all queued events from stub, remote stub + may exit and we have no chance to process them back in + remote_wait_ns. */ + mark_async_event_handler (remote_async_inferior_event_token); + return 0; +} + +static void +stop_reply_dtr (struct notif_event *event) +{ + struct stop_reply *r = (struct stop_reply *) event; + + VEC_free (cached_reg_t, r->regcache); +} + +static struct notif_event * +remote_notif_stop_alloc_reply (void) +{ + struct notif_event *r + = (struct notif_event *) XMALLOC (struct stop_reply); + + r->dtr = stop_reply_dtr; + + return r; +} + +/* A client of notification Stop. */ + +struct notif_client notif_client_stop = +{ + "Stop", + "vStopped", + remote_notif_stop_parse, + remote_notif_stop_ack, + remote_notif_stop_can_get_pending_events, + remote_notif_stop_alloc_reply, + NULL, +}; + +/* A parameter to pass data in and out. */ + +struct queue_iter_param +{ + void *input; + struct stop_reply *output; +}; + +/* Remove all queue elements meet the condition it checks. */ + +static int +remote_notif_remove_all (QUEUE (stop_reply_p) *q, + QUEUE_ITER (stop_reply_p) *iter, + stop_reply_p event, + void *data) +{ + struct queue_iter_param *param = data; + struct inferior *inf = param->input; + + if (inf == NULL || ptid_get_pid (event->ptid) == inf->pid) + { + stop_reply_xfree (event); + QUEUE_remove_elem (stop_reply_p, q, iter); + } + + return 1; +} + /* Discard all pending stop replies of inferior INF. If INF is NULL, discard everything. */ static void discard_pending_stop_replies (struct inferior *inf) { - struct stop_reply *prev = NULL, *reply, *next; + int i; + struct queue_iter_param param; + struct stop_reply *reply + = (struct stop_reply *) notif_client_stop.pending_event; /* Discard the in-flight notification. */ - if (pending_stop_reply != NULL + if (reply != NULL && (inf == NULL - || ptid_get_pid (pending_stop_reply->ptid) == inf->pid)) + || ptid_get_pid (reply->ptid) == inf->pid)) { - stop_reply_xfree (pending_stop_reply); - pending_stop_reply = NULL; + stop_reply_xfree (reply); + notif_client_stop.pending_event = NULL; } + param.input = inf; + param.output = NULL; /* Discard the stop replies we have already pulled with vStopped. */ - for (reply = stop_reply_queue; reply; reply = next) - { - next = reply->next; - if (inf == NULL - || ptid_get_pid (reply->ptid) == inf->pid) - { - if (reply == stop_reply_queue) - stop_reply_queue = reply->next; - else - prev->next = reply->next; + QUEUE_iterate (stop_reply_p, stop_reply_queue, + remote_notif_remove_all, ¶m); +} - stop_reply_xfree (reply); - } - else - prev = reply; +/* A parameter to pass data in and out. */ + +static int +remote_notif_remove_once_on_match (QUEUE (stop_reply_p) *q, + QUEUE_ITER (stop_reply_p) *iter, + stop_reply_p event, + void *data) +{ + struct queue_iter_param *param = data; + ptid_t *ptid = param->input; + + if (ptid_match (event->ptid, *ptid)) + { + param->output = event; + QUEUE_remove_elem (stop_reply_p, q, iter); + return 0; } + + return 1; } -/* Cleanup wrapper. */ +/* Remove the first reply in 'stop_reply_queue' which matches + PTID. */ -static void -do_stop_reply_xfree (void *arg) +static struct stop_reply * +remote_notif_remove_queued_reply (ptid_t ptid) { - struct stop_reply *r = arg; + struct queue_iter_param param; + + param.input = &ptid; + param.output = NULL; + + QUEUE_iterate (stop_reply_p, stop_reply_queue, + remote_notif_remove_once_on_match, ¶m); + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: discard queued event: 'Stop' in %s\n", + target_pid_to_str (ptid)); - stop_reply_xfree (r); + return param.output; } /* Look for a queued stop reply belonging to PTID. If one is found, @@ -5216,29 +5317,13 @@ do_stop_reply_xfree (void *arg) static struct stop_reply * queued_stop_reply (ptid_t ptid) { - struct stop_reply *it; - struct stop_reply **it_link; - - it = stop_reply_queue; - it_link = &stop_reply_queue; - while (it) - { - if (ptid_match (it->ptid, ptid)) - { - *it_link = it->next; - it->next = NULL; - break; - } - - it_link = &it->next; - it = *it_link; - } + struct stop_reply *r = remote_notif_remove_queued_reply (ptid); - if (stop_reply_queue) + if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue)) /* There's still at least an event left. */ mark_async_event_handler (remote_async_inferior_event_token); - return it; + return r; } /* Push a fully parsed stop reply in the stop reply queue. Since we @@ -5248,38 +5333,37 @@ queued_stop_reply (ptid_t ptid) static void push_stop_reply (struct stop_reply *new_event) { - struct stop_reply *event; - - if (stop_reply_queue) - { - for (event = stop_reply_queue; - event && event->next; - event = event->next) - ; + QUEUE_enque (stop_reply_p, stop_reply_queue, new_event); - event->next = new_event; - } - else - stop_reply_queue = new_event; + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: push 'Stop' %s to queue %d\n", + target_pid_to_str (new_event->ptid), + QUEUE_length (stop_reply_p, + stop_reply_queue)); mark_async_event_handler (remote_async_inferior_event_token); } +static int +stop_reply_match_ptid_and_ws (QUEUE (stop_reply_p) *q, + QUEUE_ITER (stop_reply_p) *iter, + struct stop_reply *event, + void *data) +{ + ptid_t *ptid = data; + + return !(ptid_equal (*ptid, event->ptid) + && event->ws.kind == TARGET_WAITKIND_STOPPED); +} + /* Returns true if we have a stop reply for PTID. */ static int peek_stop_reply (ptid_t ptid) { - struct stop_reply *it; - - for (it = stop_reply_queue; it; it = it->next) - if (ptid_equal (ptid, it->ptid)) - { - if (it->ws.kind == TARGET_WAITKIND_STOPPED) - return 1; - } - - return 0; + return !QUEUE_iterate (stop_reply_p, stop_reply_queue, + stop_reply_match_ptid_and_ws, &ptid); } /* Parse the stop reply in BUF. Either the function succeeds, and the @@ -5495,13 +5579,14 @@ Packet: '%s'\n"), error (_("No process or thread specified in stop reply: %s"), buf); } -/* When the stub wants to tell GDB about a new stop reply, it sends a - stop notification (%Stop). Those can come it at any time, hence, - we have to make sure that any pending putpkt/getpkt sequence we're - making is finished, before querying the stub for more events with - vStopped. E.g., if we started a vStopped sequence immediatelly - upon receiving the %Stop notification, something like this could - happen: +/* When the stub wants to tell GDB about a new notification reply, it + sends a notification (%Stop, for example). Those can come it at + any time, hence, we have to make sure that any pending + putpkt/getpkt sequence we're making is finished, before querying + the stub for more events with the corresponding ack command + (vStopped, for example). E.g., if we started a vStopped sequence + immediately upon receiving the notification, something like this + could happen: 1.1) --> Hg 1 1.2) <-- OK @@ -5536,19 +5621,21 @@ Packet: '%s'\n"), 2.9) --> OK */ -static void -remote_get_pending_stop_replies (void) +void +remote_notif_get_pending_events (struct notif_client *nc) { struct remote_state *rs = get_remote_state (); - if (pending_stop_reply) + if (nc->pending_event) { - /* acknowledge */ - putpkt ("vStopped"); + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: process: '%s' ack pending event\n", + nc->name); - /* Now we can rely on it. */ - push_stop_reply (pending_stop_reply); - pending_stop_reply = NULL; + /* acknowledge */ + nc->ack (nc, rs->buf, nc->pending_event); + nc->pending_event = NULL; while (1) { @@ -5556,31 +5643,18 @@ remote_get_pending_stop_replies (void) if (strcmp (rs->buf, "OK") == 0) break; else - { - struct cleanup *old_chain; - struct stop_reply *stop_reply = stop_reply_xmalloc (); - - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - remote_parse_stop_reply (rs->buf, stop_reply); - - /* acknowledge */ - putpkt ("vStopped"); - - if (stop_reply->ws.kind != TARGET_WAITKIND_IGNORE) - { - /* Now we can rely on it. */ - discard_cleanups (old_chain); - push_stop_reply (stop_reply); - } - else - /* We got an unknown stop reply. */ - do_cleanups (old_chain); - } + remote_notif_ack (nc, rs->buf); } } + else + { + if (notif_debug) + fprintf_unfiltered (gdb_stdlog, + "notif: process: '%s' no pending reply\n", + nc->name); + } } - /* Called when it is decided that STOP_REPLY holds the info of the event that is to be returned to the core. This function always destroys STOP_REPLY. */ @@ -5664,8 +5738,8 @@ remote_wait_ns (ptid_t ptid, struct target_waitstatus *status, int options) /* Acknowledge a pending stop reply that may have arrived in the mean time. */ - if (pending_stop_reply != NULL) - remote_get_pending_stop_replies (); + if (notif_client_stop.pending_event != NULL) + remote_notif_get_pending_events (¬if_client_stop); /* If indeed we noticed a stop reply, we're done. */ stop_reply = queued_stop_reply (ptid); @@ -5712,6 +5786,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) else { int ret; + int is_notif; if (!target_is_async_p ()) { @@ -5729,7 +5804,14 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) _never_ wait for ever -> test on target_is_async_p(). However, before we do that we need to ensure that the caller knows how to take the target into/out of async mode. */ - ret = getpkt_sane (&rs->buf, &rs->buf_size, wait_forever_enabled_p); + ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size, + wait_forever_enabled_p, &is_notif); + + /* GDB gets a notification. Return to core as this event is + not interesting. */ + if (ret != -1 && is_notif) + return minus_one_ptid; + if (!target_is_async_p ()) signal (SIGINT, ofunc); } @@ -5761,13 +5843,10 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options) break; case 'T': case 'S': case 'X': case 'W': { - struct stop_reply *stop_reply; - struct cleanup *old_chain; + struct stop_reply *stop_reply + = (struct stop_reply *) remote_notif_parse (¬if_client_stop, + rs->buf); - stop_reply = stop_reply_xmalloc (); - old_chain = make_cleanup (do_stop_reply_xfree, stop_reply); - remote_parse_stop_reply (buf, stop_reply); - discard_cleanups (old_chain); event_ptid = process_stop_reply (stop_reply, status); break; } @@ -5848,7 +5927,7 @@ remote_wait (struct target_ops *ops, { /* If there are are events left in the queue tell the event loop to return here. */ - if (stop_reply_queue) + if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue)) mark_async_event_handler (remote_async_inferior_event_token); } @@ -6743,52 +6822,6 @@ remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len) /* Return what we have. Let higher layers handle partial reads. */ return i; } - - -/* Remote notification handler. */ - -static void -handle_notification (char *buf) -{ - if (strncmp (buf, "Stop:", 5) == 0) - { - if (pending_stop_reply) - { - /* We've already parsed the in-flight stop-reply, but the - stub for some reason thought we didn't, possibly due to - timeout on its side. Just ignore it. */ - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "ignoring resent notification\n"); - } - else - { - struct cleanup *old_chain; - struct stop_reply *reply = stop_reply_xmalloc (); - - old_chain = make_cleanup (do_stop_reply_xfree, reply); - - remote_parse_stop_reply (buf + 5, reply); - - discard_cleanups (old_chain); - - /* Be careful to only set it after parsing, since an error - may be thrown then. */ - pending_stop_reply = reply; - - /* Notify the event loop there's a stop reply to acknowledge - and that there may be more events to fetch. */ - mark_async_event_handler (remote_async_get_pending_events_token); - - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "stop notification captured\n"); - } - } - else - { - /* We ignore notifications we don't recognize, for compatibility - with newer stubs. */ - } -} /* Read or write LEN bytes from inferior memory at MEMADDR, @@ -11197,12 +11230,6 @@ remote_async_inferior_event_handler (gdb_client_data data) } static void -remote_async_get_pending_events_handler (gdb_client_data data) -{ - remote_get_pending_stop_replies (); -} - -static void remote_async (void (*callback) (enum inferior_event_type event_type, void *context), void *context) { @@ -11357,6 +11384,7 @@ _initialize_remote (void) init_remote_threadtests (); #endif + stop_reply_queue = QUEUE_alloc (stop_reply_p, stop_reply_xfree); /* set/show remote ... */ add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, _("\ |