1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 a_events.h - Internal Event System
4 ---------------------------------------------------------------------------
5 * Copyright (C) 2002, David Olofson
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #ifndef _A_EVENTS_H_
23 #define _A_EVENTS_H_
24
25 #define AEV_TRACKING
26
27 #include "a_globals.h"
28 #include "a_types.h"
29
30 /*----------------------------------------------------------
31 Open/Close
32 ----------------------------------------------------------*/
33 int aev_open(int pool_size);
34 void aev_close(void);
35
36
37 /*----------------------------------------------------------
38 The global event timestamp time base
39 ----------------------------------------------------------*/
40 #define AEV_TIMESTAMP_MASK 0xffff
41 typedef Uint16 aev_timestamp_t;
42
43 extern aev_timestamp_t aev_timer;
44
aev_reset_timer(void)45 static inline void aev_reset_timer(void)
46 {
47 aev_timer = 0;
48 }
49
aev_advance_timer(unsigned frames)50 static inline void aev_advance_timer(unsigned frames)
51 {
52 aev_timer += (aev_timestamp_t)frames;
53 }
54
55
56 /*----------------------------------------------------------
57 Event
58 ----------------------------------------------------------*/
59 #define AEV_ET_FREE 0xff
60 #define AEV_ET_ALLOCATED 0xfe
61
62 struct aev_port_t;
63 typedef struct aev_event_t
64 {
65 struct aev_event_t *next;
66 aev_timestamp_t frame; /* When */
67 Uint8 type; /* What */
68 Uint8 index; /* Qualifier */
69 Sint32 arg1; /* Argument 1 */
70 Sint32 arg2; /* Argument 2 */
71 Sint32 arg3; /* Argument 3 */
72 #ifdef AEV_TRACKING
73 const char *client; /* Client name */
74 struct aev_port_t *port; /* Receiver port */
75 #endif
76 } aev_event_t;
77
78
79 /* Macro for interpreting event timestamps. */
80 #define AEV_TIME(frame, offset) \
81 ((unsigned)(frame - aev_timer - offset) & \
82 AEV_TIMESTAMP_MASK)
83
84 /* The global event pool. */
85 extern aev_event_t *aev_event_pool;
86
87 #ifdef AEV_TRACKING
88 extern int aev_event_counter; //Current number of events in use
89 extern int aev_event_counter_max; //Peak use tracker
90 extern const char *aev_current_client; //Name of current client
91 #endif
92
93 #ifdef AEV_TRACKING
94 #define aev_client(x) aev_current_client = x;
95 #else
96 #define aev_client(x)
97 #endif
98
99 /* Refill event pool. */
100 int _aev_refill_pool(void);
101
102 /*
103 * Allocate an event.
104 *
105 * Will try to refill the event pool if required.
106 * Returns the event, or NULL, if the pool was empty
107 * and could not be refilled.
108 */
aev_new(void)109 static inline aev_event_t *aev_new(void)
110 {
111 aev_event_t *ev;
112 if(!aev_event_pool)
113 if(_aev_refill_pool() < 0)
114 return NULL;
115
116 ev = aev_event_pool;
117 aev_event_pool = ev->next;
118 #ifdef AEV_TRACKING
119 ev->type = AEV_ET_ALLOCATED;
120 ev->client = aev_current_client;
121 ++aev_event_counter;
122 if(aev_event_counter > aev_event_counter_max)
123 aev_event_counter_max = aev_event_counter;
124 #endif
125 return ev;
126 }
127
128
129 /* Free an event. */
aev_free(aev_event_t * ev)130 static inline void aev_free(aev_event_t *ev)
131 {
132 ev->next = aev_event_pool;
133 aev_event_pool = ev;
134 #ifdef AEV_TRACKING
135 ev->type = AEV_ET_FREE;
136 --aev_event_counter;
137 #endif
138 }
139
140
141 /*----------------------------------------------------------
142 Event Input Port
143 ----------------------------------------------------------*/
144 typedef struct aev_port_t
145 {
146 /*
147 * Note that when 'first' is NULL, 'last' is undefined!
148 * (If there's no first event, there can't be a last
149 * event either - makes sense, eh? :-)
150 */
151 aev_event_t *first;
152 aev_event_t *last;
153 const char *name;
154 } aev_port_t;
155
156
157 /*
158 * Initialize a port.
159 *****************************************
160 * DO NOT FORGET TO USE THIS!
161 *****************************************
162 */
aev_port_init(aev_port_t * evp,const char * name)163 static inline void aev_port_init(aev_port_t *evp, const char *name)
164 {
165 evp->first = evp->last = NULL;
166 evp->name = name;
167 }
168
169
170 /*
171 * Write one event to a port. The event will belong to the
172 * owner of the port, who is responsible for freeing or
173 * reusing the event after reading it.
174 *
175 * NOTE: Events must be queued in increasing timestamp order!
176 */
aev_write(aev_port_t * evp,aev_event_t * ev)177 static inline void aev_write(aev_port_t *evp, aev_event_t *ev)
178 {
179 ev->next = NULL;
180 if(!evp->first)
181 evp->first = evp->last = ev; /* Oops, empty port! */
182 else
183 {
184 evp->last->next = ev;
185 evp->last = ev;
186 }
187 #ifdef AEV_TRACKING
188 ev->port = evp;
189 #endif
190 }
191
192
193 /*
194 * Insert an event at the right position in the queue of
195 * the specified port. The event will be placed *after*
196 * any other events with the same timestamp.
197 *
198 * The event will belong to the owner of the port, who is
199 * responsible for freeing or reusing the event after
200 * reading it.
201 */
202 void aev_insert(aev_port_t *evp, aev_event_t *ev);
203
204
205 /*
206 * Read one event from a port. The event will be removed
207 * from the port, and is effectively detached from the
208 * event system until you reuse it by sending it somewhere,
209 * or free it.
210 *
211 * WARNING: Events *MUST* be either freed or reused!
212 *
213 * Event leaks will result in severe timing issues, as the
214 * pool will need to be refilled regularly, which is *not*
215 * a real time compatible operation.
216 *
217 * Returns the event, or NULL, if no event was queued.
218 */
aev_read(aev_port_t * evp)219 static inline aev_event_t *aev_read(aev_port_t *evp)
220 {
221 aev_event_t *ev = evp->first;
222 if(!ev)
223 return NULL;
224
225 evp->first = ev->next;
226 return ev;
227 }
228
229 /*
230 * Return number of frames from the start of the current
231 * buffer (current value of 'aev_timer') + 'offset' to
232 * the next event queued on this port.
233 *
234 * If there's no event enqueued, the maximum possible
235 * number of frames is returned.
236 */
aev_next(aev_port_t * evp,unsigned offset)237 static inline unsigned aev_next(aev_port_t *evp, unsigned offset)
238 {
239 aev_event_t *ev = evp->first;
240 if(ev)
241 return AEV_TIME(ev->frame, offset);
242 else
243 return AEV_TIMESTAMP_MASK;
244 }
245
246
247 /*
248 * Remove and free all events on the specified port.
249 */
aev_flush(aev_port_t * evp)250 static inline void aev_flush(aev_port_t *evp)
251 {
252 #ifdef AEV_TRACKING
253 while(1)
254 {
255 aev_event_t *ev = evp->first;
256 if(!ev)
257 return;
258
259 evp->first = ev->next;
260 aev_free(ev);
261 }
262 #else
263 /*
264 * Silly me! I've pulled this simple trick
265 * before, but just forgot somehow... :-)
266 */
267 if(!evp->first)
268 return;
269
270 evp->last->next = aev_event_pool;
271 aev_event_pool = evp->first;
272 evp->first = NULL;
273 #endif
274 }
275
276
277 /*
278 * Short and handy "send" functions.
279 *
280 * Allocates an event, fills it in, and sends it to the
281 * specified port. The address of the event used is
282 * returned - which means that you can detect an error
283 * by checking that the return is not NULL.
284 */
aev_send0(aev_port_t * evp,aev_timestamp_t delay,Uint8 type)285 static inline aev_event_t *aev_send0(aev_port_t *evp,
286 aev_timestamp_t delay, Uint8 type)
287 {
288 aev_event_t *ev = aev_new();
289 if(!ev)
290 return NULL;
291 ev->type = type;
292 ev->frame = delay + aev_timer;
293 aev_write(evp, ev);
294 return ev;
295 }
296
aev_send1(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Sint32 arg1)297 static inline aev_event_t *aev_send1(aev_port_t *evp,
298 aev_timestamp_t delay, Uint8 type, Sint32 arg1)
299 {
300 aev_event_t *ev = aev_new();
301 if(!ev)
302 return NULL;
303 ev->type = type;
304 ev->frame = delay + aev_timer;
305 ev->arg1 = arg1;
306 aev_write(evp, ev);
307 return ev;
308 }
309
aev_send2(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Sint32 arg1,Sint32 arg2)310 static inline aev_event_t *aev_send2(aev_port_t *evp,
311 aev_timestamp_t delay, Uint8 type, Sint32 arg1, Sint32 arg2)
312 {
313 aev_event_t *ev = aev_new();
314 if(!ev)
315 return NULL;
316 ev->type = type;
317 ev->frame = delay + aev_timer;
318 ev->arg1 = arg1;
319 ev->arg2 = arg2;
320 aev_write(evp, ev);
321 return ev;
322 }
323
aev_sendi0(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Uint8 index)324 static inline aev_event_t *aev_sendi0(aev_port_t *evp,
325 aev_timestamp_t delay, Uint8 type, Uint8 index)
326 {
327 aev_event_t *ev = aev_new();
328 if(!ev)
329 return NULL;
330 ev->type = type;
331 ev->index = index;
332 ev->frame = delay + aev_timer;
333 aev_write(evp, ev);
334 return ev;
335 }
336
aev_sendi1(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Uint8 index,Sint32 arg1)337 static inline aev_event_t *aev_sendi1(aev_port_t *evp,
338 aev_timestamp_t delay, Uint8 type,
339 Uint8 index, Sint32 arg1)
340 {
341 aev_event_t *ev = aev_new();
342 if(!ev)
343 return NULL;
344 ev->type = type;
345 ev->index = index;
346 ev->frame = delay + aev_timer;
347 ev->arg1 = arg1;
348 aev_write(evp, ev);
349 return ev;
350 }
351
aev_sendi2(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Uint8 index,Sint32 arg1,Sint32 arg2)352 static inline aev_event_t *aev_sendi2(aev_port_t *evp,
353 aev_timestamp_t delay, Uint8 type,
354 Uint8 index, Sint32 arg1, Sint32 arg2)
355 {
356 aev_event_t *ev = aev_new();
357 if(!ev)
358 return NULL;
359 ev->type = type;
360 ev->index = index;
361 ev->frame = delay + aev_timer;
362 ev->arg1 = arg1;
363 ev->arg2 = arg2;
364 aev_write(evp, ev);
365 return ev;
366 }
367
368 /*
369 * Like the above, but using aev_insert().
370 */
aev_insert0(aev_port_t * evp,aev_timestamp_t delay,Uint8 type)371 static inline aev_event_t *aev_insert0(aev_port_t *evp,
372 aev_timestamp_t delay, Uint8 type)
373 {
374 aev_event_t *ev = aev_new();
375 if(!ev)
376 return NULL;
377 ev->type = type;
378 ev->frame = delay + aev_timer;
379 aev_insert(evp, ev);
380 return ev;
381 }
382
aev_insert1(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Sint32 arg1)383 static inline aev_event_t *aev_insert1(aev_port_t *evp,
384 aev_timestamp_t delay, Uint8 type, Sint32 arg1)
385 {
386 aev_event_t *ev = aev_new();
387 if(!ev)
388 return NULL;
389 ev->type = type;
390 ev->frame = delay + aev_timer;
391 ev->arg1 = arg1;
392 aev_insert(evp, ev);
393 return ev;
394 }
395
aev_insert2(aev_port_t * evp,aev_timestamp_t delay,Uint8 type,Sint32 arg1,Sint32 arg2)396 static inline aev_event_t *aev_insert2(aev_port_t *evp,
397 aev_timestamp_t delay, Uint8 type,
398 Sint32 arg1, Sint32 arg2)
399 {
400 aev_event_t *ev = aev_new();
401 if(!ev)
402 return NULL;
403 ev->type = type;
404 ev->frame = delay + aev_timer;
405 ev->arg1 = arg1;
406 ev->arg2 = arg2;
407 aev_insert(evp, ev);
408 return ev;
409 }
410
411 #endif /*_A_EVENTS_H_*/
412