This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/4] de-couple %Stop from notification: gdb


This patch is to de-couple vStopped/%Stop from notification in gdb side.

gdb:

2012-08-24  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'.
	* remote-notif.c: New.  Moved from remote.c.
	* remote-notif.h: New.
	* remote.c: Include 'remote-notif.h'.
	Remove declarations of stop_reply_xmalloc, stop_reply_xfree,
	do_stop_reply_xfree, remote_parse_stop_reply, push_stop_reply,
	remote_get_pending_stop_replies, and
	remote_async_get_pending_events_handler.
	Declare remote_parse_stop_reply.
	Remove variable pending_stop_reply.
	(struct remote_state): Move to remote.h.
	(get_remote_state): Remove 'static'.
	(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.
	(remote_start_remote): Call remote_notif_parse and
	remote_notif_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_reply_push.
	(struct stop_reply) <next>: Remove.
	<base>: New field.
	Remove stop_reply_queue.
	(stop_reply_xmalloc, stop_reply_xfree, do_stop_reply_xfree): Remove
	(remote_notif_ack_stop, stop_reply_dtr): New.
	(remote_notif_alloc_reply_stop): New.
	(notif_packet_stop): New variable.
	(stop_reply_match_pid, stop_reply_match_ptid): New.
	(discard_pending_stop_replies): Adjust to call
	remote_notif_discard_pending_replies only.
	(queued_stop_reply, peek_stop_reply): Adjust.
	(push_stop_reply): Add one more parameter 'queue', and rename to
	notif_reply_push.
	(remote_get_pending_stop_replies): Move to remote-notif.c.
	(handle_notification): Likewise.
	(remote_async_get_pending_events_handler): Likewise.
	(remote_wait_as): Adjust to call remote_notif_parse.
	(remote_wait): Call gdb_queue_notif_reply_is_empty.
	* remote.h (struct remote_state): Moved from remote.c.
	Declare notif_reply_push.
	Include "target.h" and "remote-notif.h".
---
 gdb/Makefile.in    |    9 +-
 gdb/remote-notif.c |  285 ++++++++++++++++++++++++++++++
 gdb/remote-notif.h |   83 +++++++++
 gdb/remote.c       |  484 ++++++++++++----------------------------------------
 gdb/remote.h       |  103 +++++++++++
 5 files changed, 585 insertions(+), 379 deletions(-)
 create mode 100644 gdb/remote-notif.c
 create mode 100644 gdb/remote-notif.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5d5574e..26e12ae 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -503,7 +503,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@
@@ -725,7 +726,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 reverse.c remote-notif.c \
 	sentinel-frame.c \
 	serial.c ser-base.c ser-unix.c skip.c \
 	solib.c solib-target.c source.c \
@@ -778,7 +779,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 gdb_stat.h memory-map.h	memrange.h \
@@ -830,7 +831,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/gdb_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 0000000..ca7f821
--- /dev/null
+++ b/gdb/remote-notif.c
@@ -0,0 +1,285 @@
+/* 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/>.  */
+
+#include "defs.h"
+#include "remote.h"
+#include "remote-notif.h"
+#include "event-loop.h"
+#include "target.h"
+
+#include <string.h>
+
+extern struct remote_state *get_remote_state (void);
+
+/* Supported notifications.  */
+
+static struct notif *notifs[] =
+{
+  &notif_packet_stop,
+};
+
+/* Parse the BUF for the expected notification NP, and send packet to
+   acknowledge.  */
+
+struct notif_reply *
+remote_notif_ack (struct notif *np, char *buf)
+{
+  struct notif_reply *reply = np->alloc_reply ();
+  struct cleanup *old_chain = make_cleanup (do_notif_reply_xfree, reply);
+
+  np->parse (np, buf, reply);
+  np->ack (np, buf, reply);
+
+  discard_cleanups (old_chain);
+
+  return reply;
+}
+
+/* Parse the BUF for the expected notification NP.  */
+
+struct notif_reply *
+remote_notif_parse (struct notif *np, char *buf)
+{
+  struct notif_reply *reply = np->alloc_reply ();
+  struct cleanup *old_chain = make_cleanup (do_notif_reply_xfree, reply);
+
+  np->parse (np, buf, reply);
+
+  discard_cleanups (old_chain);
+
+  return reply;
+}
+
+/* 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
+    1.3) --> g
+    1.4) <-- %Stop
+    1.5) --> vStopped
+    1.6) <-- (registers reply to step #1.3)
+
+   Obviously, the reply in step #1.6 would be unexpected to a vStopped
+   query.
+
+   To solve this, whenever we parse a %Stop notification successfully,
+   we mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN, and carry on
+   doing whatever we were doing:
+
+    2.1) --> Hg 1
+    2.2) <-- OK
+    2.3) --> g
+    2.4) <-- %Stop
+      <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
+    2.5) <-- (registers reply to step #2.3)
+
+   Eventualy after step #2.5, we return to the event loop, which
+   notices there's an event on the
+   REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN event and calls the
+   associated callback --- the function below.  At this point, we're
+   always safe to start a vStopped sequence. :
+
+    2.6) --> vStopped
+    2.7) <-- T05 thread:2
+    2.8) --> vStopped
+    2.9) --> OK
+*/
+
+void
+remote_notif_pending_replies (struct notif *np)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  if (np->pending_reply)
+    {
+      /* acknowledge */
+      putpkt ((char *) np->ack_command);
+
+      /* Now we can rely on it.  */
+      notif_reply_push (np->pending_reply, np->ack_queue);
+      np->pending_reply = NULL;
+
+      while (1)
+	{
+	  getpkt (&rs->buf, &rs->buf_size, 0);
+	  if (strcmp (rs->buf, "OK") == 0)
+	    break;
+	  else
+	    {
+	      struct notif_reply *reply = remote_notif_ack (np, rs->buf);
+
+	      notif_reply_push (reply, np->ack_queue);
+	    }
+	}
+    }
+}
+
+static void
+remote_async_get_pending_events_handler (gdb_client_data data)
+{
+  remote_notif_pending_replies (*((struct notif **) data));
+}
+
+/* The current notif_packet we are processing.  */
+
+static struct notif *current_notif;
+
+/* 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;
+
+/* 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,
+				  &current_notif);
+}
+
+/* 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);
+}
+
+extern int remote_debug;
+
+/* Remote notification handler.  */
+
+void
+handle_notification (char *buf)
+{
+  struct notif *np = NULL;
+  int i;
+
+  for (i = 0; i < sizeof (notifs) / sizeof (notifs[0]); i++)
+    {
+      np = notifs[i];
+      if (strncmp (buf, np->name, strlen (np->name)) == 0
+	  && buf[strlen (np->name)] == ':')
+	break;
+    }
+
+  /* We ignore notifications we don't recognize, for compatibility
+     with newer stubs.  */
+  if (np == NULL)
+    return;
+
+  if (np->pending_reply)
+    {
+      /* 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 (remote_debug)
+	fprintf_unfiltered (gdb_stdlog, "ignoring resent notification\n");
+    }
+  else
+    {
+      struct notif_reply *reply
+	= remote_notif_parse (np, buf+ strlen (np->name) + 1);
+
+      /* Be careful to only set it after parsing, since an error
+	 may be thrown then.  */
+      np->pending_reply = reply;
+
+      /* Notify the event loop there's a stop reply to acknowledge
+	 and that there may be more events to fetch.  */
+      current_notif = np;
+      mark_async_event_handler (remote_async_get_pending_events_token);
+
+      if (remote_debug)
+	fprintf_unfiltered (gdb_stdlog, "Notification '%s' captured\n",
+			    np->name);
+    }
+}
+
+/* Free REPLY.  */
+
+void
+notif_reply_xfree (struct notif_reply *reply)
+{
+  if (reply && reply->dtr)
+    reply->dtr (reply);
+
+  xfree (reply);
+}
+
+/* Cleanup wrapper.  */
+
+void
+do_notif_reply_xfree (void *arg)
+{
+  struct notif_reply *reply = arg;
+
+  notif_reply_xfree (reply);
+}
+
+void
+gdb_queue_ele_notif_reply_xfree (struct notif_reply *reply)
+{
+  /* A placehoder, nothing to release for 'struct notif_reply', and its sub
+     classes.  */
+}
+
+QUEUE_DEFINE_TYPE(notif_reply);
+
+/* Discard the pending replies in NP if function MATCH returns true.  */
+
+void
+remote_notif_discard_pending_replies (struct notif *np,
+				      int (*match) (struct notif_reply *,
+						    void *),
+				      void *data)
+{
+  struct notif_reply *reply = NULL;
+
+  /* Discard the in-flight notification.  */
+  if (np->pending_reply != NULL && match (np->pending_reply, data))
+    {
+      notif_reply_xfree (np->pending_reply);
+      np->pending_reply = NULL;
+    }
+
+  /* Discard the replies we have already pulled with ack.  */
+  reply = gdb_queue_notif_reply_remove (np->ack_queue, match, data);
+  notif_reply_xfree (reply);
+}
+
+void
+initialize_notif (void)
+{
+  int i;
+
+  for (i = 0; i < sizeof (notifs) / sizeof (notifs[0]); i++)
+    notifs[i]->ack_queue = gdb_queue_notif_reply_alloc ();
+}
diff --git a/gdb/remote-notif.h b/gdb/remote-notif.h
new file mode 100644
index 0000000..b9a753b
--- /dev/null
+++ b/gdb/remote-notif.h
@@ -0,0 +1,83 @@
+/* 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 "gdb_queue.h"
+
+/* A reply for a remote notification.  */
+
+struct notif_reply
+{
+  /* Destructor.  Release everything from SELF, but not SELF itself.  */
+  void (*dtr) (struct notif_reply *self);
+};
+
+QUEUE_DECLARE (notif_reply);
+
+/* Data and operations related to notification packet.  */
+
+struct notif
+{
+  /* 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 reply.  This function may throw exception
+     if contents in BUF is not the expected reply.  */
+  void (*parse) (struct notif *self, char *buf, void *data);
+
+  /* Send field <ack_command> to remote, and do some checking.  If something
+     wrong, throw exception.  */
+  void (*ack) (struct notif *self, char *buf, void *data);
+
+  /* Allocate a reply.  */
+  struct notif_reply *(*alloc_reply) (void);
+
+  /* One pending reply.  This is where we keep it until it is acknowledge.  */
+  struct notif_reply *pending_reply;
+
+  /* The list of already fetched and acknowledged events.  */
+  struct gdb_queue_notif_reply *ack_queue;
+};
+
+struct notif_reply *remote_notif_ack (struct notif *np, char *buf);
+struct notif_reply *remote_notif_parse (struct notif *np, char *buf);
+
+void handle_notification (char *buf);
+
+void remote_notif_register_async_event_handler (void);
+void remote_notif_unregister_async_event_handler (void);
+
+void notif_reply_xfree (struct notif_reply *reply);
+void do_notif_reply_xfree (void *arg);
+
+void remote_notif_pending_replies (struct notif *np);
+void remote_notif_discard_pending_replies (struct notif *np,
+					   int (*match) (struct notif_reply *,
+							 void *),
+					   void *data);
+
+extern struct notif notif_packet_stop;
+
+void initialize_notif (void);
+
+#endif /* REMOTE_NOTIF_H */
diff --git a/gdb/remote.c b/gdb/remote.c
index 2db2c9d..278d4bd 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,12 @@ 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 push_stop_reply (struct stop_reply *);
-static void remote_get_pending_stop_replies (void);
+
 static void discard_pending_stop_replies (int pid);
 static int peek_stop_reply (ptid_t ptid);
