1 /* Public domain */
2
3 #include <agar/core/begin.h>
4
5 #define AG_EVENT_ARGS_MAX 16
6 #define AG_EVENT_NAME_MAX 32
7
8 #ifdef AG_DEBUG
9 # define AG_PTR(v) (event->argv[v].type==AG_VARIABLE_POINTER ? event->argv[v].data.p : AG_PtrMismatch())
10 # define AG_OBJECT(v,t) (AG_OfClass(event->argv[v].data.p,(t))) ? event->argv[v].data.p : AG_ObjectMismatch(AGOBJECT(event->argv[v].data.p)->cls->hier,(t))
11 # define AG_STRING(v) (event->argv[v].type==AG_VARIABLE_STRING ? event->argv[v].data.s : (char *)AG_PtrMismatch())
12 # define AG_INT(v) (event->argv[v].type==AG_VARIABLE_INT ? event->argv[v].data.i : AG_IntMismatch())
13 # define AG_UINT(v) (event->argv[v].type==AG_VARIABLE_UINT ? event->argv[v].data.u : (Uint)AG_IntMismatch())
14 # define AG_LONG(v) (event->argv[v].type==AG_VARIABLE_SINT32 ? event->argv[v].data.s32 : (Sint32)AG_IntMismatch())
15 # define AG_ULONG(v) (event->argv[v].type==AG_VARIABLE_UINT32 ? event->argv[v].data.u32 : (Uint32)AG_IntMismatch())
16 # define AG_FLOAT(v) (event->argv[v].type==AG_VARIABLE_FLOAT ? event->argv[v].data.flt : AG_FloatMismatch())
17 # define AG_DOUBLE(v) (event->argv[v].type==AG_VARIABLE_DOUBLE ? event->argv[v].data.dbl : (double)AG_FloatMismatch())
18 #else /* !AG_DEBUG */
19 # define AG_PTR(v) (event->argv[v].data.p)
20 # define AG_OBJECT(v,t) (event->argv[v].data.p)
21 # define AG_STRING(v) (event->argv[v].data.s)
22 # define AG_INT(v) (event->argv[v].data.i)
23 # define AG_UINT(v) (event->argv[v].data.u)
24 # define AG_LONG(v) ((long)event->argv[v].data.s32)
25 # define AG_ULONG(v) ((Ulong)event->argv[v].data.u32)
26 # define AG_FLOAT(v) ((float)event->argv[v].data.flt)
27 # define AG_DOUBLE(v) (event->argv[v].data.dbl)
28 #endif /* AG_DEBUG */
29
30 #define AG_SELF() AG_PTR(0)
31 #define AG_SENDER() AG_PTR(event->argc)
32
33 #define AG_PTR_NAMED(k) AG_GetNamedPtr(event,(k))
34 #define AG_OBJECT_NAMED(k,cls) AG_GetNamedObject(event,(k),(cls))
35 #define AG_STRING_NAMED(k) AG_GetNamedString(event,(k))
36 #define AG_INT_NAMED(k) AG_GetNamedInt(event,(k))
37 #define AG_UINT_NAMED(k) AG_GetNamedUint(event,(k))
38 #define AG_LONG_NAMED(k) AG_GetNamedLong(event,(k))
39 #define AG_ULONG_NAMED(k) AG_GetNamedUlong(event,(k))
40 #define AG_FLOAT_NAMED(k) AG_GetNamedFlt(event,(k))
41 #define AG_DOUBLE_NAMED(k) AG_GetNamedDbl(event,(k))
42
43 struct ag_timer;
44 struct ag_event_sink;
45
46 /* Event handler / virtual function */
47 typedef struct ag_event {
48 char name[AG_EVENT_NAME_MAX]; /* String identifier */
49 Uint flags;
50 #define AG_EVENT_ASYNC 0x01 /* Service in separate thread */
51 #define AG_EVENT_PROPAGATE 0x02 /* Forward to child objs */
52 union ag_function fn; /* Callback function */
53 int argc, argc0; /* Argument count & offset */
54 AG_Variable argv[AG_EVENT_ARGS_MAX]; /* Argument values */
55 AG_TAILQ_ENTRY(ag_event) events; /* Entry in Object */
56 } AG_Event, AG_Function;
57
58 /* Low-level event sink */
59 enum ag_event_sink_type {
60 AG_SINK_NONE,
61 AG_SINK_PROLOGUE, /* Special event loop prologue */
62 AG_SINK_EPILOGUE, /* Special event sink epilogue */
63 AG_SINK_SPINNER, /* Special non-blocking sink */
64 AG_SINK_TERMINATOR, /* Quit request */
65 AG_SINK_TIMER, /* Timer expiration */
66 AG_SINK_READ, /* Data available on fd */
67 AG_SINK_WRITE, /* Write buffer available on fd */
68 AG_SINK_FSEVENT, /* Filesystem event */
69 AG_SINK_PROCEVENT, /* Process event */
70 AG_SINK_LAST
71 };
72
73 typedef int (*AG_EventSinkFn)(struct ag_event_sink *, AG_Event *);
74
75 typedef struct ag_event_sink {
76 enum ag_event_sink_type type; /* Event filter type */
77 int ident; /* Identifier / fd */
78 Uint flags, flagsMatched;
79 #define AG_FSEVENT_DELETE 0x0001 /* Referenced file deleted */
80 #define AG_FSEVENT_WRITE 0x0002 /* Write occured */
81 #define AG_FSEVENT_EXTEND 0x0004 /* File extended */
82 #define AG_FSEVENT_ATTRIB 0x0008 /* File attributes changed */
83 #define AG_FSEVENT_LINK 0x0010 /* Link count changed */
84 #define AG_FSEVENT_RENAME 0x0020 /* Referenced file renamed */
85 #define AG_FSEVENT_REVOKE 0x0040 /* Filesystem unmount / revoke() */
86 #define AG_PROCEVENT_EXIT 0x1000 /* Process exited */
87 #define AG_PROCEVENT_FORK 0x2000 /* Process forked */
88 #define AG_PROCEVENT_EXEC 0x4000 /* Process exec'd */
89 AG_EventSinkFn fn; /* Sink function */
90 AG_Event fnArgs; /* Sink function arguments */
91 AG_TAILQ_ENTRY(ag_event_sink) sinks; /* Epilogue "sinks" */
92 } AG_EventSink;
93
94 /* Low-level event source */
95 typedef struct ag_event_source {
96 int caps[AG_SINK_LAST]; /* Capabilities */
97 Uint flags;
98 int breakReq; /* Break from event loop */
99 int returnCode; /* AG_EventLoop() return code */
100 int (*sinkFn)(void);
101 int (*addTimerFn)(struct ag_timer *, Uint32, int);
102 void (*delTimerFn)(struct ag_timer *);
103 int (*resetTimerFn)(struct ag_timer *, Uint32, int);
104 AG_TAILQ_HEAD_(ag_event_sink) prologues; /* Event prologues */
105 AG_TAILQ_HEAD_(ag_event_sink) epilogues; /* Event sink epilogues */
106 AG_TAILQ_HEAD_(ag_event_sink) spinners; /* Spinning sinks */
107 AG_TAILQ_HEAD_(ag_event_sink) sinks; /* Normal event sinks */
108 } AG_EventSource;
109
110 /* Queue of events */
111 typedef struct ag_event_queue {
112 Uint nEvents;
113 AG_Event *events;
114 } AG_EventQ;
115
116 typedef void (*AG_EventFn)(AG_Event *);
117
118 #ifdef AG_DEBUG
119 #define AG_EVENT_BOUNDARY_CHECK(ev) \
120 if ((ev)->argc >= AG_EVENT_ARGS_MAX-1) \
121 AG_FatalError("Too many AG_Event(3) arguments");
122 #else
123 #define AG_EVENT_BOUNDARY_CHECK(ev)
124 #endif
125
126 #define AG_EVENT_INS_VAL(eev,tname,aname,member,val) { \
127 AG_EVENT_BOUNDARY_CHECK(eev) \
128 (eev)->argv[(eev)->argc].type = (tname); \
129 if ((aname) != NULL) { \
130 AG_Strlcpy((eev)->argv[(eev)->argc].name, (aname), \
131 AG_VARIABLE_NAME_MAX); \
132 } else { \
133 (eev)->argv[(eev)->argc].name[0] = '\0'; \
134 } \
135 (eev)->argv[(eev)->argc].mutex = NULL; \
136 (eev)->argv[(eev)->argc].data.member = (val); \
137 (eev)->argv[(eev)->argc].fn.fnVoid = NULL; \
138 (eev)->argc++; \
139 }
140 #define AG_EVENT_INS_ARG(eev,ap,tname,member,t) { \
141 V = &(eev)->argv[(eev)->argc]; \
142 AG_EVENT_BOUNDARY_CHECK(eev) \
143 V->type = (tname); \
144 V->mutex = NULL; \
145 V->data.member = va_arg(ap,t); \
146 V->fn.fnVoid = NULL; \
147 (eev)->argc++; \
148 }
149 #define AG_EVENT_PUSH_ARG(ap,ev) { \
150 AG_Variable *V; \
151 \
152 switch (*c) { \
153 case 'p': \
154 AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_POINTER,p,void *); \
155 break; \
156 case 'i': \
157 AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_INT,i,int); \
158 break; \
159 case 'u': \
160 AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_UINT,i,int); \
161 break; \
162 case 'f': \
163 AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_FLOAT,flt,double); \
164 break; \
165 case 'd': \
166 AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_DOUBLE,dbl,double);\
167 break; \
168 case 's': \
169 AG_EVENT_INS_ARG((ev),ap,AG_VARIABLE_STRING,s,char *); \
170 break; \
171 case 'l': \
172 switch (c[1]) { \
173 case 'i': \
174 AG_EVENT_INS_ARG((ev),ap, \
175 AG_VARIABLE_SINT32, \
176 s32,long); \
177 break; \
178 case 'u': \
179 AG_EVENT_INS_ARG((ev),ap, \
180 AG_VARIABLE_UINT32, \
181 u32,unsigned long); \
182 break; \
183 default: \
184 AG_FatalError("Bad AG_Event(3) arguments"); \
185 continue; \
186 } \
187 c++; \
188 break; \
189 case 'C': \
190 switch (c[1]) { \
191 case 's': \
192 AG_EVENT_INS_ARG((ev),ap, \
193 AG_VARIABLE_CONST_STRING, \
194 Cs,const char *); \
195 break; \
196 case 'p': \
197 AG_EVENT_INS_ARG((ev),ap, \
198 AG_VARIABLE_CONST_POINTER, \
199 Cp,const void *); \
200 break; \
201 default: \
202 AG_FatalError("Bad AG_Event(3) arguments"); \
203 continue; \
204 } \
205 c++; \
206 break; \
207 case ' ': \
208 case ',': \
209 case '%': \
210 c++; \
211 continue; \
212 default: \
213 AG_FatalError("Bad AG_Event(3) argument: `%c'", *c); \
214 c++; \
215 continue; \
216 } \
217 c++; \
218 if (*c == '(' && c[1] != '\0') { \
219 char *cEnd; \
220 AG_Strlcpy(V->name, &c[1], sizeof(V->name)); \
221 for (cEnd = V->name; *cEnd != '\0'; cEnd++) { \
222 if (*cEnd == ')') { \
223 *cEnd = '\0'; \
224 c+=2; \
225 break; \
226 } \
227 c++; \
228 } \
229 } else { \
230 V->name[0] = '\0'; \
231 } \
232 }
233
234 #define AG_EVENT_GET_ARGS(ev, fmtp) \
235 if (fmtp != NULL) { \
236 const char *c = (const char *)fmtp; \
237 va_list ap; \
238 \
239 va_start(ap, fmtp); \
240 while (*c != '\0') { \
241 AG_EVENT_PUSH_ARG(ap,(ev)); \
242 } \
243 va_end(ap); \
244 }
245
246 __BEGIN_DECLS
247 int AG_InitEventSubsystem(Uint);
248 void AG_DestroyEventSubsystem(void);
249 void AG_EventInit(AG_Event *);
250 void AG_EventArgs(AG_Event *, const char *, ...);
251
252 AG_Event *AG_SetEvent(void *, const char *, AG_EventFn, const char *, ...);
253 AG_Event *AG_AddEvent(void *, const char *, AG_EventFn, const char *, ...);
254
255 AG_Function *AG_SetVoidFn(void *, AG_VoidFn, const char *, ...);
256 AG_Function *AG_SetIntFn(void *, AG_IntFn, const char *, ...);
257 AG_Function *AG_SetUintFn(void *, AG_UintFn, const char *, ...);
258 AG_Function *AG_SetUint8Fn(void *, AG_Uint8Fn, const char *, ...);
259 AG_Function *AG_SetSint8Fn(void *, AG_Sint8Fn, const char *, ...);
260 AG_Function *AG_SetUint16Fn(void *, AG_Uint16Fn, const char *, ...);
261 AG_Function *AG_SetSint16Fn(void *, AG_Sint16Fn, const char *, ...);
262 AG_Function *AG_SetUint32Fn(void *, AG_Uint32Fn, const char *, ...);
263 AG_Function *AG_SetSint32Fn(void *, AG_Sint32Fn, const char *, ...);
264 #ifdef AG_HAVE_64BIT
265 AG_Function *AG_SetUint64Fn(void *, AG_Uint64Fn, const char *, ...);
266 AG_Function *AG_SetSint64Fn(void *, AG_Sint64Fn, const char *, ...);
267 #endif
268 AG_Function *AG_SetFloatFn(void *, AG_FloatFn, const char *, ...);
269 AG_Function *AG_SetDoubleFn(void *, AG_DoubleFn, const char *, ...);
270 #ifdef AG_HAVE_LONG_DOUBLE
271 AG_Function *AG_SetLongDoubleFn(void *, AG_LongDoubleFn, const char *, ...);
272 #endif
273 AG_Function *AG_SetStringFn(void *, AG_StringFn, const char *, ...);
274 AG_Function *AG_SetPointerFn(void *, AG_PointerFn, const char *, ...);
275 AG_Function *AG_SetConstPointerFn(void *, AG_ConstPointerFn, const char *, ...);
276 AG_Function *AG_SetTextFn(void *, AG_TextFn, const char *, ...);
277
278 void AG_UnsetEvent(void *, const char *);
279 void AG_PostEvent(void *, void *, const char *, const char *, ...);
280 void AG_PostEventByPtr(void *, void *, AG_Event *, const char *, ...);
281 AG_Event *AG_FindEventHandler(void *, const char *);
282
283 void AG_InitEventQ(AG_EventQ *);
284 void AG_FreeEventQ(AG_EventQ *);
285 void AG_QueueEvent(AG_EventQ *, const char *, const char *, ...);
286
287 int AG_SchedEvent(void *, void *, Uint32, const char *,
288 const char *, ...);
289 void AG_ForwardEvent(void *, void *, AG_Event *);
290
291 int AG_EventLoop(void);
292 AG_EventSource *AG_GetEventSource(void);
293 AG_EventSink *AG_AddEventPrologue(AG_EventSinkFn, const char *, ...);
294 AG_EventSink *AG_AddEventEpilogue(AG_EventSinkFn, const char *, ...);
295 AG_EventSink *AG_AddEventSpinner(AG_EventSinkFn, const char *, ...);
296 AG_EventSink *AG_AddEventSink(enum ag_event_sink_type, int, Uint,
297 AG_EventSinkFn, const char *, ...);
298 void AG_DelEventPrologue(AG_EventSink *);
299 void AG_DelEventEpilogue(AG_EventSink *);
300 void AG_DelEventSpinner(AG_EventSink *);
301 void AG_DelEventSink(AG_EventSink *);
302 void AG_DelEventSinksByIdent(enum ag_event_sink_type, int, Uint);
303 void AG_Terminate(int);
304 void AG_TerminateEv(AG_Event *);
305
306 int AG_AddTimerKQUEUE(struct ag_timer *, Uint32, int);
307 void AG_DelTimerKQUEUE(struct ag_timer *);
308 int AG_AddTimerTIMERFD(struct ag_timer *, Uint32, int);
309 void AG_DelTimerTIMERFD(struct ag_timer *);
310 int AG_EventSinkKQUEUE(void);
311 int AG_EventSinkTIMERFD(void);
312 int AG_EventSinkTIMEDSELECT(void);
313 int AG_EventSinkSELECT(void);
314 int AG_EventSinkSPINNER(void);
315
316 /* Push arguments onto an Event structure. */
AG_EventPushPointer(AG_Event * ev,const char * key,void * val)317 static __inline__ void AG_EventPushPointer(AG_Event *ev, const char *key, void *val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_POINTER, key, p, val); }
AG_EventPushString(AG_Event * ev,const char * key,char * val)318 static __inline__ void AG_EventPushString(AG_Event *ev, const char *key, char *val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_STRING, key, s, val); }
AG_EventPushInt(AG_Event * ev,const char * key,int val)319 static __inline__ void AG_EventPushInt(AG_Event *ev, const char *key, int val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_INT, key, i, val); }
AG_EventPushUint(AG_Event * ev,const char * key,Uint val)320 static __inline__ void AG_EventPushUint(AG_Event *ev, const char *key, Uint val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_UINT, key, i, (int)val); }
AG_EventPushLong(AG_Event * ev,const char * key,long val)321 static __inline__ void AG_EventPushLong(AG_Event *ev, const char *key, long val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_SINT32, key, s32, (Sint32)val); }
AG_EventPushUlong(AG_Event * ev,const char * key,Ulong val)322 static __inline__ void AG_EventPushUlong(AG_Event *ev, const char *key, Ulong val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_UINT32, key, u32, (Uint32)val); }
AG_EventPushFloat(AG_Event * ev,const char * key,float val)323 static __inline__ void AG_EventPushFloat(AG_Event *ev, const char *key, float val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_FLOAT, key, flt, val); }
AG_EventPushDouble(AG_Event * ev,const char * key,double val)324 static __inline__ void AG_EventPushDouble(AG_Event *ev, const char *key, double val) { AG_EVENT_INS_VAL(ev, AG_VARIABLE_DOUBLE, key, dbl, val); }
AG_EventPopArgument(AG_Event * ev)325 static __inline__ void AG_EventPopArgument(AG_Event *ev) { ev->argc--; }
326
327 /*
328 * Accessor functions for AG_FOO_NAMED() macros.
329 */
330 static __inline__ AG_Variable *
AG_GetNamedEventArg(AG_Event * ev,const char * key)331 AG_GetNamedEventArg(AG_Event *ev, const char *key)
332 {
333 int i;
334
335 for (i = 0; i < ev->argc; i++) {
336 if (strcmp(ev->argv[i].name, key) == 0)
337 return (&ev->argv[i]);
338 }
339 AG_FatalError("No such AG_Event argument: \"%s\"", key);
340 return (NULL);
341 }
342 static __inline__ void *
AG_GetNamedPtr(AG_Event * event,const char * key)343 AG_GetNamedPtr(AG_Event *event, const char *key)
344 {
345 AG_Variable *V = AG_GetNamedEventArg(event, key);
346 return (V->data.p);
347 }
348 static __inline__ char *
AG_GetNamedString(AG_Event * event,const char * key)349 AG_GetNamedString(AG_Event *event, const char *key)
350 {
351 AG_Variable *V = AG_GetNamedEventArg(event, key);
352 return (V->data.s);
353 }
354 static __inline__ int
AG_GetNamedInt(AG_Event * event,const char * key)355 AG_GetNamedInt(AG_Event *event, const char *key)
356 {
357 AG_Variable *V = AG_GetNamedEventArg(event, key);
358 return (V->data.i);
359 }
360 static __inline__ Uint
AG_GetNamedUint(AG_Event * event,const char * key)361 AG_GetNamedUint(AG_Event *event, const char *key)
362 {
363 AG_Variable *V = AG_GetNamedEventArg(event, key);
364 return (V->data.u);
365 }
366 static __inline__ long
AG_GetNamedLong(AG_Event * event,const char * key)367 AG_GetNamedLong(AG_Event *event, const char *key)
368 {
369 AG_Variable *V = AG_GetNamedEventArg(event, key);
370 return ((long)V->data.s32);
371 }
372 static __inline__ Ulong
AG_GetNamedUlong(AG_Event * event,const char * key)373 AG_GetNamedUlong(AG_Event *event, const char *key)
374 {
375 AG_Variable *V = AG_GetNamedEventArg(event, key);
376 return ((Ulong)V->data.u32);
377 }
378 static __inline__ float
AG_GetNamedFlt(AG_Event * event,const char * key)379 AG_GetNamedFlt(AG_Event *event, const char *key)
380 {
381 AG_Variable *V = AG_GetNamedEventArg(event, key);
382 return (V->data.flt);
383 }
384 static __inline__ double
AG_GetNamedDbl(AG_Event * event,const char * key)385 AG_GetNamedDbl(AG_Event *event, const char *key)
386 {
387 AG_Variable *V = AG_GetNamedEventArg(event, key);
388 return (V->data.dbl);
389 }
390
391 #ifdef AG_LEGACY
392 # define AG_EVENT_SCHEDULED 0x04 /* Obsolete since AG_Timer(3) */
393 # define AG_CHAR(v) ((char)event->argv[v].data.i)
394 # define AG_UCHAR(v) ((Uchar)event->argv[v].data.u)
395 # define AG_EventPushChar(ev,key,val) AG_EventPushInt((ev),(key),(int)(val))
396 # define AG_EventPushUchar(ev,key,val) AG_EventPushUint((ev),(key),(Uint)(val))
397 #endif
398 __END_DECLS
399
400 #include <agar/core/close.h>
401