]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/events.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / sim / ppc / events.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1998, 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 _EVENTS_C_
23 #define _EVENTS_C_
24
25 #include "basics.h"
26 #include "events.h"
27
28 #include <signal.h>
29
30 #if !defined (SIM_EVENTS_POLL_RATE)
31 #define SIM_EVENTS_POLL_RATE 0x1000
32 #endif
33
34
35
36 /* The event queue maintains a single absolute time using two
37 variables.
38
39 TIME_OF_EVENT: this holds the time at which the next event is ment
40 to occure. If no next event it will hold the time of the last
41 event.
42
43 TIME_FROM_EVENT: The current distance from TIME_OF_EVENT. If an
44 event is pending, this will be positive. If no future event is
45 pending this will be negative. This variable is decremented once
46 for each iteration of a clock cycle.
47
48 Initially, the clock is started at time one (1) with TIME_OF_EVENT
49 == 0 and TIME_FROM_EVENT == -1.
50
51 Clearly there is a bug in that this code assumes that the absolute
52 time counter will never become greater than 2^62. */
53
54 typedef struct _event_entry event_entry;
55 struct _event_entry {
56 void *data;
57 event_handler *handler;
58 signed64 time_of_event;
59 event_entry *next;
60 };
61
62 struct _event_queue {
63 int processing;
64 event_entry *queue;
65 event_entry *volatile held;
66 event_entry *volatile *volatile held_end;
67 signed64 time_of_event;
68 signed64 time_from_event;
69 };
70
71
72 STATIC_INLINE_EVENTS\
73 (void)
74 sim_events_poll (void *data)
75 {
76 event_queue *queue = data;
77 /* just re-schedule in 1000 million ticks time */
78 event_queue_schedule (queue, SIM_EVENTS_POLL_RATE, sim_events_poll, queue);
79 sim_io_poll_quit ();
80 }
81
82
83 INLINE_EVENTS\
84 (event_queue *)
85 event_queue_create(void)
86 {
87 event_queue *new_event_queue = ZALLOC(event_queue);
88
89 new_event_queue->processing = 0;
90 new_event_queue->queue = NULL;
91 new_event_queue->held = NULL;
92 new_event_queue->held_end = &new_event_queue->held;
93
94 /* both times are already zero */
95 return new_event_queue;
96 }
97
98
99 INLINE_EVENTS\
100 (void)
101 event_queue_init(event_queue *queue)
102 {
103 event_entry *event;
104
105 /* drain the interrupt queue */
106 {
107 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
108 sigset_t old_mask;
109 sigset_t new_mask;
110 sigfillset(&new_mask);
111 /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
112 #endif
113 event = queue->held;
114 while (event != NULL) {
115 event_entry *dead = event;
116 event = event->next;
117 zfree(dead);
118 }
119 queue->held = NULL;
120 queue->held_end = &queue->held;
121 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
122 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
123 #endif
124 }
125
126 /* drain the normal queue */
127 event = queue->queue;
128 while (event != NULL) {
129 event_entry *dead = event;
130 event = event->next;
131 zfree(dead);
132 }
133 queue->queue = NULL;
134
135 /* wind time back to one */
136 queue->processing = 0;
137 queue->time_of_event = 0;
138 queue->time_from_event = -1;
139
140 /* schedule our initial counter event */
141 event_queue_schedule (queue, 0, sim_events_poll, queue);
142 }
143
144 INLINE_EVENTS\
145 (signed64)
146 event_queue_time(event_queue *queue)
147 {
148 return queue->time_of_event - queue->time_from_event;
149 }
150
151 STATIC_INLINE_EVENTS\
152 (void)
153 update_time_from_event(event_queue *events)
154 {
155 signed64 current_time = event_queue_time(events);
156 if (events->queue != NULL) {
157 events->time_from_event = (events->queue->time_of_event - current_time);
158 events->time_of_event = events->queue->time_of_event;
159 }
160 else {
161 events->time_of_event = current_time - 1;
162 events->time_from_event = -1;
163 }
164 ASSERT(current_time == event_queue_time(events));
165 ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
166 }
167
168 STATIC_INLINE_EVENTS\
169 (void)
170 insert_event_entry(event_queue *events,
171 event_entry *new_event,
172 signed64 delta)
173 {
174 event_entry *curr;
175 event_entry **prev;
176 signed64 time_of_event;
177
178 if (delta < 0)
179 error("what is past is past!\n");
180
181 /* compute when the event should occure */
182 time_of_event = event_queue_time(events) + 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 ASSERT(curr->next == NULL
189 || curr->time_of_event <= curr->next->time_of_event);
190 prev = &curr->next;
191 curr = curr->next;
192 }
193 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(events);
202 }
203
204 INLINE_EVENTS\
205 (event_entry_tag)
206 event_queue_schedule(event_queue *events,
207 signed64 delta_time,
208 event_handler *handler,
209 void *data)
210 {
211 event_entry *new_event = ZALLOC(event_entry);
212 new_event->data = data;
213 new_event->handler = handler;
214 insert_event_entry(events, new_event, delta_time);
215 TRACE(trace_events, ("event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
216 (long)event_queue_time(events),
217 (long)new_event,
218 (long)new_event->time_of_event,
219 (long)new_event->handler,
220 (long)new_event->data));
221 return (event_entry_tag)new_event;
222 }
223
224
225 INLINE_EVENTS\
226 (event_entry_tag)
227 event_queue_schedule_after_signal(event_queue *events,
228 signed64 delta_time,
229 event_handler *handler,
230 void *data)
231 {
232 event_entry *new_event = ZALLOC(event_entry);
233
234 new_event->data = data;
235 new_event->handler = handler;
236 new_event->time_of_event = delta_time; /* work it out later */
237 new_event->next = NULL;
238
239 {
240 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
241 sigset_t old_mask;
242 sigset_t new_mask;
243 sigfillset(&new_mask);
244 /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
245 #endif
246 if (events->held == NULL) {
247 events->held = new_event;
248 }
249 else {
250 *events->held_end = new_event;
251 }
252 events->held_end = &new_event->next;
253 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
254 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
255 #endif
256 }
257
258 TRACE(trace_events, ("event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
259 (long)event_queue_time(events),
260 (long)new_event,
261 (long)new_event->time_of_event,
262 (long)new_event->handler,
263 (long)new_event->data));
264
265 return (event_entry_tag)new_event;
266 }
267
268
269 INLINE_EVENTS\
270 (void)
271 event_queue_deschedule(event_queue *events,
272 event_entry_tag event_to_remove)
273 {
274 event_entry *to_remove = (event_entry*)event_to_remove;
275 ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
276 if (event_to_remove != NULL) {
277 event_entry *current;
278 event_entry **ptr_to_current;
279 for (ptr_to_current = &events->queue, current = *ptr_to_current;
280 current != NULL && current != to_remove;
281 ptr_to_current = &current->next, current = *ptr_to_current);
282 if (current == to_remove) {
283 *ptr_to_current = current->next;
284 TRACE(trace_events, ("event descheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
285 (long)event_queue_time(events),
286 (long)event_to_remove,
287 (long)current->time_of_event,
288 (long)current->handler,
289 (long)current->data));
290 zfree(current);
291 update_time_from_event(events);
292 }
293 else {
294 TRACE(trace_events, ("event descheduled at %ld - tag 0x%lx - not found\n",
295 (long)event_queue_time(events),
296 (long)event_to_remove));
297 }
298 }
299 ASSERT((events->time_from_event >= 0) == (events->queue != NULL));
300 }
301
302
303
304
305 INLINE_EVENTS\
306 (int)
307 event_queue_tick(event_queue *events)
308 {
309 signed64 time_from_event;
310
311 /* we should only be here when the previous tick has been fully processed */
312 ASSERT(!events->processing);
313
314 /* move any events that were queued by any signal handlers onto the
315 real event queue. BTW: When inlining, having this code here,
316 instead of in event_queue_process() causes GCC to put greater
317 weight on keeping the pointer EVENTS in a register. This, in
318 turn results in better code being output. */
319 if (events->held != NULL) {
320 event_entry *held_events;
321 event_entry *curr_event;
322
323 {
324 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
325 sigset_t old_mask;
326 sigset_t new_mask;
327 sigfillset(&new_mask);
328 /*-LOCK-*/ sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
329 #endif
330 held_events = events->held;
331 events->held = NULL;
332 events->held_end = &events->held;
333 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
334 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK, &old_mask, NULL);
335 #endif
336 }
337
338 do {
339 curr_event = held_events;
340 held_events = curr_event->next;
341 insert_event_entry(events, curr_event, curr_event->time_of_event);
342 } while (held_events != NULL);
343 }
344
345 /* advance time, checking to see if we've reached time zero which
346 would indicate the time for the next event has arrived */
347 time_from_event = events->time_from_event;
348 events->time_from_event = time_from_event - 1;
349 return time_from_event == 0;
350 }
351
352
353
354 INLINE_EVENTS\
355 (void)
356 event_queue_process(event_queue *events)
357 {
358 signed64 event_time = event_queue_time(events);
359
360 ASSERT((events->time_from_event == -1 && events->queue != NULL)
361 || events->processing); /* something to do */
362
363 /* consume all events for this or earlier times. Be careful to
364 allow a new event to appear under our feet */
365 events->processing = 1;
366 while (events->queue != NULL
367 && events->queue->time_of_event <= event_time) {
368 event_entry *to_do = events->queue;
369 event_handler *handler = to_do->handler;
370 void *data = to_do->data;
371 events->queue = to_do->next;
372 TRACE(trace_events, ("event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx\n",
373 (long)event_time,
374 (long)to_do,
375 (long)handler,
376 (long)data));
377 zfree(to_do);
378 handler(data);
379 }
380 events->processing = 0;
381
382 /* re-caculate time for new events */
383 update_time_from_event(events);
384 }
385
386
387 #endif /* _EVENTS_C_ */