+static void remote_parse_stop_reply (char *buf, struct stop_reply *event);
 
 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 +241,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;
@@ -259,103 +250,6 @@ static struct cmd_list_element *remote_cmdlist;
 static struct cmd_list_element *remote_set_cmdlist;
 static struct cmd_list_element *remote_show_cmdlist;
 
-/* Description of the remote protocol state for the currently
-   connected target.  This is per-target state, and independent of the
-   selected architecture.  */
-
-struct remote_state
-{
-  /* A buffer to use for incoming packets, and its current size.  The
-     buffer is grown dynamically for larger incoming packets.
-     Outgoing packets may also be constructed in this buffer.
-     BUF_SIZE is always at least REMOTE_PACKET_SIZE;
-     REMOTE_PACKET_SIZE should be used to limit the length of outgoing
-     packets.  */
-  char *buf;
-  long buf_size;
-
-  /* True if we're going through initial connection setup (finding out
-     about the remote side's threads, relocating symbols, etc.).  */
-  int starting_up;
-
-  /* If we negotiated packet size explicitly (and thus can bypass
-     heuristics for the largest packet size that will not overflow
-     a buffer in the stub), this will be set to that packet size.
-     Otherwise zero, meaning to use the guessed size.  */
-  long explicit_packet_size;
-
-  /* remote_wait is normally called when the target is running and
-     waits for a stop reply packet.  But sometimes we need to call it
-     when the target is already stopped.  We can send a "?" packet
-     and have remote_wait read the response.  Or, if we already have
-     the response, we can stash it in BUF and tell remote_wait to
-     skip calling getpkt.  This flag is set when BUF contains a
-     stop reply packet and the target is not waiting.  */
-  int cached_wait_status;
-
-  /* True, if in no ack mode.  That is, neither GDB nor the stub will
-     expect acks from each other.  The connection is assumed to be
-     reliable.  */
-  int noack_mode;
-
-  /* True if we're connected in extended remote mode.  */
-  int extended;
-
-  /* True if the stub reported support for multi-process
-     extensions.  */
-  int multi_process_aware;
-
-  /* True if we resumed the target and we're waiting for the target to
-     stop.  In the mean time, we can't start another command/query.
-     The remote server wouldn't be ready to process it, so we'd
-     timeout waiting for a reply that would never come and eventually
-     we'd close the connection.  This can happen in asynchronous mode
-     because we allow GDB commands while the target is running.  */
-  int waiting_for_stop_reply;
-
-  /* True if the stub reports support for non-stop mode.  */
-  int non_stop_aware;
-
-  /* True if the stub reports support for vCont;t.  */
-  int support_vCont_t;
-
-  /* True if the stub reports support for conditional tracepoints.  */
-  int cond_tracepoints;
-
-  /* True if the stub reports support for target-side breakpoint
-     conditions.  */
-  int cond_breakpoints;
-
-  /* True if the stub reports support for target-side breakpoint
-     commands.  */
-  int breakpoint_commands;
-
-  /* True if the stub reports support for fast tracepoints.  */
-  int fast_tracepoints;
-
-  /* True if the stub reports support for static tracepoints.  */
-  int static_tracepoints;
-
-  /* True if the stub reports support for installing tracepoint while
-     tracing.  */
-  int install_in_trace;
-
-  /* True if the stub can continue running a trace while GDB is
-     disconnected.  */
-  int disconnected_tracing;
-
-  /* True if the stub reports support for enabling and disabling
-     tracepoints while a trace experiment is running.  */
-  int enable_disable_tracepoints;
-
-  /* True if the stub can collect strings using tracenz bytecode.  */
-  int string_tracing;
-
-  /* Nonzero if the user has pressed Ctrl-C, but the target hasn't
-     responded to that.  */
-  int ctrlc_pending_p;
-};
-
 /* Private data that we'll store in (struct thread_info)->private.  */
 struct private_thread_info
 {
@@ -528,9 +422,11 @@ get_remote_arch_state (void)
   return gdbarch_data (target_gdbarch, remote_gdbarch_data_handle);
 }
 
