summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog49
-rw-r--r--gdb/Makefile.in9
-rw-r--r--gdb/remote-notif.c270
-rw-r--r--gdb/remote-notif.h85
-rw-r--r--gdb/remote.c462
-rw-r--r--gdb/remote.h3
6 files changed, 657 insertions, 221 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index cd282322235..e98564575f5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,54 @@
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.
+
+2012-12-15 Yao Qi <yao@codesourcery.com>
+
* remote.c (discard_pending_stop_replies): Update declaration.
(remote_detach_1, extended_remote_mourn_1): Likewise.
(discard_pending_stop_replies): Change parameter from PID to
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 22f2acbaa94..8e7b589deb0 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -507,7 +507,8 @@ SER_HARDWIRE = @SER_HARDWIRE@
# The `remote' debugging target is supported for most architectures,
# but not all (e.g. 960)
-REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o
+REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o \
+ remote-notif.o
# This is remote-sim.o if a simulator is to be linked in.
SIM_OBS = @SIM_OBS@
@@ -729,7 +730,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
proc-service.list progspace.c \
prologue-value.c psymtab.c \
- regcache.c reggroups.c remote.c remote-fileio.c reverse.c \
+ regcache.c reggroups.c remote.c remote-fileio.c remote-notif.c reverse.c \
sentinel-frame.c \
serial.c ser-base.c ser-unix.c skip.c \
solib.c solib-target.c source.c \
@@ -774,7 +775,7 @@ c-lang.h d-lang.h go-lang.h frame.h event-loop.h block.h cli/cli-setshow.h \
cli/cli-decode.h cli/cli-cmds.h cli/cli-dump.h cli/cli-utils.h \
cli/cli-script.h macrotab.h symtab.h version.h \
gnulib/import/string.in.h gnulib/import/str-two-way.h \
-gnulib/import/stdint.in.h remote.h gdb.h sparc-nat.h \
+gnulib/import/stdint.in.h remote.h remote-notif.h gdb.h sparc-nat.h \
gdbthread.h dwarf2-frame.h dwarf2-frame-tailcall.h nbsd-nat.h dcache.h \
amd64-nat.h s390-tdep.h arm-linux-tdep.h exceptions.h macroscope.h \
gdbarch.h bsd-uthread.h common/gdb_stat.h memory-map.h memrange.h \
@@ -826,7 +827,7 @@ gnulib/import/extra/snippet/arg-nonnull.h gnulib/import/extra/snippet/c++defs.h
gnulib/import/extra/snippet/warn-on-use.h \
gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
-common/format.h common/host-defs.h utils.h \
+common/format.h common/host-defs.h utils.h common/queue.h \
common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h gdb_bfd.h
# Header files that already have srcdir in them, or which are in objdir.
diff --git a/gdb/remote-notif.c b/gdb/remote-notif.c
new file mode 100644
index 00000000000..5a72f408137
--- /dev/null
+++ b/gdb/remote-notif.c
@@ -0,0 +1,270 @@
+/* Remote notification in GDB protocol
+
+ Copyright (C) 1988-2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Remote async notification is sent from remote target over RSP.
+ Each type of notification is represented by an object of
+ 'struct notif', which has a field 'pending_reply'. It is not
+ NULL when GDB receives a notification from GDBserver, but hasn't
+ acknowledge yet. Before GDB acknowledges the notification,
+ GDBserver shouldn't send notification again (see the header comments
+ in gdbserver/notif.c).
+
+ Notifications are processed in an almost-unified approach for both
+ all-stop mode and non-stop mode, except the timing to process them.
+ In non-stop mode, notifications are processed in
+ remote_async_get_pending_events_handler, while in all-stop mode,
+ they are processed in remote_resume. */
+
+#include "defs.h"
+#include "remote.h"
+#include "remote-notif.h"
+#include "observer.h"
+#include "event-loop.h"
+#include "target.h"
+#include "inferior.h"
+
+#include <string.h>
+
+unsigned int notif_debug = 0;
+
+/* Supported clients of notifications. */
+
+static struct notif_client *notifs[] =
+{
+ &notif_client_stop,
+};
+
+static void do_notif_event_xfree (void *arg);
+
+/* Parse the BUF for the expected notification NC, and send packet to
+ acknowledge. */
+
+void
+remote_notif_ack (struct notif_client *nc, char *buf)
+{
+ struct notif_event *event = nc->alloc_event ();
+ struct cleanup *old_chain
+ = make_cleanup (do_notif_event_xfree, event);
+
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog, "notif: ack '%s'\n",
+ nc->ack_command);
+
+ nc->parse (nc, buf, event);
+ nc->ack (nc, buf, event);
+
+ discard_cleanups (old_chain);
+}
+
+/* Parse the BUF for the expected notification NC. */
+
+struct notif_event *
+remote_notif_parse (struct notif_client *nc, char *buf)
+{
+ struct notif_event *event = nc->alloc_event ();
+ struct cleanup *old_chain
+ = make_cleanup (do_notif_event_xfree, event);
+
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog, "notif: parse '%s'\n", nc->name);
+
+ nc->parse (nc, buf, event);
+
+ discard_cleanups (old_chain);
+ return event;
+}
+
+DECLARE_QUEUE_P (notif_client_p);
+DEFINE_QUEUE_P (notif_client_p);
+
+static QUEUE(notif_client_p) *notif_queue;
+
+/* Process notifications one by one. EXCEPT is not expected in
+ the queue. */
+
+void
+remote_notif_process (struct notif_client *except)
+{
+ while (!QUEUE_is_empty (notif_client_p, notif_queue))
+ {
+ struct notif_client *nc = QUEUE_deque (notif_client_p,
+ notif_queue);
+
+ gdb_assert (nc != except);
+
+ if (nc->can_get_pending_events (nc))
+ remote_notif_get_pending_events (nc);
+ }
+}
+
+static void
+remote_async_get_pending_events_handler (gdb_client_data data)
+{
+ gdb_assert (non_stop);
+ remote_notif_process (NULL);
+}
+
+/* Asynchronous signal handle registered as event loop source for when
+ the remote sent us a notification. The registered callback
+ will do a ACK 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;
+
+/* Register async_event_handler for notification. */
+
+void
+remote_notif_register_async_event_handler (void)
+{
+ remote_async_get_pending_events_token
+ = create_async_event_handler (remote_async_get_pending_events_handler,
+ NULL);
+}
+
+/* Unregister async_event_handler for notification. */
+
+void
+remote_notif_unregister_async_event_handler (void)
+{
+ if (remote_async_get_pending_events_token)
+ delete_async_event_handler (&remote_async_get_pending_events_token);
+}
+
+/* Remote notification handler. */
+
+void
+handle_notification (char *buf)
+{
+ struct notif_client *nc = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (notifs); i++)
+ {
+ nc = notifs[i];
+ if (strncmp (buf, nc->name, strlen (nc->name)) == 0
+ && buf[strlen (nc->name)] == ':')
+ break;
+ }
+
+ /* We ignore notifications we don't recognize, for compatibility
+ with newer stubs. */
+ if (nc == NULL)
+ return;
+
+ if (nc->pending_event)
+ {
+ /* We've already parsed the in-flight reply, but the stub for some
+ reason thought we didn't, possibly due to timeout on its side.
+ Just ignore it. */
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "notif: ignoring resent notification\n");
+ }
+ else
+ {
+ struct notif_event *event
+ = remote_notif_parse (nc, buf + strlen (nc->name) + 1);
+
+ /* Be careful to only set it after parsing, since an error
+ may be thrown then. */
+ nc->pending_event = event;
+
+ /* Notify the event loop there's a stop reply to acknowledge
+ and that there may be more events to fetch. */
+ QUEUE_enque (notif_client_p, notif_queue, nc);
+ if (non_stop)
+ {
+ /* In non-stop, We mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
+ in order to go on what we were doing and postpone
+ querying notification events to some point safe to do so.
+ See details in the function comment of
+ remote.c:remote_notif_get_pending_events.
+
+ In all-stop, GDB may be blocked to wait for the reply, we
+ shouldn't return to event loop until the expected reply
+ arrives. For example:
+
+ 1.1) --> vCont;c
+ GDB expects getting stop reply 'T05 thread:2'.
+ 1.2) <-- %Notif
+ <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
+
+ After step #1.2, we return to the event loop, which
+ notices there is a new event on the
+ REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and calls the
+ handler, which will send 'vNotif' packet.
+ 1.3) --> vNotif
+ It is not safe to start a new sequence, because target
+ is still running and GDB is expecting the stop reply
+ from stub.
+
+ To solve this, whenever we parse a notification
+ successfully, we don't mark the
+ REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and let GDB blocked
+ there as before to get the sequence done.
+
+ 2.1) --> vCont;c
+ GDB expects getting stop reply 'T05 thread:2'
+ 2.2) <-- %Notif
+ <Don't mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
+ 2.3) <-- T05 thread:2
+
+ These pending notifications can be processed later. */
+ mark_async_event_handler (remote_async_get_pending_events_token);
+ }
+
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "notif: Notification '%s' captured\n",
+ nc->name);
+ }
+}
+
+/* Cleanup wrapper. */
+
+static void
+do_notif_event_xfree (void *arg)
+{
+ struct notif_event *event = arg;
+
+ if (event && event->dtr)
+ event->dtr (event);
+
+ xfree (event);
+}
+
+static void
+notif_xfree (struct notif_client *notif)
+{
+ if (notif->pending_event != NULL
+ && notif->pending_event->dtr != NULL)
+ notif->pending_event->dtr (notif->pending_event);
+
+ xfree (notif->pending_event);
+ xfree (notif);
+}
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_notif;
+
+void
+_initialize_notif (void)
+{
+ notif_queue = QUEUE_alloc (notif_client_p, notif_xfree);
+}
diff --git a/gdb/remote-notif.h b/gdb/remote-notif.h
new file mode 100644
index 00000000000..92c4bb611bd
--- /dev/null
+++ b/gdb/remote-notif.h
@@ -0,0 +1,85 @@
+/* Remote notification in GDB protocol
+
+ Copyright (C) 1988-2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_NOTIF_H
+#define REMOTE_NOTIF_H
+
+#include "queue.h"
+
+/* An event of a type of async remote notification. */
+
+struct notif_event
+{
+ /* Destructor. Release everything from SELF, but not SELF
+ itself. */
+ void (*dtr) (struct notif_event *self);
+};
+
+/* A client to a sort of async remote notification. */
+
+typedef struct notif_client
+{
+ /* The name of notification packet. */
+ const char *name;
+
+ /* The packet to acknowledge a previous reply. */
+ const char *ack_command;
+
+ /* Parse BUF to get the expected event and update EVENT. This
+ function may throw exception if contents in BUF is not the
+ expected event. */
+ void (*parse) (struct notif_client *self, char *buf,
+ struct notif_event *event);
+
+ /* Send field <ack_command> to remote, and do some checking. If
+ something wrong, throw an exception. */
+ void (*ack) (struct notif_client *self, char *buf,
+ struct notif_event *event);
+
+ /* Check this notification client can get pending events in
+ 'remote_notif_process'. */
+ int (*can_get_pending_events) (struct notif_client *self);
+
+ /* Allocate an event. */
+ struct notif_event *(*alloc_event) (void);
+
+ /* One pending event. This is where we keep it until it is
+ acknowledged. When there is a notification packet, parse it,
+ and create an object of 'struct notif_event' to assign to
+ it. This field is unchanged until GDB starts to ack this
+ notification (which is done by
+ remote.c:remote_notif_pending_replies). */
+ struct notif_event *pending_event;
+} *notif_client_p;
+
+void remote_notif_ack (struct notif_client *nc, char *buf);
+struct notif_event *remote_notif_parse (struct notif_client *nc,
+ char *buf);
+
+void handle_notification (char *buf);
+
+void remote_notif_register_async_event_handler (void);
+void remote_notif_unregister_async_event_handler (void);
+
+void remote_notif_process (struct notif_client *except);
+extern struct notif_client notif_client_stop;
+
+extern unsigned int notif_debug;
+
+#endif /* REMOTE_NOTIF_H */
diff --git a/gdb/remote.c b/gdb/remote.c
index 3f4436728e3..a6a6227c614 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 = &notif_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 (&notif_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 (&notif_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, &param);
+}
- 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, &param);
+ 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 (&notif_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 (&notif_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, _("\
diff --git a/gdb/remote.h b/gdb/remote.h
index 3adc54ee6c5..4cd38f637db 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -19,6 +19,8 @@
#ifndef REMOTE_H
#define REMOTE_H
+#include "remote-notif.h"
+
struct target_desc;
/* Read a packet from the remote machine, with error checking, and
@@ -59,4 +61,5 @@ extern int remote_register_number_and_offset (struct gdbarch *gdbarch,
int regnum, int *pnum,
int *poffset);
+extern void remote_notif_get_pending_events (struct notif_client *np);
#endif