Index: gdb/gdbserver/notif.c |
diff --git a/gdb/gdbserver/notif.c b/gdb/gdbserver/notif.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6da2c5cf534599c3b070d4b595cb8182ac4e7181 |
--- /dev/null |
+++ b/gdb/gdbserver/notif.c |
@@ -0,0 +1,170 @@ |
+/* Notification to GDB. |
+ Copyright (C) 1989-2013 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[] = |
+{ |
+ ¬if_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) |
+{ |
+ size_t i; |
+ struct notif_server *np; |
+ |
+ for (i = 0; i < ARRAY_SIZE (notifs); i++) |
+ { |
+ const char *ack_name = notifs[i]->ack_name; |
+ |
+ if (strncmp (own_buf, ack_name, strlen (ack_name)) == 0 |
+ && packet_len == strlen (ack_name)) |
+ break; |
+ } |
+ |
+ if (i == ARRAY_SIZE (notifs)) |
+ return 0; |
+ |
+ np = notifs[i]; |
+ |
+ /* 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); |
+} |