Commit | Line | Data |
---|---|---|
722247f1 YQ |
1 | /* Remote notification in GDB protocol |
2 | ||
28e7fd62 | 3 | Copyright (C) 1988-2013 Free Software Foundation, Inc. |
722247f1 YQ |
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" | |
c9b6281a | 41 | #include "gdbcmd.h" |
722247f1 YQ |
42 | |
43 | #include <string.h> | |
44 | ||
99f0a309 | 45 | int notif_debug = 0; |
722247f1 YQ |
46 | |
47 | /* Supported clients of notifications. */ | |
48 | ||
49 | static struct notif_client *notifs[] = | |
50 | { | |
51 | ¬if_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); | |
c9b6281a YQ |
271 | |
272 | add_setshow_boolean_cmd ("notification", no_class, ¬if_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); | |
722247f1 | 281 | } |