gdb/gdbserver/

2012-12-15  Yao Qi  <yao@codesourcery.com>

	* Makefile.in (OBS): Add notif.o.
	* notif.c, notif.h: New.
	* server.c: Include "notif.h".
	(struct vstop_notif) <next>: Remove.
	<base>: New field.
	(queue_stop_reply): Update.
	(push_event, send_next_stop_reply): Remove.
	(discard_queued_stop_replies): Update.
	(notif_stop): New variable.
	(handle_v_stopped): Remove.
	(handle_v_requests): Don't call handle_v_stopped.  Call
	handle_ack_notif instead.
	(queue_stop_reply_callback): Call notif_event_enque instead
	of queue_stop_reply.
	(handle_status): Don't call send_next_stop_reply, call
	notif_write_event instead.
	(kill_inferior_callback): Likewise.
	(detach_or_kill_inferior_callback): Likewise.
	(main): Call initialize_notif.
	(process_serial_event): Call QUEUE_is_empty.
	(handle_target_event): Call notif_push instead of push event.
	* server.h (push_event): Remove declaration.
This commit is contained in:
Yao Qi 2012-12-15 02:48:18 +00:00
parent dbb0cf06a3
commit 14a0047001
6 changed files with 313 additions and 113 deletions

View File

@ -1,3 +1,28 @@
2012-12-15 Yao Qi <yao@codesourcery.com>
* Makefile.in (OBS): Add notif.o.
* notif.c, notif.h: New.
* server.c: Include "notif.h".
(struct vstop_notif) <next>: Remove.
<base>: New field.
(queue_stop_reply): Update.
(push_event, send_next_stop_reply): Remove.
(discard_queued_stop_replies): Update.
(notif_stop): New variable.
(handle_v_stopped): Remove.
(handle_v_requests): Don't call handle_v_stopped. Call
handle_ack_notif instead.
(queue_stop_reply_callback): Call notif_event_enque instead
of queue_stop_reply.
(handle_status): Don't call send_next_stop_reply, call
notif_write_event instead.
(kill_inferior_callback): Likewise.
(detach_or_kill_inferior_callback): Likewise.
(main): Call initialize_notif.
(process_serial_event): Call QUEUE_is_empty.
(handle_target_event): Call notif_push instead of push event.
* server.h (push_event): Remove declaration.
2012-12-10 Tom Tromey <tromey@redhat.com>
* Makefile.in (DEPMODE, DEPDIR, depcomp, COMPILE.pre)

View File

@ -168,7 +168,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o targ
utils.o version.o vec.o gdb_vecs.o \
mem-break.o hostio.o event-loop.o tracepoint.o \
xml-utils.o common-utils.o ptid.o buffer.o format.o \
dll.o \
dll.o notif.o \
$(XML_BUILTIN) \
$(DEPFILES) $(LIBOBJS)
GDBREPLAY_OBS = gdbreplay.o version.o

168
gdb/gdbserver/notif.c Normal file
View File

