gdb/
[deliverable/binutils-gdb.git] / gdb / remote-notif.c
1 /* Remote notification in GDB protocol
2
3 Copyright (C) 1988-2012 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 /* Remote async notification is sent from remote target over RSP.
21 Each type of notification is represented by an object of
22 'struct notif', which has a field 'pending_reply'. It is not
23 NULL when GDB receives a notification from GDBserver, but hasn't
24 acknowledge yet. Before GDB acknowledges the notification,
25 GDBserver shouldn't send notification again (see the header comments
26 in gdbserver/notif.c).
27
28 Notifications are processed in an almost-unified approach for both
29 all-stop mode and non-stop mode, except the timing to process them.
30 In non-stop mode, notifications are processed in
31 remote_async_get_pending_events_handler, while in all-stop mode,
32 they are processed in remote_resume. */
33
34 #include "defs.h"
35 #include "remote.h"
36 #include "remote-notif.h"
37 #include "observer.h"
38 #include "event-loop.h"
39 #include "target.h"
40 #include "inferior.h"
41 #include "gdbcmd.h"
42
43 #include <string.h>
44
45 unsigned int notif_debug = 0;
46
47 /* Supported clients of notifications. */
48
49 static struct notif_client *notifs[] =
50 {
51 &notif_client_stop,
52 };
53
54 static void do_notif_event_xfree (void *arg);
55
56 /* Parse the BUF for the expected notification NC, and send packet to
57 acknowledge. */
58
59 void
60 remote_notif_ack (struct notif_client *nc, char *buf)
61 {
62 struct notif_event *event = nc->alloc_event ();
63 struct cleanup *old_chain
64 = make_cleanup (do_notif_event_xfree, event);
65
66 if (notif_debug)
67 fprintf_unfiltered (gdb_stdlog, "notif: ack '%s'\n",
68 nc->ack_command);
69
70 nc->parse (nc, buf, event);
71 nc->ack (nc, buf, event);
72
73 discard_cleanups (old_chain);
74 }
75
76 /* Parse the BUF for the expected notification NC. */
77
78 struct notif_event *
79 remote_notif_parse (struct notif_client *nc, char *buf)
80 {
81 struct notif_event *event = nc->alloc_event ();
82 struct cleanup *old_chain
83 = make_cleanup (do_notif_event_xfree, event);
84
85 if (notif_debug)
86 fprintf_unfiltered (gdb_stdlog, "notif: parse '%s'\n", nc->name);
87
88 nc->parse (nc, buf, event);
89
90 discard_cleanups (old_chain);
91 return event;
92 }
93
94 DECLARE_QUEUE_P (notif_client_p);
95 DEFINE_QUEUE_P (notif_client_p);
96
97 static QUEUE(notif_client_p) *notif_queue;
98
99 /* Process notifications one by one. EXCEPT is not expected in
100 the queue. */
101
102 void
103 remote_notif_process (struct notif_client *except)
104 {
105 while (!QUEUE_is_empty (notif_client_p, notif_queue))
106 {
107 struct notif_client *nc = QUEUE_deque (notif_client_p,
108 notif_queue);
109
110 gdb_assert (nc != except);
111
112 if (nc->can_get_pending_events (nc))
113 remote_notif_get_pending_events (nc);
114 }
115 }
116
117 static void
118 remote_async_get_pending_events_handler (gdb_client_data data)
119 {
120 gdb_assert (non_stop);
121 remote_notif_process (NULL);
122 }
123
124 /* Asynchronous signal handle registered as event loop source for when
125 the remote sent us a notification. The registered callback
126 will do a ACK sequence to pull the rest of the events out of
127 the remote side into our event queue. */
128
129 static struct async_event_handler *remote_async_get_pending_events_token;
130
131 /* Register async_event_handler for notification. */
132
133 void
134 remote_notif_register_async_event_handler (void)
135 {
136 remote_async_get_pending_events_token
137 = create_async_event_handler (remote_async_get_pending_events_handler,
138 NULL);
139 }
140
141 /* Unregister async_event_handler for notification. */
142
143 void
144 remote_notif_unregister_async_event_handler (void)
145 {
146 if (remote_async_get_pending_events_token)
147 delete_async_event_handler (&remote_async_get_pending_events_token);
148 }
149
150 /* Remote notification handler. */
151
152 void
153 handle_notification (char *buf)
154 {
155 struct notif_client *nc = NULL;
156 int i;
157
158 for (i = 0; i < ARRAY_SIZE (notifs); i++)
159 {
160 nc = notifs[i];
161 if (strncmp (buf, nc->name, strlen (nc->name)) == 0
162 && buf[strlen (nc->name)] == ':')
163 break;
164 }
165
166 /* We ignore notifications we don't recognize, for compatibility
167 with newer stubs. */
168 if (nc == NULL)
169 return;
170
171 if (nc->pending_event)
172 {
173 /* We've already parsed the in-flight reply, but the stub for some
174 reason thought we didn't, possibly due to timeout on its side.
175 Just ignore it. */
176 if (notif_debug)
177 fprintf_unfiltered (gdb_stdlog,
178 "notif: ignoring resent notification\n");
179 }
180 else
181 {
182 struct notif_event *event
183 = remote_notif_parse (nc, buf + strlen (nc->name) + 1);
184
185 /* Be careful to only set it after parsing, since an error
186 may be thrown then. */
187 nc->pending_event = event;
188
189 /* Notify the event loop there's a stop reply to acknowledge
190 and that there may be more events to fetch. */
191 QUEUE_enque (notif_client_p, notif_queue, nc);
192 if (non_stop)
193 {
194 /* In non-stop, We mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
195 in order to go on what we were doing and postpone
196 querying notification events to some point safe to do so.
197 See details in the function comment of
198 remote.c:remote_notif_get_pending_events.
199
200 In all-stop, GDB may be blocked to wait for the reply, we
201 shouldn't return to event loop until the expected reply
202 arrives. For example:
203
204 1.1) --> vCont;c
205 GDB expects getting stop reply 'T05 thread:2'.
206 1.2) <-- %Notif
207 <GDB marks the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
208
209 After step #1.2, we return to the event loop, which
210 notices there is a new event on the
211 REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and calls the
212 handler, which will send 'vNotif' packet.
213 1.3) --> vNotif
214 It is not safe to start a new sequence, because target
215 is still running and GDB is expecting the stop reply
216 from stub.
217
218 To solve this, whenever we parse a notification
219 successfully, we don't mark the
220 REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN and let GDB blocked
221 there as before to get the sequence done.
222
223 2.1) --> vCont;c
224 GDB expects getting stop reply 'T05 thread:2'
225 2.2) <-- %Notif
226 <Don't mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN>
227 2.3) <-- T05 thread:2
228
229 These pending notifications can be processed later. */
230 mark_async_event_handler (remote_async_get_pending_events_token);
231 }
232
233 if (notif_debug)
234 fprintf_unfiltered (gdb_stdlog,
235 "notif: Notification '%s' captured\n",
236 nc->name);
237 }
238 }
239
240 /* Cleanup wrapper. */
241
242 static void
243 do_notif_event_xfree (void *arg)
244 {
245 struct notif_event *event = arg;
246
247 if (event && event->dtr)
248 event->dtr (event);
249
250 xfree (event);
251 }
252
253 static void
254 notif_xfree (struct notif_client *notif)
255 {
256 if (notif->pending_event != NULL
257 && notif->pending_event->dtr != NULL)
258 notif->pending_event->dtr (notif->pending_event);
259
260 xfree (notif->pending_event);
261 xfree (notif);
262 }
263
264 /* -Wmissing-prototypes */
265 extern initialize_file_ftype _initialize_notif;
266
267 void
268 _initialize_notif (void)
269 {
270 notif_queue = QUEUE_alloc (notif_client_p, notif_xfree);
271
272 add_setshow_boolean_cmd ("notification", no_class, &notif_debug,
273 _("\
274 Set debugging of async remote notification."), _("\
275 Show debugging of async remote notification."), _("\
276 When non-zero, debugging output about async remote notifications"
277 " is enabled."),
278 NULL,
279 NULL,
280 &setdebuglist, &showdebuglist);
281 }
This page took 0.037034 seconds and 5 git commands to generate.