]>
Commit | Line | Data |
---|---|---|
cb7a6892 MM |
1 | /* This file is part of the program psim. |
2 | ||
3 | Copyright (C) 1994-1995, Andrew Cagney <[email protected]> | |
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 | #ifndef STATIC_INLINE_EVENTS | |
26 | #define STATIC_INLINE_EVENTS STATIC_INLINE | |
27 | #endif | |
28 | ||
29 | ||
30 | #include "basics.h" | |
31 | #include "events.h" | |
32 | ||
33 | ||
34 | /* The event queue maintains a single absolute time using two | |
35 | variables. | |
36 | ||
37 | TIME_OF_EVENT: this holds the time at which the next event is ment | |
38 | to occure. If no next event it will hold the time of the last | |
39 | event. The first event occures at time 0 - system start. | |
40 | ||
41 | TIME_FROM_EVENT: The current distance from TIME_OF_EVENT. If an | |
42 | event is pending, this will be positive. If no future event is | |
43 | pending this will be negative. This variable is decremented once | |
44 | for each iteration of a clock cycle. | |
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 | typedef struct _event_entry event_entry; | |
50 | struct _event_entry { | |
51 | void *data; | |
52 | event_handler *handler; | |
53 | signed64 time_of_event; | |
54 | event_entry *next; | |
55 | }; | |
56 | ||
57 | struct _event_queue { | |
58 | event_entry *queue; | |
59 | event_entry *volatile held; | |
60 | event_entry *volatile *volatile held_end; | |
61 | signed64 time_of_event; | |
62 | signed64 time_from_event; | |
63 | }; | |
64 | ||
65 | ||
66 | INLINE_EVENTS event_queue * | |
67 | event_queue_create(void) | |
68 | { | |
69 | event_queue *new_event_queue = ZALLOC(event_queue); | |
70 | ||
71 | new_event_queue->queue = NULL; | |
72 | new_event_queue->held = NULL; | |
73 | new_event_queue->held_end = &new_event_queue->held; | |
74 | /* both times are already zero */ | |
75 | return new_event_queue; | |
76 | } | |
77 | ||
78 | ||
79 | ||
80 | STATIC_INLINE_EVENTS void | |
81 | insert_event_entry(event_queue *events, | |
82 | event_entry *new_event, | |
83 | signed64 delta) | |
84 | { | |
85 | event_entry *curr; | |
86 | event_entry **last; | |
87 | signed64 time_of_event; | |
88 | ||
89 | if (delta <= 0) | |
90 | error("can not schedule event for current time\n"); | |
91 | ||
92 | /* compute when the event should occure */ | |
93 | time_of_event = (events->time_of_event | |
94 | - events->time_from_event | |
95 | + delta); | |
96 | ||
97 | /* find the queue insertion point - things are time ordered */ | |
98 | last = &events->queue; | |
99 | curr = events->queue; | |
100 | while (curr != NULL && time_of_event >= curr->time_of_event) { | |
101 | last = &curr->next; | |
102 | curr = curr->next; | |
103 | } | |
104 | ||
105 | /* insert it */ | |
106 | new_event->next = curr; | |
107 | *last = new_event; | |
108 | new_event->time_of_event = time_of_event; | |
109 | ||
110 | /* adjust the time until the first event */ | |
111 | events->time_from_event = (events->queue->time_of_event | |
112 | - (events->time_of_event | |
113 | - events->time_from_event)); | |
114 | events->time_of_event = events->queue->time_of_event; | |
115 | } | |
116 | ||
117 | INLINE_EVENTS event_entry_tag | |
118 | event_queue_schedule(event_queue *events, | |
119 | signed64 delta_time, | |
120 | event_handler *handler, | |
121 | void *data) | |
122 | { | |
123 | event_entry *new_event = ZALLOC(event_entry); | |
124 | new_event->data = data; | |
125 | new_event->handler = handler; | |
126 | insert_event_entry(events, new_event, delta_time); | |
127 | return new_event; | |
128 | } | |
129 | ||
130 | ||
131 | INLINE_EVENTS event_entry_tag | |
132 | event_queue_schedule_after_signal(event_queue *events, | |
133 | signed64 delta_time, | |
134 | event_handler *handler, | |
135 | void *data) | |
136 | { | |
137 | event_entry *new_event = ZALLOC(event_entry); | |
138 | ||
139 | new_event->data = data; | |
140 | new_event->handler = handler; | |
141 | new_event->time_of_event = delta_time; /* work it out later */ | |
142 | new_event->next = NULL; | |
143 | ||
144 | /*-LOCK-*/ | |
145 | if (events->held == NULL) { | |
146 | events->held = new_event; | |
147 | } | |
148 | else { | |
149 | *events->held_end = new_event; | |
150 | } | |
151 | events->held_end = &new_event->next; | |
152 | /*-UNLOCK-*/ | |
153 | ||
154 | return new_event; | |
155 | } | |
156 | ||
157 | ||
158 | INLINE_EVENTS void | |
159 | event_queue_deschedule(event_queue *events, | |
160 | event_entry_tag event_to_remove) | |
161 | { | |
162 | if (event_to_remove != NULL) { | |
163 | event_entry *current; | |
164 | event_entry **ptr_to_current; | |
165 | for (ptr_to_current = &events->queue, current = *ptr_to_current; | |
166 | current != NULL && current != event_to_remove; | |
167 | ptr_to_current = ¤t->next, current = *ptr_to_current); | |
168 | if (current == event_to_remove) { | |
169 | *ptr_to_current = current->next; | |
170 | zfree(current); | |
171 | /* Just forget to recompute the delay to the next event */ | |
172 | } | |
173 | } | |
174 | } | |
175 | ||
176 | ||
177 | ||
178 | ||
179 | INLINE_EVENTS int | |
180 | event_queue_tick(event_queue *events) | |
181 | { | |
182 | /* remove things from the asynchronous event queue onto the real one */ | |
183 | if (events->held != NULL) { | |
184 | event_entry *held_events; | |
185 | event_entry *curr_event; | |
186 | ||
187 | /*-LOCK-*/ | |
188 | held_events = events->held; | |
189 | events->held = NULL; | |
190 | events->held_end = &events->held; | |
191 | /*-UNLOCK-*/ | |
192 | ||
193 | do { | |
194 | curr_event = held_events; | |
195 | held_events = curr_event->next; | |
196 | insert_event_entry(events, curr_event, curr_event->time_of_event); | |
197 | } while (held_events != NULL); | |
198 | } | |
199 | ||
200 | /* advance time, checking to see if we've reached time zero which | |
201 | would indicate the time for the next event has arrived */ | |
202 | events->time_from_event -= 1; | |
203 | return events->time_from_event == 0; | |
204 | } | |
205 | ||
206 | INLINE_EVENTS void | |
207 | event_queue_process(event_queue *events) | |
208 | { | |
209 | if (events->time_from_event == 0) { | |
210 | /* consume all events for this or earlier times */ | |
211 | do { | |
212 | event_entry *to_do = events->queue; | |
213 | events->queue = to_do->next; | |
214 | to_do->handler(events, | |
215 | to_do->data); | |
216 | zfree(to_do); | |
217 | } while (events->queue != NULL | |
218 | && events->queue->time_of_event <= events->time_of_event); | |
219 | /* re-caculate time for new events */ | |
220 | if (events->queue != NULL) { | |
221 | events->time_from_event = (events->queue->time_of_event | |
222 | - events->time_of_event); | |
223 | events->time_of_event = events->queue->time_of_event; | |
224 | } | |
225 | else { | |
226 | /* nothing to do, time_from_event will go negative */ | |
227 | } | |
228 | } | |
229 | } | |
230 | ||
231 | INLINE_EVENTS signed64 | |
232 | event_queue_time(event_queue *queue) | |
233 | { | |
234 | return queue->time_of_event - queue->time_from_event; | |
235 | } | |
236 | ||
237 | ||
238 | #endif /* _EVENTS_C_ */ |