+extern struct remote_state *get_remote_state (void);
+
 /* Fetch the global remote target state.  */
 
-static struct remote_state *
+struct remote_state *
 get_remote_state (void)
 {
   /* Make sure that the remote architecture state has been
@@ -1402,12 +1298,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;
@@ -3027,8 +2917,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.  */
@@ -3450,19 +3340,15 @@ 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;
-
-	  stop_reply = stop_reply_xmalloc ();
-	  old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
+	  struct stop_reply *stop_reply
+	    = (struct stop_reply *) remote_notif_parse (&notif_packet_stop,
+							rs->buf);
 
-	  remote_parse_stop_reply (rs->buf, stop_reply);
-	  discard_cleanups (old_chain);
 
-	  /* get_pending_stop_replies acks this one, and gets the rest
+	  /* remote_notif_pending_replies acks this one, and gets the rest
 	     out.  */
-	  pending_stop_reply = stop_reply;
-	  remote_get_pending_stop_replies ();
+	  notif_packet_stop.pending_reply = (struct notif_reply *) stop_reply;
+	  remote_notif_pending_replies (&notif_packet_stop);
 
 	  /* Make sure that threads that were stopped remain
 	     stopped.  */
@@ -4222,9 +4108,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.  */
@@ -4384,6 +4268,8 @@ remote_disconnect (struct target_ops *target, char *args, int from_tty)
     puts_filtered ("Ending remote debugging.\n");
 }
 
