From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16064 invoked by alias); 24 Aug 2012 02:26:26 -0000 Received: (qmail 15669 invoked by uid 22791); 24 Aug 2012 02:26:19 -0000 X-SWARE-Spam-Status: No, hits=-4.3 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_CP,TW_DB,TW_EG,TW_XS X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 24 Aug 2012 02:26:04 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1T4jb1-0003wS-It from Yao_Qi@mentor.com for gdb-patches@sourceware.org; Thu, 23 Aug 2012 19:26:03 -0700 Received: from SVR-ORW-FEM-04.mgc.mentorg.com ([147.34.97.41]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Thu, 23 Aug 2012 19:26:03 -0700 Received: from qiyao.dyndns.org.dyndns.org (147.34.91.1) by svr-orw-fem-04.mgc.mentorg.com (147.34.97.41) with Microsoft SMTP Server id 14.1.289.1; Thu, 23 Aug 2012 19:26:01 -0700 From: Yao Qi To: Subject: [PATCH 3/4] de-couple %Stop from notification: gdbserver Date: Fri, 24 Aug 2012 02:26:00 -0000 Message-ID: <1345775139-13576-4-git-send-email-yao@codesourcery.com> In-Reply-To: <1345775139-13576-1-git-send-email-yao@codesourcery.com> References: <1345775139-13576-1-git-send-email-yao@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-08/txt/msg00706.txt.bz2 gdb/gdbserver: 2012-08-24 Yao Qi * Makefile.in (OBS): Add notif.o. (notif_h, gdb_queue_h): New. (notif.o): New rule. * server.c: Include 'notif.h'. (struct vstop_notif): Move it to notif.h. (notif_process_stop): New. (notif_stop): New variable. (push_event, notif_queue): Remove. (queue_stop_reply): Remove parameters. Add two new parameters 'new_notif' and 'queue'. Caller update. (vstop_notif_match_pid, notif_queued_replies_discard): New. (notif_queued_replies_discard_all): New. (discard_queued_stop_replies, send_next_stop_reply): Remove. (handle_v_kill): Don't call discard_queued_stop_replies. Call notif_queued_replies_discard_all instead. (handle_v_stopped): Remove. (handle_v_requests): Don't call handle_v_stopped. Call handle_ack_notif instead. (queue_stop_reply_callback): Call notif_reply_enqueue instead of queue_stop_reply. (handle_status): Don't call discard_queued_stop_replies. Call notif_queued_replies_discard instead. (kill_inferior_callback): Likewise. (detach_or_kill_inferior_callback): Likewise. (process_serial_event): Likewise. Call notif_queued_replies_empty_p. (handle_target_event): Process queued replies. * server.h: Remove declaration of push_event. --- gdb/gdbserver/Makefile.in | 5 +- gdb/gdbserver/linux-low.c | 9 ++- gdb/gdbserver/notif.c | 152 +++++++++++++++++++++++++++++++ gdb/gdbserver/notif.h | 79 ++++++++++++++++ gdb/gdbserver/server.c | 218 ++++++++++++++++----------------------------- gdb/gdbserver/server.h | 2 - 6 files changed, 318 insertions(+), 147 deletions(-) create mode 100644 gdb/gdbserver/notif.c create mode 100644 gdb/gdbserver/notif.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index f62799e..68f6b23 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -156,7 +156,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 @@ -407,6 +407,7 @@ gdb_proc_service_h = $(srcdir)/gdb_proc_service.h regdat_sh = $(srcdir)/../regformats/regdat.sh regdef_h = $(srcdir)/../regformats/regdef.h regcache_h = $(srcdir)/regcache.h +gdb_queue_h = $(srcdir)/../common/gdb_queue.h signals_def = $(srcdir)/../../include/gdb/signals.def signals_h = $(srcdir)/../../include/gdb/signals.h $(signals_def) ptid_h = $(srcdir)/../common/ptid.h @@ -428,6 +429,7 @@ server_h = $(srcdir)/server.h $(regcache_h) $(srcdir)/target.h \ $(ptid_h) \ $(signals_h) \ $(generated_files) +notif_h = ${srcdir}/notif.h gdbthread_h = $(srcdir)/gdbthread.h $(target_h) $(srcdir)/server.h linux_low_h = $(srcdir)/linux-low.h $(gdbthread_h) @@ -485,6 +487,7 @@ proc-service.o: proc-service.c $(server_h) $(gdb_proc_service_h) regcache.o: regcache.c $(server_h) $(regdef_h) $(gdbthread_h) remote-utils.o: remote-utils.c terminal.h $(server_h) $(gdbthread_h) server.o: server.c $(server_h) $(agent_h) $(gdbthread_h) +notif.o: notif.c $(notif_h) $(gdb_queue_h) target.o: target.c $(server_h) thread-db.o: thread-db.c $(server_h) $(linux_low_h) $(gdb_proc_service_h) \ $(gdb_thread_db_h) $(gdb_vecs_h) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index a476031..e9752b0 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -20,6 +20,7 @@ #include "linux-low.h" #include "linux-osdata.h" #include "agent.h" +#include "notif.h" #include #include @@ -2787,6 +2788,8 @@ async_file_mark (void) be awakened anyway. */ } +extern struct notif notif_stop; + static ptid_t linux_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int target_options) @@ -2807,7 +2810,11 @@ linux_wait (ptid_t ptid, if (target_is_async_p () && (target_options & TARGET_WNOHANG) != 0 && !ptid_equal (event_ptid, null_ptid)) - async_file_mark (); + { + gdb_queue_notif_enque (¬if_stop, ¬if_queue); + + async_file_mark (); + } return event_ptid; } diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c new file mode 100644 index 0000000..838f391 --- /dev/null +++ b/gdb/gdbserver/notif.c @@ -0,0 +1,152 @@ +/* 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 . */ + +#include "notif.h" + +extern struct notif notif_stop; + +static struct notif *notif_packets [] = +{ + ¬if_stop, + NULL, +}; + +void +gdb_queue_ele_notif_xfree (struct notif *notif) +{ + /* It is a placeholder. Never be called. */ + gdb_assert (0); +} + +QUEUE_DEFINE_TYPE(notif); + +QUEUE_DEFINE_VAR(notif, notif_queue); + +void +gdb_queue_ele_notif_reply_xfree (struct notif_reply *reply) +{ + /* Nothing to release for 'struct notif_reply' and its sub-classes. */ +} + +QUEUE_DEFINE_TYPE(notif_reply); + +extern int remote_debug; + +/* Push another reply, or if there are no more left, an OK. */ + +void +notif_send_reply (struct notif *notif, char *own_buf) +{ + struct notif_reply *reply = gdb_queue_notif_reply_peek (notif->queue); + + if (reply != NULL) + notif->reply (reply, own_buf); + else + write_ok (own_buf); +} + +/* Handle the ack in buffer OWN_BUF. Return 1 if the ack is handled, and + return 0 if the contents in OWN_BUF is not a ack. */ + +int +notif_ack_handle (char *own_buf) +{ + int i = 0; + struct notif *np = NULL; + + for (i = 0; notif_packets[i] != NULL; i++) + { + np = notif_packets[i]; + if (strncmp (own_buf, np->name, strlen (np->name)) == 0) + break; + } + + if (np == NULL) + return 0; + + /* If we're waiting for GDB to acknowledge a pending reply, + consider that done. */ + if (!gdb_queue_notif_reply_is_empty (np->queue)) + { + struct notif_reply *head = gdb_queue_notif_reply_deque (np->queue); + + if (remote_debug) + fprintf (stderr, "%s: acking\n", np->name); + + xfree (head); + } + + notif_send_reply (np, own_buf); + + return 1; +} + +/* Return true if the queues of all notifications are empty. If the queue of + one of notification is not empty, return false. */ + +int +notif_queued_replies_empty_p (void) +{ + int i; + + for (i = 0; notif_packets[i] != NULL; i++) + if (!gdb_queue_notif_reply_is_empty (notif_packets[i]->queue)) + return 0; + + return 1; +} + +static int +notif_reply_match_pid (struct notif_reply *reply, void *data) +{ + int *pid = data; + + return (*pid == -1 || ptid_get_pid (reply->ptid) == *pid); +} + +/* Get rid of the currently pending replies of NOTIF for PID. If PID is + -1, then apply to all processes. */ + +void +notif_queued_replies_discard (int pid, struct notif *notif) +{ + gdb_queue_notif_reply_remove_all (notif->queue, notif_reply_match_pid, + &pid); +} + +/* Get rid of pending replies of all notifications. */ + +void +notif_queued_replies_discard_all (int pid) +{ + int i; + + for (i = 0; notif_packets[i] != NULL; i++) + notif_queued_replies_discard (pid, notif_packets[i]); +} + +void +initialize_notif (void) +{ + int i = 0; + + for (i = 0; notif_packets[i] != NULL; i++) + notif_packets[i]->queue = gdb_queue_notif_reply_alloc (); + +} diff --git a/gdb/gdbserver/notif.h b/gdb/gdbserver/notif.h new file mode 100644 index 0000000..ac62eab --- /dev/null +++ b/gdb/gdbserver/notif.h @@ -0,0 +1,79 @@ +/* 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 . */ + +#include "ptid.h" +#include "server.h" +#include "target.h" +#include "gdb_queue.h" + +/* Structure holding information relative to a single reply. We + keep a queue of these (really a singly-linked list) to push to GDB + in non-stop mode. */ + +struct notif_reply +{ + /* Thread or process that got the event. */ + ptid_t ptid; +}; + +/* A sub-class of 'struct ack_notif' for stop reply. */ + +struct vstop_notif +{ + struct notif_reply base; + + /* Event info. */ + struct target_waitstatus status; +}; + +enum notif_type { NOTIF_STOP }; + +/* A notification to GDB. */ + +struct notif +{ + /* The name of ack packet, for example, 'vStopped'. */ + const char *name; + + /* The notification packet, for example, '%Stop'. Note that '%' is not in + 'notif_name'. */ + const char *notif_name; + + const enum notif_type type; + + /* A queue of reply to GDB. */ + struct gdb_queue_notif_reply *queue; + + /* Reply to GDB. */ + void (*reply) (struct notif_reply *reply, char *own_buf); +}; + +int notif_ack_handle (char *own_buf); +void notif_send_reply (struct notif *notif, char *own_buf); + +int notif_queued_replies_empty_p (void); +void notif_queued_replies_discard (int pid, struct notif *notif); +void notif_queued_replies_discard_all (int pid); + +extern struct gdb_queue_notif notif_queue; + +QUEUE_DECLARE (notif); +QUEUE_DECLARE (notif_reply); + +void initialize_notif (void); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 547552f..0b756cd 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -20,6 +20,7 @@ #include "server.h" #include "gdbthread.h" #include "agent.h" +#include "notif.h" #if HAVE_UNISTD_H #include @@ -117,121 +118,28 @@ 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. */ -struct vstop_notif -{ - /* Pointer to next in list. */ - struct vstop_notif *next; - - /* Thread or process that got the event. */ - ptid_t ptid; - - /* Event info. */ - struct target_waitstatus status; -}; - -/* The pending stop replies list head. */ -static struct vstop_notif *notif_queue = NULL; - -/* Put a stop reply to the stop reply queue. */ - static void -queue_stop_reply (ptid_t ptid, struct target_waitstatus *status) +notif_reply_stop (struct notif_reply *reply, char *own_buf) { - struct vstop_notif *new_notif; - - new_notif = xmalloc (sizeof (*new_notif)); - new_notif->next = NULL; - new_notif->ptid = ptid; - new_notif->status = *status; + struct vstop_notif *vstop = (struct vstop_notif *) reply; - 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); - } + prepare_resume_reply (own_buf, reply->ptid, &vstop->status); } -/* 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) +struct notif notif_stop = { - gdb_assert (status->kind != TARGET_WAITKIND_IGNORE); - - 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) - { - char *p = own_buf; - strcpy (p, "Stop:"); - p += strlen (p); - prepare_resume_reply (p, - notif_queue->ptid, ¬if_queue->status); - putpkt_notif (own_buf); - } -} - -/* Get rid of the currently pending stop replies for PID. If PID is - -1, then apply to all processes. */ + "vStopped", "Stop", NOTIF_STOP, NULL, notif_reply_stop, +}; static void -discard_queued_stop_replies (int pid) +notif_reply_enque (struct notif_reply *reply, struct notif *notif) { - struct vstop_notif *prev = NULL, *reply, *next; + gdb_queue_notif_reply_enque (reply, notif->queue); - 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; - } -} - -/* If there are more stop replies to push, push one now. */ + if (remote_debug) + fprintf (stderr, "pending replies: %s %d\n", notif->notif_name, + gdb_queue_notif_reply_length (notif->queue)); -static void -send_next_stop_reply (char *own_buf) -{ - if (notif_queue) - prepare_resume_reply (own_buf, - notif_queue->ptid, - ¬if_queue->status); - else - write_ok (own_buf); } static int @@ -2159,7 +2067,8 @@ handle_v_kill (char *own_buf) last_status.kind = TARGET_WAITKIND_SIGNALLED; last_status.value.sig = GDB_SIGNAL_KILL; last_ptid = pid_to_ptid (pid); - discard_queued_stop_replies (pid); + + notif_queued_replies_discard_all (pid); write_ok (own_buf); return 1; } @@ -2170,29 +2079,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) @@ -2253,11 +2139,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 (notif_ack_handle (own_buf)) + return; /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ @@ -2335,18 +2218,25 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) { struct thread_info *thread = (struct thread_info *) entry; + /* For now, assume targets that don't have this callback also don't manage the thread's last_status field. */ if (the_target->thread_stopped == NULL) { + struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif)); + + new_notif->base.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_reply_enque ((struct notif_reply *) new_notif, ¬if_stop); } else { if (thread_stopped (thread)) { + struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif)); + if (debug_threads) fprintf (stderr, "Reporting thread %s as already stopped with %s\n", @@ -2355,9 +2245,11 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE); + new_notif->base.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_reply_enque ((struct notif_reply *) new_notif, ¬if_stop); } } @@ -2416,13 +2308,13 @@ handle_status (char *own_buf) if (non_stop) { - discard_queued_stop_replies (-1); + notif_queued_replies_discard (-1, ¬if_stop); find_inferior (&all_threads, queue_stop_reply_callback, NULL); /* 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_send_reply (¬if_stop, own_buf); } else { @@ -2515,7 +2407,7 @@ kill_inferior_callback (struct inferior_list_entry *entry) int pid = ptid_get_pid (process->head.id); kill_inferior (pid); - discard_queued_stop_replies (pid); + notif_queued_replies_discard_all (pid); } /* Callback for for_each_inferior to detach or kill the inferior, @@ -2534,7 +2426,7 @@ detach_or_kill_inferior_callback (struct inferior_list_entry *entry) else kill_inferior (pid); - discard_queued_stop_replies (pid); + notif_queued_replies_discard_all (pid); } /* for_each_inferior callback for detach_or_kill_for_exit to print @@ -2791,6 +2683,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. */ @@ -3061,7 +2955,7 @@ process_serial_event (void) write_enn (own_buf); else { - discard_queued_stop_replies (pid); + notif_queued_replies_discard_all (pid); write_ok (own_buf); if (extended_protocol) @@ -3403,7 +3297,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 (notif_queued_replies_empty_p ()) { fprintf (stderr, "GDBserver exiting\n"); remote_close (); @@ -3501,8 +3395,46 @@ handle_target_event (int err, gdb_client_data client_data) } else { - /* Something interesting. Tell GDB about it. */ - push_event (last_ptid, &last_status); + while (!gdb_queue_notif_is_empty (¬if_queue)) + { + struct notif *np = gdb_queue_notif_deque (¬if_queue); + struct notif_reply *new_notif = NULL; + int is_first_event = 0; + + switch (np->type) + { + case NOTIF_STOP: + { + struct vstop_notif *vstop_notif + = xmalloc (sizeof (struct vstop_notif)); + + vstop_notif->status = last_status; + new_notif = (struct notif_reply *) vstop_notif; + } + break; + default: + error ("Unknown notification type"); + } + + new_notif->ptid = last_ptid; + is_first_event = gdb_queue_notif_reply_is_empty (np->queue); + + /* Something interesting. Tell GDB about it. */ + notif_reply_enque (new_notif, np); + + /* 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 *p = own_buf; + + xsnprintf (p, PBUFSIZ, "%s:", np->notif_name); + p += strlen (p); + + np->reply (new_notif, p); + putpkt_notif (own_buf); + } + } } } diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index e93ad00..3bf72dc 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -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 *); -- 1.7.7.6