2 * Event loop for AmigaOS/MorphOS/AROS
3 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2010-2011, Neil Cafferkey
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
21 #include <exec/types.h>
23 #include <exec/memory.h>
25 #include <devices/timer.h>
27 #include <proto/exec.h>
28 #include <proto/timer.h>
35 void (*handler
)(int sock
, void *eloop_ctx
, void *sock_ctx
);
38 struct eloop_timeout
{
42 void (*handler
)(void *eloop_ctx
, void *sock_ctx
);
43 struct eloop_timeout
*next
;
49 void (*handler
)(int sig
, void *signal_ctx
);
56 int max_sock
, reader_count
;
57 struct eloop_sock
*readers
;
59 struct eloop_timeout
*timeout
;
62 struct eloop_signal
*signals
;
64 int pending_terminate
;
67 int reader_table_changed
;
69 struct MsgPort
*timer_port
;
70 struct timerequest
*timer_request
;
73 static struct eloop_data eloop
;
80 memset(&eloop
, 0, sizeof(eloop
));
82 /* Open timer device */
86 eloop
.timer_port
= CreateMsgPort();
87 eloop
.timer_request
= (APTR
)CreateIORequest(eloop
.timer_port
,
88 sizeof(struct timerequest
));
89 if(eloop
.timer_request
== NULL
)
95 if(OpenDevice((CONST_STRPTR
)"timer.device", UNIT_VBLANK
,
96 (APTR
)eloop
.timer_request
, 0) != 0) {
98 DeleteIORequest((APTR
)eloop
.timer_request
);
99 eloop
.timer_request
= NULL
;
101 eloop
.timer_request
->tr_node
.io_Message
.mn_Node
.ln_Type
105 /* Use request at least once to make shutdown easier */
109 eloop
.timer_request
->tr_node
.io_Command
=
111 eloop
.timer_request
->tr_time
.tv_secs
= 0;
112 eloop
.timer_request
->tr_time
.tv_micro
= 0;
113 DoIO((APTR
) eloop
.timer_request
);
120 int eloop_register_read_sock(int sock
,
121 void (*handler
)(int sock
, void *eloop_ctx
,
123 void *eloop_data
, void *user_data
)
125 struct eloop_sock
*tmp
;
127 tmp
= (struct eloop_sock
*)
128 realloc(eloop
.readers
,
129 (eloop
.reader_count
+ 1) * sizeof(struct eloop_sock
));
133 tmp
[eloop
.reader_count
].sock
= sock
;
134 tmp
[eloop
.reader_count
].eloop_data
= eloop_data
;
135 tmp
[eloop
.reader_count
].user_data
= user_data
;
136 tmp
[eloop
.reader_count
].handler
= handler
;
137 eloop
.reader_count
++;
139 if (sock
> eloop
.max_sock
)
140 eloop
.max_sock
= sock
;
141 eloop
.reader_table_changed
= 1;
147 void eloop_unregister_read_sock(int sock
)
151 if (eloop
.readers
== NULL
|| eloop
.reader_count
== 0)
154 for (i
= 0; i
< eloop
.reader_count
; i
++) {
155 if (eloop
.readers
[i
].sock
== sock
)
158 if (i
== eloop
.reader_count
)
160 if (i
!= eloop
.reader_count
- 1) {
161 memmove(&eloop
.readers
[i
], &eloop
.readers
[i
+ 1],
162 (eloop
.reader_count
- i
- 1) *
163 sizeof(struct eloop_sock
));
165 eloop
.reader_count
--;
166 eloop
.reader_table_changed
= 1;
170 int eloop_register_timeout(unsigned int secs
, unsigned int usecs
,
171 void (*handler
)(void *eloop_ctx
, void *timeout_ctx
),
172 void *eloop_data
, void *user_data
)
174 struct eloop_timeout
*timeout
, *tmp
, *prev
;
176 timeout
= (struct eloop_timeout
*) malloc(sizeof(*timeout
));
179 os_get_time(&timeout
->time
);
180 timeout
->time
.sec
+= secs
;
181 timeout
->time
.usec
+= usecs
;
182 while (timeout
->time
.usec
>= 1000000) {
184 timeout
->time
.usec
-= 1000000;
186 timeout
->eloop_data
= eloop_data
;
187 timeout
->user_data
= user_data
;
188 timeout
->handler
= handler
;
189 timeout
->next
= NULL
;
191 if (eloop
.timeout
== NULL
) {
192 eloop
.timeout
= timeout
;
198 while (tmp
!= NULL
) {
199 if (os_time_before(&timeout
->time
, &tmp
->time
))
206 timeout
->next
= eloop
.timeout
;
207 eloop
.timeout
= timeout
;
209 timeout
->next
= prev
->next
;
210 prev
->next
= timeout
;
217 int eloop_cancel_timeout(void (*handler
)(void *eloop_ctx
, void *sock_ctx
),
218 void *eloop_data
, void *user_data
)
220 struct eloop_timeout
*timeout
, *prev
, *next
;
224 timeout
= eloop
.timeout
;
225 while (timeout
!= NULL
) {
226 next
= timeout
->next
;
228 if (timeout
->handler
== handler
&&
229 (timeout
->eloop_data
== eloop_data
||
230 eloop_data
== ELOOP_ALL_CTX
) &&
231 (timeout
->user_data
== user_data
||
232 user_data
== ELOOP_ALL_CTX
)) {
234 eloop
.timeout
= next
;
249 int eloop_is_timeout_registered(void (*handler
)(void *eloop_ctx
,
251 void *eloop_data
, void *user_data
)
253 struct eloop_timeout
*tmp
;
256 while (tmp
!= NULL
) {
257 if (tmp
->handler
== handler
&&
258 tmp
->eloop_data
== eloop_data
&&
259 tmp
->user_data
== user_data
)
269 static void eloop_handle_signals(u32 sigs
)
274 for (i
= 0; i
< eloop
.signal_count
; i
++) {
275 if (1 << eloop
.signals
[i
].sig
& sigs
) {
276 eloop
.signals
[i
].signaled
++;
282 static void eloop_process_pending_signals(void)
286 if (eloop
.signaled
== 0)
290 if (eloop
.pending_terminate
) {
291 eloop
.pending_terminate
= 0;
294 for (i
= 0; i
< eloop
.signal_count
; i
++) {
295 if (eloop
.signals
[i
].signaled
) {
296 eloop
.signals
[i
].signaled
= 0;
297 eloop
.signals
[i
].handler(eloop
.signals
[i
].sig
,
298 eloop
.signals
[i
].user_data
);
304 int eloop_register_signal(int sig
,
305 void (*handler
)(int sig
, void *signal_ctx
),
308 struct eloop_signal
*tmp
;
310 tmp
= (struct eloop_signal
*)
311 realloc(eloop
.signals
,
312 (eloop
.signal_count
+ 1) *
313 sizeof(struct eloop_signal
));
317 tmp
[eloop
.signal_count
].sig
= sig
;
318 tmp
[eloop
.signal_count
].user_data
= user_data
;
319 tmp
[eloop
.signal_count
].handler
= handler
;
320 tmp
[eloop
.signal_count
].signaled
= 0;
321 eloop
.signal_count
++;
328 int eloop_register_signal_terminate(eloop_signal_handler handler
,
331 return eloop_register_signal(SIGBREAKB_CTRL_C
, handler
, user_data
);
335 int eloop_register_signal_reconfig(eloop_signal_handler handler
,
339 /* TODO: for example */
340 return eloop_register_signal(SIGHUP
, handler
, user_data
);
349 struct os_time tv
, now
;
351 struct timerequest
*cur_timer_req
= NULL
;
353 while (!eloop
.terminate
) {
356 if (eloop
.timeout
&& cur_timer_req
== NULL
) {
357 /* Send a timer request for the next timeout
358 * (even if it's already occurred) */
360 if (os_time_before(&now
, &eloop
.timeout
->time
))
361 os_time_sub(&eloop
.timeout
->time
, &now
, &tv
);
363 tv
.sec
= tv
.usec
= 0;
364 eloop
.timer_request
->tr_node
.io_Command
=
366 eloop
.timer_request
->tr_time
.tv_secs
=
368 eloop
.timer_request
->tr_time
.tv_micro
=
370 SendIO((APTR
) eloop
.timer_request
);
371 cur_timer_req
= eloop
.timer_request
;
374 sig_mask
|= 1 << eloop
.timer_port
->mp_SigBit
;
378 /* Add registered signals to signal mask */
379 for (i
= 0; i
< eloop
.signal_count
; i
++)
380 sig_mask
|= 1 << eloop
.signals
[i
].sig
;
382 /* Wait for something to happen */
383 sigs
= Wait(sig_mask
);
384 eloop_handle_signals(sigs
);
385 eloop_process_pending_signals();
387 /* Check if some registered timeouts have occurred */
389 struct eloop_timeout
*tmp
;
392 if (sigs
& 1 << eloop
.timer_port
->mp_SigBit
) {
394 eloop
.timeout
= eloop
.timeout
->next
;
395 tmp
->handler(tmp
->eloop_data
,
399 WaitIO((APTR
) eloop
.timer_request
);
400 cur_timer_req
= NULL
;
408 void eloop_terminate(void)
414 void eloop_destroy(void)
416 struct eloop_timeout
*timeout
, *prev
;
418 timeout
= eloop
.timeout
;
419 while (timeout
!= NULL
) {
421 timeout
= timeout
->next
;
426 if(eloop
.timer_request
!= NULL
) {
427 AbortIO((APTR
) eloop
.timer_request
);
428 WaitIO((APTR
) eloop
.timer_request
);
429 CloseDevice((APTR
) eloop
.timer_request
);
431 DeleteIORequest((APTR
) eloop
.timer_request
);
432 DeleteMsgPort(eloop
.timer_port
);
436 int eloop_terminated(void)
438 return eloop
.terminate
;