+struct stop_reply;
+
 /* Attach to the process specified by ARGS.  If FROM_TTY is non-zero,
    be chatty about it.  */
 
@@ -4480,14 +4366,12 @@ 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 stop_reply *stop_reply
+	    = (struct stop_reply *) remote_notif_parse (&notif_packet_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);
+	  notif_reply_push ((struct notif_reply *) stop_reply,
+			    notif_packet_stop.ack_queue);
 
 	  target_async (inferior_event_handler, 0);
 	}
@@ -5116,7 +5000,7 @@ DEF_VEC_O(cached_reg_t);
 
 struct stop_reply
 {
-  struct stop_reply *next;
+  struct notif_reply base;
 
   ptid_t ptid;
 
@@ -5137,26 +5021,62 @@ struct stop_reply
   int core;
 };
 
-/* The list of already fetched and acknowledged stop events.  */
-static struct stop_reply *stop_reply_queue;
+static void
+remote_notif_parse_stop (struct notif *self, char *buf, void *data)
+{
+  remote_parse_stop_reply (buf, (struct stop_reply *) data);
+}
 
-static struct stop_reply *
-stop_reply_xmalloc (void)
+static void
+remote_notif_ack_stop (struct notif *self, char *buf, void *data)
 {
-  struct stop_reply *r = XMALLOC (struct stop_reply);
+  struct stop_reply *stop_reply = (struct stop_reply *) data;
 
-  r->next = NULL;
-  return r;
+  /* acknowledge */
+  putpkt ((char *) self->ack_command);
+
+  if (stop_reply->ws.kind == TARGET_WAITKIND_IGNORE)
+      /* We got an unknown stop reply.  */
+      error (_("Unknown stop reply"));
 }
 
 static void
