2 * Event loop based on select() loop
3 * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include <sys/types.h>
24 #ifdef CONFIG_NATIVE_WINDOWS
26 #endif /* CONFIG_NATIVE_WINDOWS */
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 *eloop_ctx
, 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
;
70 static struct eloop_data eloop
;
73 void eloop_init(void *user_data
)
75 memset(&eloop
, 0, sizeof(eloop
));
76 eloop
.user_data
= user_data
;
80 int eloop_register_read_sock(int sock
,
81 void (*handler
)(int sock
, void *eloop_ctx
,
83 void *eloop_data
, void *user_data
)
85 struct eloop_sock
*tmp
;
87 tmp
= (struct eloop_sock
*)
88 realloc(eloop
.readers
,
89 (eloop
.reader_count
+ 1) * sizeof(struct eloop_sock
));
93 tmp
[eloop
.reader_count
].sock
= sock
;
94 tmp
[eloop
.reader_count
].eloop_data
= eloop_data
;
95 tmp
[eloop
.reader_count
].user_data
= user_data
;
96 tmp
[eloop
.reader_count
].handler
= handler
;
99 if (sock
> eloop
.max_sock
)
100 eloop
.max_sock
= sock
;
101 eloop
.reader_table_changed
= 1;
107 void eloop_unregister_read_sock(int sock
)
111 if (eloop
.readers
== NULL
|| eloop
.reader_count
== 0)
114 for (i
= 0; i
< eloop
.reader_count
; i
++) {
115 if (eloop
.readers
[i
].sock
== sock
)
118 if (i
== eloop
.reader_count
)
120 if (i
!= eloop
.reader_count
- 1) {
121 memmove(&eloop
.readers
[i
], &eloop
.readers
[i
+ 1],
122 (eloop
.reader_count
- i
- 1) *
123 sizeof(struct eloop_sock
));
125 eloop
.reader_count
--;
126 eloop
.reader_table_changed
= 1;
130 int eloop_register_timeout(unsigned int secs
, unsigned int usecs
,
131 void (*handler
)(void *eloop_ctx
, void *timeout_ctx
),
132 void *eloop_data
, void *user_data
)
134 struct eloop_timeout
*timeout
, *tmp
, *prev
;
136 timeout
= (struct eloop_timeout
*) malloc(sizeof(*timeout
));
139 gettimeofday(&timeout
->time
, NULL
);
140 timeout
->time
.tv_sec
+= secs
;
141 timeout
->time
.tv_usec
+= usecs
;
142 while (timeout
->time
.tv_usec
>= 1000000) {
143 timeout
->time
.tv_sec
++;
144 timeout
->time
.tv_usec
-= 1000000;
146 timeout
->eloop_data
= eloop_data
;
147 timeout
->user_data
= user_data
;
148 timeout
->handler
= handler
;
149 timeout
->next
= NULL
;
151 if (eloop
.timeout
== NULL
) {
152 eloop
.timeout
= timeout
;
158 while (tmp
!= NULL
) {
159 if (timercmp(&timeout
->time
, &tmp
->time
, <))
166 timeout
->next
= eloop
.timeout
;
167 eloop
.timeout
= timeout
;
169 timeout
->next
= prev
->next
;
170 prev
->next
= timeout
;
177 int eloop_cancel_timeout(void (*handler
)(void *eloop_ctx
, void *sock_ctx
),
178 void *eloop_data
, void *user_data
)
180 struct eloop_timeout
*timeout
, *prev
, *next
;
184 timeout
= eloop
.timeout
;
185 while (timeout
!= NULL
) {
186 next
= timeout
->next
;
188 if (timeout
->handler
== handler
&&
189 (timeout
->eloop_data
== eloop_data
||
190 eloop_data
== ELOOP_ALL_CTX
) &&
191 (timeout
->user_data
== user_data
||
192 user_data
== ELOOP_ALL_CTX
)) {
194 eloop
.timeout
= next
;
209 #ifndef CONFIG_NATIVE_WINDOWS
210 static void eloop_handle_alarm(int sig
)
212 fprintf(stderr
, "eloop: could not process SIGINT or SIGTERM in two "
213 "seconds. Looks like there\n"
214 "is a bug that ends up in a busy loop that "
215 "prevents clean shutdown.\n"
216 "Killing program forcefully.\n");
219 #endif /* CONFIG_NATIVE_WINDOWS */
222 static void eloop_handle_signal(int sig
)
226 #ifndef CONFIG_NATIVE_WINDOWS
227 if ((sig
== SIGINT
|| sig
== SIGTERM
) && !eloop
.pending_terminate
) {
228 /* Use SIGALRM to break out from potential busy loops that
229 * would not allow the program to be killed. */
230 eloop
.pending_terminate
= 1;
231 signal(SIGALRM
, eloop_handle_alarm
);
234 #endif /* CONFIG_NATIVE_WINDOWS */
237 for (i
= 0; i
< eloop
.signal_count
; i
++) {
238 if (eloop
.signals
[i
].sig
== sig
) {
239 eloop
.signals
[i
].signaled
++;
246 static void eloop_process_pending_signals(void)
250 if (eloop
.signaled
== 0)
254 if (eloop
.pending_terminate
) {
255 #ifndef CONFIG_NATIVE_WINDOWS
257 #endif /* CONFIG_NATIVE_WINDOWS */
258 eloop
.pending_terminate
= 0;
261 for (i
= 0; i
< eloop
.signal_count
; i
++) {
262 if (eloop
.signals
[i
].signaled
) {
263 eloop
.signals
[i
].signaled
= 0;
264 eloop
.signals
[i
].handler(eloop
.signals
[i
].sig
,
266 eloop
.signals
[i
].user_data
);
272 int eloop_register_signal(int sig
,
273 void (*handler
)(int sig
, void *eloop_ctx
,
277 struct eloop_signal
*tmp
;
279 tmp
= (struct eloop_signal
*)
280 realloc(eloop
.signals
,
281 (eloop
.signal_count
+ 1) *
282 sizeof(struct eloop_signal
));
286 tmp
[eloop
.signal_count
].sig
= sig
;
287 tmp
[eloop
.signal_count
].user_data
= user_data
;
288 tmp
[eloop
.signal_count
].handler
= handler
;
289 tmp
[eloop
.signal_count
].signaled
= 0;
290 eloop
.signal_count
++;
292 signal(sig
, eloop_handle_signal
);
302 struct timeval tv
, now
;
304 rfds
= malloc(sizeof(*rfds
));
306 printf("eloop_run - malloc failed\n");
310 while (!eloop
.terminate
&&
311 (eloop
.timeout
|| eloop
.reader_count
> 0)) {
313 gettimeofday(&now
, NULL
);
314 if (timercmp(&now
, &eloop
.timeout
->time
, <))
315 timersub(&eloop
.timeout
->time
, &now
, &tv
);
317 tv
.tv_sec
= tv
.tv_usec
= 0;
319 printf("next timeout in %lu.%06lu sec\n",
320 tv
.tv_sec
, tv
.tv_usec
);
325 for (i
= 0; i
< eloop
.reader_count
; i
++)
326 FD_SET(eloop
.readers
[i
].sock
, rfds
);
327 res
= select(eloop
.max_sock
+ 1, rfds
, NULL
, NULL
,
328 eloop
.timeout
? &tv
: NULL
);
329 if (res
< 0 && errno
!= EINTR
) {
334 eloop_process_pending_signals();
336 /* check if some registered timeouts have occurred */
338 struct eloop_timeout
*tmp
;
340 gettimeofday(&now
, NULL
);
341 if (!timercmp(&now
, &eloop
.timeout
->time
, <)) {
343 eloop
.timeout
= eloop
.timeout
->next
;
344 tmp
->handler(tmp
->eloop_data
,
354 eloop
.reader_table_changed
= 0;
355 for (i
= 0; i
< eloop
.reader_count
; i
++) {
356 if (FD_ISSET(eloop
.readers
[i
].sock
, rfds
)) {
357 eloop
.readers
[i
].handler(
358 eloop
.readers
[i
].sock
,
359 eloop
.readers
[i
].eloop_data
,
360 eloop
.readers
[i
].user_data
);
361 if (eloop
.reader_table_changed
)
371 void eloop_terminate(void)
377 void eloop_destroy(void)
379 struct eloop_timeout
*timeout
, *prev
;
381 timeout
= eloop
.timeout
;
382 while (timeout
!= NULL
) {
384 timeout
= timeout
->next
;
392 int eloop_terminated(void)
394 return eloop
.terminate
;