@ -0,0 +1,168 @@
/* Notification to GDB.
Copyright (C) 1989, 1993-1995, 1997-2000, 2002-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/>. */
/* Async notifications to GDB. When the state of remote target is
changed or something interesting to GDB happened, async
notifications are used to tell GDB.
Each type of notification is represented by an object
'struct notif_server', in which there is a queue for events to GDB
represented by 'struct notif_event'. GDBserver writes (by means of
'write' field) each event in the queue into the buffer and send the
contents in buffer to GDB. The contents in buffer is specified in
RSP. See more in the comments to field 'queue' of
'struct notif_server'.
Here is the workflow of sending events and managing queue:
1. At any time, when something interesting FOO happens, a object
of 'struct notif_event' or its sub-class EVENT is created for FOO.
2. Enque EVENT to the 'queue' field of 'struct notif_server' for
FOO and send corresponding notification packet to GDB if EVENT is
the first one.
#1 and #2 are done by function 'notif_push'.
3. EVENT is not deque'ed until the ack of FOO from GDB arrives.
Before ack of FOO arrives, FOO happens again, a new object of
EVENT is created and enque EVENT silently.
Once GDB has a chance to ack to FOO, it sends an ack to GDBserver,
and GDBserver repeatedly sends events to GDB and gets ack of FOO,
until queue is empty. Then, GDBserver sends 'OK' to GDB that all
queued notification events are done.
# 3 is done by function 'handle_notif_ack'. */
#include "notif.h"
static struct notif_server *notifs[] =
{
&notif_stop,
};
/* Write another event or an OK, if there are no more left, to
OWN_BUF. */
void
notif_write_event (struct notif_server *notif, char *own_buf)
{
if (!QUEUE_is_empty (notif_event_p, notif->queue))
{
struct notif_event *event
= QUEUE_peek (notif_event_p, notif->queue);
notif->write (event, own_buf);
}
else
write_ok (own_buf);
}
/* Handle the ack in buffer OWN_BUF,and packet length is PACKET_LEN.
Return 1 if the ack is handled, and return 0 if the contents
in OWN_BUF is not a ack. */
int
handle_notif_ack (char *own_buf, int packet_len)
{
int i = 0;
struct notif_server *np = NULL;
for (i = 0; i < ARRAY_SIZE (notifs); i++)
{
np = notifs[i];
if (strncmp (own_buf, np->ack_name, strlen (np->ack_name)) == 0
&& packet_len == strlen (np->ack_name))
break;
}
if (np == NULL)
return 0;
/* If we're waiting for GDB to acknowledge a pending event,
consider that done. */
if (!QUEUE_is_empty (notif_event_p, np->queue))
{
struct notif_event *head
= QUEUE_deque (notif_event_p, np->queue);
if (remote_debug)
fprintf (stderr, "%s: acking %d\n", np->ack_name,
QUEUE_length (notif_event_p, np->queue));
xfree (head);
}
notif_write_event (np, own_buf);
return 1;
}
/* Put EVENT to the queue of NOTIF. */
void
notif_event_enque (struct notif_server *notif,
struct notif_event *event)
{
QUEUE_enque (notif_event_p, notif->queue, event);
if (remote_debug)
fprintf (stderr, "pending events: %s %d\n", notif->notif_name,
QUEUE_length (notif_event_p, notif->queue));
}
/* Push one event NEW_EVENT of notification NP into NP->queue. */
void
notif_push (struct notif_server *np, struct notif_event *new_event)
{
int is_first_event = QUEUE_is_empty (notif_event_p, np->queue);
/* Something interesting. Tell GDB about it. */
notif_event_enque (np, new_event);
/* If this is the first stop reply in the queue, then inform GDB
about it, by sending a corresponding notification. */
if (is_first_event)
{
char buf[PBUFSIZ];
char *p = buf;
xsnprintf (p, PBUFSIZ, "%s:", np->notif_name);
p += strlen (p);
np->write (new_event, p);
putpkt_notif (buf);
}
}
static void
notif_event_xfree (struct notif_event *event)
{
xfree (event);
}
void
initialize_notif (void)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE (notifs); i++)
notifs[i]->queue
= QUEUE_alloc (notif_event_p, notif_event_xfree);
}

65
gdb/gdbserver/notif.h Normal file
View File

@ -0,0 +1,65 @@
/* Notification to GDB.
Copyright (C) 1989, 1993-1995, 1997-2000, 2002-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 "ptid.h"
#include "server.h"
#include "target.h"
#include "queue.h"
/* Structure holding information related to a single event. We
keep a queue of these to push to GDB. It can be extended if
the event of given notification contains more information. */
typedef struct notif_event
{
} *notif_event_p;
DECLARE_QUEUE_P (notif_event_p);
/* A type notification to GDB. An object of 'struct notif_server'
represents a type of notification. */
typedef struct notif_server
{
/* The name of ack packet, for example, 'vStopped'. */
const char *ack_name;
/* The notification packet, for example, '%Stop'. Note that '%' is
not in 'notif_name'. */
const char *notif_name;
/* A queue of events to GDB. A new notif_event can be enque'ed
into QUEUE at any appropriate time, and the notif_reply is
deque'ed only when the ack from GDB arrives. */
QUEUE (notif_event_p) *queue;
/* Write event EVENT to OWN_BUF. */
void (*write) (struct notif_event *event, char *own_buf);
} *notif_server_p;
extern struct notif_server notif_stop;
int handle_notif_ack (char *own_buf, int packet_len);
void notif_write_event (struct notif_server *notif, char *own_buf);
void notif_push (struct notif_server *np, struct notif_event *event);
void notif_event_enque (struct notif_server *notif,
struct notif_event *event);
void initialize_notif (void);