-stop_reply_xfree (struct stop_reply *r)
+stop_reply_dtr (struct notif_reply *reply)
 {
+  struct stop_reply *r = (struct stop_reply *) reply;
+
   if (r != NULL)
-    {
-      VEC_free (cached_reg_t, r->regcache);
-      xfree (r);
-    }
+    VEC_free (cached_reg_t, r->regcache);
+}
+
+static struct notif_reply *
+remote_notif_alloc_reply_stop (void)
+{
+  struct notif_reply *r = (struct notif_reply *) XMALLOC (struct stop_reply);
+
+  r->dtr = stop_reply_dtr;
+
+  return r;
+}
+
+struct notif notif_packet_stop =
+{
+  "Stop",
+  "vStopped",
+  remote_notif_parse_stop,
+  remote_notif_ack_stop,
+  remote_notif_alloc_reply_stop,
+  NULL,
+  NULL,
+};
+
+static int
+stop_reply_match_pid (struct notif_reply *reply, void *data)
+{
+  int *pid = (int *) data;
+  struct stop_reply *r = (struct stop_reply *) reply;
+
+  return (*pid == -1 || ptid_get_pid (r->ptid) == *pid);
 }
 
 /* Discard all pending stop replies of inferior PID.  If PID is -1,
@@ -5165,45 +5085,18 @@ stop_reply_xfree (struct stop_reply *r)
 static void
 discard_pending_stop_replies (int pid)
 {
-  struct stop_reply *prev = NULL, *reply, *next;
-
-  /* Discard the in-flight notification.  */
-  if (pending_stop_reply != NULL
-      && (pid == -1
-	  || ptid_get_pid (pending_stop_reply->ptid) == pid))
-    {
-      stop_reply_xfree (pending_stop_reply);
-      pending_stop_reply = NULL;
-    }
-
-  /* Discard the stop replies we have already pulled with
-     vStopped.  */
-  for (reply = stop_reply_queue; reply; reply = next)
-    {
-      next = reply->next;
-      if (pid == -1
-	  || ptid_get_pid (reply->ptid) == pid)
-	{
-	  if (reply == stop_reply_queue)
-	    stop_reply_queue = reply->next;
-	  else
-	    prev->next = reply->next;
+  remote_notif_discard_pending_replies (&notif_packet_stop,
+					stop_reply_match_pid, &pid);
 
-	  stop_reply_xfree (reply);
-	}
-      else
-	prev = reply;
-    }
 }
 
