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.
This commit is contained in:
Yao Qi 2012-12-15 03:50:22 +00:00
parent 5f4cf0bb27
commit 722247f1cb
6 changed files with 659 additions and 223 deletions

View File

@ -1,3 +1,52 @@
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.

View File

@ -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.

270
gdb/remote-notif.c Normal file
View File

@ -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);
}

85
gdb/remote-notif.h Normal file
View File

@ -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 */

View File

@ -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;
};
} *stop_reply_p;
/* 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);
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;
stop_reply_xfree (reply);
}
else
prev = reply;
}
QUEUE_iterate (stop_reply_p, stop_reply_queue,
remote_notif_remove_all, &param);
}
/* Cleanup wrapper. */
/* A parameter to pass data in and out. */
static void
do_stop_reply_xfree (void *arg)
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 stop_reply *r = arg;
struct queue_iter_param *param = data;
ptid_t *ptid = param->input;
stop_reply_xfree (r);
if (ptid_match (event->ptid, *ptid))
{
param->output = event;
QUEUE_remove_elem (stop_reply_p, q, iter);
return 0;
}
return 1;
}
/* Remove the first reply in 'stop_reply_queue' which matches
PTID. */
static struct stop_reply *
remote_notif_remove_queued_reply (ptid_t ptid)
{
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));
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;
struct stop_reply *r = remote_notif_remove_queued_reply (ptid);
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;
}
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;
QUEUE_enque (stop_reply_p, stop_reply_queue, new_event);
if (stop_reply_queue)
{
for (event = stop_reply_queue;
event && event->next;
event = event->next)
;
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,
@ -11196,12 +11229,6 @@ remote_async_inferior_event_handler (gdb_client_data data)
inferior_event_handler (INF_REG_EVENT, NULL);
}
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, _("\

View File

@ -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