View File

@ -20,6 +20,7 @@
#include "server.h"
#include "gdbthread.h"
#include "agent.h"
#include "notif.h"
#if HAVE_UNISTD_H
#include <unistd.h>
@ -115,13 +116,13 @@ static ptid_t last_ptid;
static char *own_buf;
static unsigned char *mem_buf;
/* Structure holding information relative to a single stop reply. We
keep a queue of these (really a singly-linked list) to push to GDB
in non-stop mode. */
/* A sub-class of 'struct notif_event' for stop, holding information
relative to a single stop reply. We keep a queue of these to
push to GDB in non-stop mode. */
struct vstop_notif
{
/* Pointer to next in list. */
struct vstop_notif *next;
struct notif_event base;
/* Thread or process that got the event. */
ptid_t ptid;
@ -130,66 +131,39 @@ struct vstop_notif
struct target_waitstatus status;
};
/* The pending stop replies list head. */
static struct vstop_notif *notif_queue = NULL;
DEFINE_QUEUE_P (notif_event_p);
/* Put a stop reply to the stop reply queue. */
static void
queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
{
struct vstop_notif *new_notif;
struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif));
new_notif = xmalloc (sizeof (*new_notif));
new_notif->next = NULL;
new_notif->ptid = ptid;
new_notif->status = *status;
if (notif_queue)
{
struct vstop_notif *tail;
for (tail = notif_queue;
tail && tail->next;
tail = tail->next)
;
tail->next = new_notif;
}
else
notif_queue = new_notif;
if (remote_debug)
{
int i = 0;
struct vstop_notif *n;
for (n = notif_queue; n; n = n->next)
i++;
fprintf (stderr, "pending stop replies: %d\n", i);
}
notif_event_enque (&notif_stop, (struct notif_event *) new_notif);
}
/* Place an event in the stop reply queue, and push a notification if
we aren't sending one yet. */
void
push_event (ptid_t ptid, struct target_waitstatus *status)
static int
remove_all_on_match_pid (QUEUE (notif_event_p) *q,
QUEUE_ITER (notif_event_p) *iter,
struct notif_event *event,
void *data)
{
gdb_assert (status->kind != TARGET_WAITKIND_IGNORE);
int *pid = data;
queue_stop_reply (ptid, status);
/* If this is the first stop reply in the queue, then inform GDB
about it, by sending a Stop notification. */
if (notif_queue->next == NULL)
if (*pid == -1
|| ptid_get_pid (((struct vstop_notif *) event)->ptid) == *pid)
{
char *p = own_buf;
strcpy (p, "Stop:");
p += strlen (p);
prepare_resume_reply (p,
notif_queue->ptid, &notif_queue->status);
putpkt_notif (own_buf);
if (q->free_func != NULL)
q->free_func (event);
QUEUE_remove_elem (notif_event_p, q, iter);
}
return 1;
}
/* Get rid of the currently pending stop replies for PID. If PID is
@ -198,40 +172,23 @@ push_event (ptid_t ptid, struct target_waitstatus *status)
static void
discard_queued_stop_replies (int pid)
{
struct vstop_notif *prev = NULL, *reply, *next;
for (reply = notif_queue; reply; reply = next)
{
next = reply->next;
if (pid == -1
|| ptid_get_pid (reply->ptid) == pid)
{
if (reply == notif_queue)
notif_queue = next;
else
prev->next = reply->next;
free (reply);
}
else
prev = reply;
}
QUEUE_iterate (notif_event_p, notif_stop.queue,
remove_all_on_match_pid, &pid);
}
/* If there are more stop replies to push, push one now. */
static void
send_next_stop_reply (char *own_buf)
vstop_notif_reply (struct notif_event *event, char *own_buf)
{
if (notif_queue)
prepare_resume_reply (own_buf,
notif_queue->ptid,
&notif_queue->status);
else
write_ok (own_buf);
struct vstop_notif *vstop = (struct vstop_notif *) event;
prepare_resume_reply (own_buf, vstop->ptid, &vstop->status);
}
struct notif_server notif_stop =
{
"vStopped", "Stop", NULL, vstop_notif_reply,
};
static int
target_running (void)
{
@ -2169,29 +2126,6 @@ handle_v_kill (char *own_buf)
}
}
/* Handle a 'vStopped' packet. */
static void
handle_v_stopped (char *own_buf)
{
/* If we're waiting for GDB to acknowledge a pending stop reply,
consider that done. */
if (notif_queue)
{
struct vstop_notif *head;
if (remote_debug)
fprintf (stderr, "vStopped: acking %s\n",
target_pid_to_str (notif_queue->ptid));
head = notif_queue;
notif_queue = notif_queue->next;
free (head);
}
/* Push another stop reply, or if there are no more left, an OK. */
send_next_stop_reply (own_buf);
}
/* Handle all of the extended 'v' packets. */
void
handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
@ -2252,11 +2186,8 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
return;
}
if (strncmp (own_buf, "vStopped", 8) == 0)
{
handle_v_stopped (own_buf);
return;
}
if (handle_notif_ack (own_buf, packet_len))
return;
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
@ -2337,9 +2268,14 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
manage the thread's last_status field. */
if (the_target->thread_stopped == NULL)
{
struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif));
new_notif->ptid = entry->id;
new_notif->status = thread->last_status;
/* Pass the last stop reply back to GDB, but don't notify
yet. */
queue_stop_reply (entry->id, &thread->last_status);
notif_event_enque (&notif_stop,
(struct notif_event *) new_notif);
}
else
{
@ -2420,7 +2356,7 @@ handle_status (char *own_buf)
/* The first is sent immediatly. OK is sent if there is no
stopped thread, which is the same handling of the vStopped
packet (by design). */
send_next_stop_reply (own_buf);
notif_write_event (&notif_stop, own_buf);
}
else
{
@ -2789,6 +2725,8 @@ main (int argc, char *argv[])
last_ptid = minus_one_ptid;
}
initialize_notif ();
/* Don't report shared library events on the initial connection,
even if some libraries are preloaded. Avoids the "stopped by
shared library event" notice on gdb side. */
@ -3400,7 +3338,7 @@ process_serial_event (void)
{
/* In non-stop, defer exiting until GDB had a chance to query
the whole vStopped list (until it gets an OK). */
if (!notif_queue)
if (QUEUE_is_empty (notif_event_p, notif_stop.queue))
{
fprintf (stderr, "GDBserver exiting\n");
remote_close ();
@ -3498,8 +3436,14 @@ handle_target_event (int err, gdb_client_data client_data)
}
else
{
/* Something interesting. Tell GDB about it. */
push_event (last_ptid, &last_status);
struct vstop_notif *vstop_notif
= xmalloc (sizeof (struct vstop_notif));
vstop_notif->status = last_status;
vstop_notif->ptid = last_ptid;
/* Push Stop notification. */
notif_push (&notif_stop,
(struct notif_event *) vstop_notif);
}
}

View File

@ -265,8 +265,6 @@ extern void start_event_loop (void);
extern int handle_serial_event (int err, gdb_client_data client_data);
extern int handle_target_event (int err, gdb_client_data client_data);
extern void push_event (ptid_t ptid, struct target_waitstatus *status);
/* Functions from hostio.c. */
extern int handle_vFile (char *, int, int *);