-/* Cleanup wrapper.  */
-
-static void
-do_stop_reply_xfree (void *arg)
+static int
+stop_reply_match_ptid (struct notif_reply *reply, void *data)
 {
-  struct stop_reply *r = arg;
+  ptid_t *ptid = (ptid_t *) data;
+  struct stop_reply *r = (struct stop_reply *) reply;
 
-  stop_reply_xfree (r);
+  return ptid_match (r->ptid, *ptid);
 }
 
 /* Look for a queued stop reply belonging to PTID.  If one is found,
@@ -5214,53 +5107,37 @@ 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;
+  struct notif_reply *r;
 
-  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;
-    }
+  r = gdb_queue_notif_reply_remove (notif_packet_stop.ack_queue,
+				    stop_reply_match_ptid, &ptid);
 
-  if (stop_reply_queue)
+  if (!gdb_queue_notif_reply_is_empty (notif_packet_stop.ack_queue))
     /* There's still at least an event left.  */
     mark_async_event_handler (remote_async_inferior_event_token);
 
-  return it;
+  return (struct stop_reply *) r;
 }
 
-/* Push a fully parsed stop reply in the stop reply queue.  Since we
+/* Push a fully parsed reply in the reply queue.  Since we
    know that we now have at least one queued event left to pass to the
    core side, tell the event loop to get back to target_wait soon.  */
 
-static void
-push_stop_reply (struct stop_reply *new_event)
+void
+notif_reply_push (struct notif_reply *new_event,
+		  struct gdb_queue_notif_reply *queue)
 {
-  struct stop_reply *event;
-
-  if (stop_reply_queue)
-    {
-      for (event = stop_reply_queue;
-	   event && event->next;
-	   event = event->next)
-	;
+  gdb_queue_notif_reply_enque (new_event, queue);
+  mark_async_event_handler (remote_async_inferior_event_token);
+}
 
-      event->next = new_event;
-    }
-  else
-    stop_reply_queue = new_event;
+static int
+stop_reply_match_ptid_and_ws (struct notif_reply *reply, void *data)
+{
+  struct stop_reply *r = (struct stop_reply *) reply;
+  ptid_t *ptid = data;
 
-  mark_async_event_handler (remote_async_inferior_event_token);
+  return (ptid_equal (*ptid, r->ptid) && r->ws.kind == TARGET_WAITKIND_STOPPED);
 }
 
 /* Returns true if we have a stop reply for PTID.  */
