]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/sim-events.c
Ref gdb/11763 - can't stop a running simulator:
[thirdparty/binutils-gdb.git] / sim / common / sim-events.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22 #ifndef _SIM_EVENTS_C_
23 #define _SIM_EVENTS_C_
24
25 #include "sim-main.h"
26 #include "sim-assert.h"
27
28 #include <signal.h>
29
30
31 /* The event queue maintains a single absolute time using two
32 variables.
33
34 TIME_OF_EVENT: this holds the time at which the next event is ment
35 to occure. If no next event it will hold the time of the last
36 event.
37
38 TIME_FROM_EVENT: The current distance from TIME_OF_EVENT. If an
39 event is pending, this will be positive. If no future event is
40 pending this will be negative. This variable is decremented once
41 for each iteration of a clock cycle.
42
43 Initially, the clock is started at time one (0) with TIME_OF_EVENT
44 == 0 and TIME_FROM_EVENT == 0.
45
46 Clearly there is a bug in that this code assumes that the absolute
47 time counter will never become greater than 2^62.
48
49 To avoid the need to use 64bit arithmetic, the event queue always
50 contains at least one event scheduled every 16 000 ticks. This
51 limits the time from event counter to values less than
52 16 000. */
53
54
55 #if !defined (SIM_EVENTS_POLL_RATE)
56 #define SIM_EVENTS_POLL_RATE 0x4000
57 #endif
58
59
60 #define _ETRACE sd
61
62 #undef ETRACE
63 #define ETRACE(ARGS) \
64 do \
65 { \
66 if (WITH_TRACE) \
67 { \
68 if (sd->events.trace) \
69 { \
70 const char *file; \
71 SIM_FILTER_PATH(file, __FILE__); \
72 sim_io_printf (sd, "%s:%d: ", file, __LINE__); \
73 sim_io_printf ARGS; \
74 } \
75 } \
76 } \
77 while (0)
78
79
80 STATIC_INLINE_SIM_EVENTS\
81 (void)
82 sim_events_poll (void *data)
83 {
84 /* just re-schedule in 1000 million ticks time */
85 SIM_DESC sd = data;
86 sim_events_schedule(sd, SIM_EVENTS_POLL_RATE, sim_events_poll, sd);
87 sim_io_poll_quit (sd);
88 }
89
90
91 INLINE_SIM_EVENTS\
92 (void)
93 sim_events_init(SIM_DESC sd)
94 {
95 sim_events *events = &sd->events;
96 sim_event *event;
97
98 /* drain the interrupt queue */
99 {
100 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
101 sigset_t old_mask;
102 sigset_t new_mask;
103 sigfillset(&new_mask);
104 /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
105 #endif
106 event = events->held;
107 while (event != NULL) {
108 sim_event *dead = event;
109 event = event->next;
110 zfree(dead);
111 }
112 events->held = NULL;
113 events->held_end = &events->held;
114 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
115 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
116 #endif
117 }
118
119 /* drain the normal queue */
120 event = events->queue;
121 while (event != NULL) {
122 sim_event *dead = event;
123 event = event->next;
124 zfree(dead);
125 }
126 events->queue = NULL;
127
128 /* wind time back to zero */
129 events->processing = 0;
130 events->time_of_event = 0;
131 events->time_from_event = 0;
132
133 /* schedule our initial counter event */
134 sim_events_schedule(sd, 0, sim_events_poll, sd);
135
136 /* from now on, except when the large-int event is being processed
137 the event queue is non empty */
138 SIM_ASSERT(events->queue != NULL);
139 }
140
141 INLINE_SIM_EVENTS\
142 (signed64)
143 sim_events_time(SIM_DESC sd)
144 {
145 sim_events *events = &sd->events;
146 return events->time_of_event - events->time_from_event;
147 }
148
149 STATIC_INLINE_SIM_EVENTS\
150 (void)
151 update_time_from_event(SIM_DESC sd)
152 {
153 sim_events *events = &sd->events;
154 signed64 current_time = sim_events_time(sd);
155 if (events->queue != NULL) {
156 events->time_from_event = (events->queue->time_of_event - current_time);
157 events->time_of_event = events->queue->time_of_event;
158 }
159 else {
160 events->time_of_event = current_time - 1;
161 events->time_from_event = -1;
162 }
163 SIM_ASSERT(current_time == sim_events_time (sd));
164 SIM_ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
165 }
166
167 STATIC_INLINE_SIM_EVENTS\
168 (void)
169 insert_sim_event(SIM_DESC sd,
170 sim_event *new_event,
171 signed64 delta)
172 {
173 sim_events *events = &sd->events;
174 sim_event *curr;
175 sim_event **prev;
176 signed64 time_of_event;
177
178 if (delta < 0)
179 engine_error (sd, "what is past is past!\n");
180
181 /* compute when the event should occure */
182 time_of_event = sim_events_time(sd) + delta;
183
184 /* find the queue insertion point - things are time ordered */
185 prev = &events->queue;
186 curr = events->queue;
187 while (curr != NULL && time_of_event >= curr->time_of_event) {
188 SIM_ASSERT(curr->next == NULL
189 || curr->time_of_event <= curr->next->time_of_event);
190 prev = &curr->next;
191 curr = curr->next;
192 }
193 SIM_ASSERT(curr == NULL || time_of_event < curr->time_of_event);
194
195 /* insert it */
196 new_event->next = curr;
197 *prev = new_event;
198 new_event->time_of_event = time_of_event;
199
200 /* adjust the time until the first event */
201 update_time_from_event(sd);
202 }
203
204 INLINE_SIM_EVENTS\
205 (sim_event *)
206 sim_events_schedule(SIM_DESC sd,
207 signed64 delta_time,
208 sim_event_handler *handler,
209 void *data)
210 {
211 sim_event *new_event = ZALLOC(sim_event);
212 new_event->data = data;
213 new_event->handler = handler;
214 insert_sim_event(sd, new_event, delta_time);
215 ETRACE((_ETRACE,
216 "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
217 (long)sim_events_time(sd),
218 (long)new_event,
219 (long)new_event->time_of_event,
220 (long)new_event->handler,
221 (long)new_event->data));
222 return new_event;
223 }
224
225
226 INLINE_SIM_EVENTS\
227 (sim_event *)
228 sim_events_schedule_after_signal(SIM_DESC sd,
229 signed64 delta_time,
230 sim_event_handler *handler,
231 void *data)
232 {
233 sim_events *events = &sd->events;
234 sim_event *new_event = ZALLOC(sim_event);
235
236 new_event->data = data;
237 new_event->handler = handler;
238 new_event->time_of_event = delta_time; /* work it out later */
239 new_event->next = NULL;
240
241 {
242 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
243 sigset_t old_mask;
244 sigset_t new_mask;
245 sigfillset(&new_mask);
246 /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
247 #endif
248 if (events->held == NULL) {
249 events->held = new_event;
250 }
251 else {
252 *events->held_end = new_event;
253 }
254 events->held_end = &new_event->next;
255 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
256 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
257 #endif
258 }
259
260 ETRACE((_ETRACE,
261 "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
262 (long)sim_events_time(sd),
263 (long)new_event,
264 (long)new_event->time_of_event,
265 (long)new_event->handler,
266 (long)new_event->data));
267
268 return new_event;
269 }
270
271
272 INLINE_SIM_EVENTS\
273 (void)
274 sim_events_deschedule(SIM_DESC sd,
275 sim_event *event_to_remove)
276 {
277 sim_events *events = &sd->events;
278 sim_event *to_remove = (sim_event*)event_to_remove;
279 SIM_ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
280 if (event_to_remove != NULL) {
281 sim_event *current;
282 sim_event **ptr_to_current;
283 for (ptr_to_current = &events->queue, current = *ptr_to_current;
284 current != NULL && current != to_remove;
285 ptr_to_current = &current->next, current = *ptr_to_current);
286 if (current == to_remove) {
287 *ptr_to_current = current->next;
288 ETRACE((_ETRACE,
289 "event descheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
290 (long)sim_events_time(sd),
291 (long)event_to_remove,
292 (long)current->time_of_event,
293 (long)current->handler,
294 (long)current->data));
295 zfree(current);
296 update_time_from_event(sd);
297 }
298 else {
299 ETRACE((_ETRACE,
300 "event descheduled at %ld - tag 0x%lx - not found\n",
301 (long)sim_events_time(sd),
302 (long)event_to_remove));
303 }
304 }
305 SIM_ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
306 }
307
308
309
310
311 INLINE_SIM_EVENTS\
312 (int)
313 sim_events_tick(SIM_DESC sd)
314 {
315 sim_events *events = &sd->events;
316
317 /* we should only be here when the previous tick has been fully
318 processed */
319 SIM_ASSERT(!events->processing && events->queue != NULL);
320
321 /* Advance the time but *only* if there is nothing to process */
322 if (events->time_from_event == 0)
323 return 1;
324 else if (events->held != NULL)
325 return 1;
326 else {
327 events->time_from_event -= 1;
328 return 0;
329 }
330 }
331
332
333
334 INLINE_SIM_EVENTS\
335 (void)
336 sim_events_process(SIM_DESC sd)
337 {
338 sim_events *events = &sd->events;
339 signed64 event_time = sim_events_time(sd);
340
341 /* something to do */
342 SIM_ASSERT(events->time_from_event == 0 || events->held != NULL);
343 SIM_ASSERT(events->queue != NULL);
344
345 /* move any events that were queued by any signal handlers onto the
346 real event queue. */
347 if (events->held != NULL) {
348 sim_event *held_events;
349 sim_event *curr_event;
350
351 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
352 /*-LOCK-*/
353 sigset_t old_mask;
354 sigset_t new_mask;
355 sigfillset(&new_mask);
356 sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
357 #endif
358
359 held_events = events->held;
360 events->held = NULL;
361 events->held_end = &events->held;
362
363 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
364 /*-UNLOCK-*/
365 sigprocmask(SIG_SETMASK, &old_mask, NULL);
366 #endif
367
368 do {
369 curr_event = held_events;
370 held_events = curr_event->next;
371 insert_sim_event(sd, curr_event, curr_event->time_of_event);
372 } while (held_events != NULL);
373 }
374
375 /* consume all events for this or earlier times. Be careful to
376 allow a new event to appear under our feet */
377 events->processing = 1;
378 while (events->queue->time_of_event <= event_time) {
379 sim_event *to_do = events->queue;
380 sim_event_handler *handler = to_do->handler;
381 void *data = to_do->data;
382 events->queue = to_do->next;
383 ETRACE((_ETRACE,
384 "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx\n",
385 (long)event_time,
386 (long)to_do,
387 (long)handler,
388 (long)data));
389 zfree (to_do);
390 handler (data);
391 }
392 events->processing = 0;
393
394 /* re-caculate time for new events - advance the time */
395 update_time_from_event(sd);
396 SIM_ASSERT(events->time_from_event > 0 && events->queue != NULL);
397 events->time_from_event -= 1;
398 }
399
400 #endif