@@ -5268,16 +5145,12 @@ push_stop_reply (struct stop_reply *new_event)
 static int
 peek_stop_reply (ptid_t ptid)
 {
-  struct stop_reply *it;
+  struct notif_reply *reply;
 
-  for (it = stop_reply_queue; it; it = it->next)
-    if (ptid_equal (ptid, it->ptid))
-      {
-	if (it->ws.kind == TARGET_WAITKIND_STOPPED)
-	  return 1;
-      }
+  reply = gdb_queue_notif_reply_find (notif_packet_stop.ack_queue,
+				      stop_reply_match_ptid_and_ws, &ptid);
 
-  return 0;
+  return (reply != NULL);
 }
 
 /* Parse the stop reply in BUF.  Either the function succeeds, and the
@@ -5493,92 +5366,6 @@ 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:
-
-    1.1) --> Hg 1
-    1.2) <-- OK
-    1.3) --> g
-    1.4) <-- %Stop
-    1.5) --> vStopped
-    1.6) <-- (registers reply to step #1.3)
-
-   Obviously, the reply in step #1.6 would be unexpected to a vStopped
-   query.
-
-   To solve this, whenever we parse a %Stop notification sucessfully,
-   we mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN, and carry on
-   doing whatever we were doing:
-
-    2.1) --> Hg 1
-    2.2) <-- OK
-    2.3) --> g
-    2.4) <-- %Stop
-      <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
-    2.5) <-- (registers reply to step #2.3)
-
-   Eventualy after step #2.5, we return to the event loop, which
-   notices there's an event on the
-   REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN event and calls the
-   associated callback --- the function below.  At this point, we're
-   always safe to start a vStopped sequence. :
-
-    2.6) --> vStopped
-    2.7) <-- T05 thread:2
-    2.8) --> vStopped
-    2.9) --> OK
-*/
-
-static void
-remote_get_pending_stop_replies (void)
-{
-  struct remote_state *rs = get_remote_state ();
-
-  if (pending_stop_reply)
-    {
-      /* acknowledge */
-      putpkt ("vStopped");
-
-      /* Now we can rely on it.	 */
-      push_stop_reply (pending_stop_reply);
-      pending_stop_reply = NULL;
-
-      while (1)
-	{
-	  getpkt (&rs->buf, &rs->buf_size, 0);
-	  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);
-	    }
-	}
-    }
-}
-
-
 /* 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.  */
@@ -5622,7 +5409,7 @@ process_stop_reply (struct stop_reply *stop_reply,
       demand_private_info (ptid)->core = stop_reply->core;
     }
 
-  stop_reply_xfree (stop_reply);
+  notif_reply_xfree ((struct notif_reply *) stop_reply);
   return ptid;
 }
 
@@ -5661,8 +5448,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_packet_stop.pending_reply != NULL)
+	remote_notif_pending_replies (&notif_packet_stop);
 
       /* If indeed we noticed a stop reply, we're done.  */
       stop_reply = queued_stop_reply (ptid);
@@ -5758,13 +5545,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_packet_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;
       }
@@ -5845,7 +5629,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 (!gdb_queue_notif_reply_is_empty (notif_packet_stop.ack_queue))
 	mark_async_event_handler (remote_async_inferior_event_token);
     }
 
@@ -6741,52 +6525,6 @@ remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
   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,
    transferring to or from debugger address BUFFER.  Write to inferior
    if SHOULD_WRITE is nonzero.  Returns length of data written or
@@ -11183,12 +10921,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)
 {
@@ -11689,5 +11421,7 @@ Show the remote pathname for \"run\""), NULL, NULL, NULL,
 
   target_buf_size = 2048;
   target_buf = xmalloc (target_buf_size);
+
+  initialize_notif ();
 }
 
diff --git a/gdb/remote.h b/gdb/remote.h
index 3adc54e..579a92f 100644
--- a/gdb/remote.h
+++ b/gdb/remote.h
@@ -19,8 +19,108 @@
 #ifndef REMOTE_H
 #define REMOTE_H
 
+#include "target.h"
+#include "remote-notif.h"
+
 struct target_desc;
 
+/* Description of the remote protocol state for the currently
+   connected target.  This is per-target state, and independent of the
+   selected architecture.  */
+
+struct remote_state
+{
+  /* A buffer to use for incoming packets, and its current size.  The
+     buffer is grown dynamically for larger incoming packets.
+     Outgoing packets may also be constructed in this buffer.
+     BUF_SIZE is always at least REMOTE_PACKET_SIZE;
+     REMOTE_PACKET_SIZE should be used to limit the length of outgoing
+     packets.  */
+  char *buf;
+  long buf_size;
+
+  /* True if we're going through initial connection setup (finding out
+     about the remote side's threads, relocating symbols, etc.).  */
+  int starting_up;
+
+  /* If we negotiated packet size explicitly (and thus can bypass
+     heuristics for the largest packet size that will not overflow
+     a buffer in the stub), this will be set to that packet size.
+     Otherwise zero, meaning to use the guessed size.  */
+  long explicit_packet_size;
+
+  /* remote_wait is normally called when the target is running and
+     waits for a stop reply packet.  But sometimes we need to call it
+     when the target is already stopped.  We can send a "?" packet
+     and have remote_wait read the response.  Or, if we already have
+     the response, we can stash it in BUF and tell remote_wait to
+     skip calling getpkt.  This flag is set when BUF contains a
+     stop reply packet and the target is not waiting.  */
+  int cached_wait_status;
+
+  /* True, if in no ack mode.  That is, neither GDB nor the stub will
+     expect acks from each other.  The connection is assumed to be
+     reliable.  */
+  int noack_mode;
+
+  /* True if we're connected in extended remote mode.  */
+  int extended;
+
+  /* True if the stub reported support for multi-process
+     extensions.  */
+  int multi_process_aware;
+
+  /* True if we resumed the target and we're waiting for the target to
+     stop.  In the mean time, we can't start another command/query.
+     The remote server wouldn't be ready to process it, so we'd
+     timeout waiting for a reply that would never come and eventually
+     we'd close the connection.  This can happen in asynchronous mode
+     because we allow GDB commands while the target is running.  */
+  int waiting_for_stop_reply;
+
+  /* True if the stub reports support for non-stop mode.  */
+  int non_stop_aware;
+
+  /* True if the stub reports support for vCont;t.  */
+  int support_vCont_t;
+
+  /* True if the stub reports support for conditional tracepoints.  */
+  int cond_tracepoints;
+
+  /* True if the stub reports support for target-side breakpoint
+     conditions.  */
+  int cond_breakpoints;
+
+  /* True if the stub reports support for target-side breakpoint
+     commands.  */
+  int breakpoint_commands;
+
+  /* True if the stub reports support for fast tracepoints.  */
+  int fast_tracepoints;
+
+  /* True if the stub reports support for static tracepoints.  */
+  int static_tracepoints;
+
+  /* True if the stub reports support for installing tracepoint while
+     tracing.  */
+  int install_in_trace;
+
+  /* True if the stub can continue running a trace while GDB is
+     disconnected.  */
+  int disconnected_tracing;
+
+  /* True if the stub reports support for enabling and disabling
+     tracepoints while a trace experiment is running.  */
+  int enable_disable_tracepoints;
+
+  /* True if the stub can collect strings using tracenz bytecode.  */
+  int string_tracing;
+
+  /* Nonzero if the user has pressed Ctrl-C, but the target hasn't
+     responded to that.  */
+  int ctrlc_pending_p;
+};
+
 /* Read a packet from the remote machine, with error checking, and
    store it in *BUF.  Resize *BUF using xrealloc if necessary to hold
    the result, and update *SIZEOF_BUF.  If FOREVER, wait forever
@@ -59,4 +159,7 @@ extern int remote_register_number_and_offset (struct gdbarch *gdbarch,
 					      int regnum, int *pnum,
 					      int *poffset);
 
+extern void notif_reply_push (struct notif_reply *,
+			      struct gdb_queue_notif_reply *);
+
 #endif
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]