Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 556 lines (443 sloc) 11.357 kb
845e012 auto import from //depot/cupcake/@135843
The Android Open Source Project authored
1 /*
2 * Event loop based on select() loop
3 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
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 version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "eloop.h"
19
20
21 struct eloop_sock {
22 int sock;
23 void *eloop_data;
24 void *user_data;
25 eloop_sock_handler handler;
26 };
27
28 struct eloop_timeout {
29 struct os_time time;
30 void *eloop_data;
31 void *user_data;
32 eloop_timeout_handler handler;
33 struct eloop_timeout *next;
34 };
35
36 struct eloop_signal {
37 int sig;
38 void *user_data;
39 eloop_signal_handler handler;
40 int signaled;
41 };
42
43 struct eloop_sock_table {
44 int count;
45 struct eloop_sock *table;
46 int changed;
47 };
48
49 struct eloop_data {
50 void *user_data;
51
52 int max_sock;
53
54 struct eloop_sock_table readers;
55 struct eloop_sock_table writers;
56 struct eloop_sock_table exceptions;
57
58 struct eloop_timeout *timeout;
59
60 int signal_count;
61 struct eloop_signal *signals;
62 int signaled;
63 int pending_terminate;
64
65 int terminate;
66 int reader_table_changed;
67 };
68
69 static struct eloop_data eloop;
70
71
72 int eloop_init(void *user_data)
73 {
74 os_memset(&eloop, 0, sizeof(eloop));
75 eloop.user_data = user_data;
76 return 0;
77 }
78
79
80 static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
81 int sock, eloop_sock_handler handler,
82 void *eloop_data, void *user_data)
83 {
84 struct eloop_sock *tmp;
85
86 if (table == NULL)
87 return -1;
88
89 tmp = (struct eloop_sock *)
90 os_realloc(table->table,
91 (table->count + 1) * sizeof(struct eloop_sock));
92 if (tmp == NULL)
93 return -1;
94
95 tmp[table->count].sock = sock;
96 tmp[table->count].eloop_data = eloop_data;
97 tmp[table->count].user_data = user_data;
98 tmp[table->count].handler = handler;
99 table->count++;
100 table->table = tmp;
101 if (sock > eloop.max_sock)
102 eloop.max_sock = sock;
103 table->changed = 1;
104
105 return 0;
106 }
107
108
109 static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
110 int sock)
111 {
112 int i;
113
114 if (table == NULL || table->table == NULL || table->count == 0)
115 return;
116
117 for (i = 0; i < table->count; i++) {
118 if (table->table[i].sock == sock)
119 break;
120 }
121 if (i == table->count)
122 return;
123 if (i != table->count - 1) {
124 os_memmove(&table->table[i], &table->table[i + 1],
125 (table->count - i - 1) *
126 sizeof(struct eloop_sock));
127 }
128 table->count--;
129 table->changed = 1;
130 }
131
132
133 static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
134 fd_set *fds)
135 {
136 int i;
137
138 FD_ZERO(fds);
139
140 if (table->table == NULL)
141 return;
142
143 for (i = 0; i < table->count; i++)
144 FD_SET(table->table[i].sock, fds);
145 }
146
147
148 static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
149 fd_set *fds)
150 {
151 int i;
152
153 if (table == NULL || table->table == NULL)
154 return;
155
156 table->changed = 0;
157 for (i = 0; i < table->count; i++) {
158 if (FD_ISSET(table->table[i].sock, fds)) {
159 table->table[i].handler(table->table[i].sock,
160 table->table[i].eloop_data,
161 table->table[i].user_data);
162 if (table->changed)
163 break;
164 }
165 }
166 }
167
168
169 static void eloop_sock_table_destroy(struct eloop_sock_table *table)
170 {
171 if (table)
172 os_free(table->table);
173 }
174
175
176 int eloop_register_read_sock(int sock, eloop_sock_handler handler,
177 void *eloop_data, void *user_data)
178 {
179 return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
180 eloop_data, user_data);
181 }
182
183
184 void eloop_unregister_read_sock(int sock)
185 {
186 eloop_unregister_sock(sock, EVENT_TYPE_READ);
187 }
188
189
190 static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
191 {
192 switch (type) {
193 case EVENT_TYPE_READ:
194 return &eloop.readers;
195 case EVENT_TYPE_WRITE:
196 return &eloop.writers;
197 case EVENT_TYPE_EXCEPTION:
198 return &eloop.exceptions;
199 }
200
201 return NULL;
202 }
203
204
205 int eloop_register_sock(int sock, eloop_event_type type,
206 eloop_sock_handler handler,
207 void *eloop_data, void *user_data)
208 {
209 struct eloop_sock_table *table;
210
211 table = eloop_get_sock_table(type);
212 return eloop_sock_table_add_sock(table, sock, handler,
213 eloop_data, user_data);
214 }
215
216
217 void eloop_unregister_sock(int sock, eloop_event_type type)
218 {
219 struct eloop_sock_table *table;
220
221 table = eloop_get_sock_table(type);
222 eloop_sock_table_remove_sock(table, sock);
223 }
224
225
226 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
227 eloop_timeout_handler handler,
228 void *eloop_data, void *user_data)
229 {
230 struct eloop_timeout *timeout, *tmp, *prev;
231
232 timeout = os_malloc(sizeof(*timeout));
233 if (timeout == NULL)
234 return -1;
dc9507e AI 146505: am: CL 146027 Update wpa_supplicant from 0.5.10 to 0.5.11
Dmitry Shmidt authored
235 if (os_get_time(&timeout->time) < 0) {
236 os_free(timeout);
237 return -1;
238 }
845e012 auto import from //depot/cupcake/@135843
The Android Open Source Project authored
239 timeout->time.sec += secs;
240 timeout->time.usec += usecs;
241 while (timeout->time.usec >= 1000000) {
242 timeout->time.sec++;
243 timeout->time.usec -= 1000000;
244 }
245 timeout->eloop_data = eloop_data;
246 timeout->user_data = user_data;
247 timeout->handler = handler;
248 timeout->next = NULL;
249
250 if (eloop.timeout == NULL) {
251 eloop.timeout = timeout;
252 return 0;
253 }
254
255 prev = NULL;
256 tmp = eloop.timeout;
257 while (tmp != NULL) {
258 if (os_time_before(&timeout->time, &tmp->time))
259 break;
260 prev = tmp;
261 tmp = tmp->next;
262 }
263
264 if (prev == NULL) {
265 timeout->next = eloop.timeout;
266 eloop.timeout = timeout;
267 } else {
268 timeout->next = prev->next;
269 prev->next = timeout;
270 }
271
272 return 0;
273 }
274
275
276 int eloop_cancel_timeout(eloop_timeout_handler handler,
277 void *eloop_data, void *user_data)
278 {
279 struct eloop_timeout *timeout, *prev, *next;
280 int removed = 0;
281
282 prev = NULL;
283 timeout = eloop.timeout;
284 while (timeout != NULL) {
285 next = timeout->next;
286
287 if (timeout->handler == handler &&
288 (timeout->eloop_data == eloop_data ||
289 eloop_data == ELOOP_ALL_CTX) &&
290 (timeout->user_data == user_data ||
291 user_data == ELOOP_ALL_CTX)) {
292 if (prev == NULL)
293 eloop.timeout = next;
294 else
295 prev->next = next;
296 os_free(timeout);
297 removed++;
298 } else
299 prev = timeout;
300
301 timeout = next;
302 }
303
304 return removed;
305 }
306
307
dc9507e AI 146505: am: CL 146027 Update wpa_supplicant from 0.5.10 to 0.5.11
Dmitry Shmidt authored
308 int eloop_is_timeout_registered(eloop_timeout_handler handler,
309 void *eloop_data, void *user_data)
310 {
311 struct eloop_timeout *tmp;
312
313 tmp = eloop.timeout;
314 while (tmp != NULL) {
315 if (tmp->handler == handler &&
316 tmp->eloop_data == eloop_data &&
317 tmp->user_data == user_data)
318 return 1;
319
320 tmp = tmp->next;
321 }
322
323 return 0;
324 }
325
326
845e012 auto import from //depot/cupcake/@135843
The Android Open Source Project authored
327 #ifndef CONFIG_NATIVE_WINDOWS
328 static void eloop_handle_alarm(int sig)
329 {
330 fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
331 "seconds. Looks like there\n"
332 "is a bug that ends up in a busy loop that "
333 "prevents clean shutdown.\n"
334 "Killing program forcefully.\n");
335 exit(1);
336 }
337 #endif /* CONFIG_NATIVE_WINDOWS */
338
339
340 static void eloop_handle_signal(int sig)
341 {
342 int i;
343
344 #ifndef CONFIG_NATIVE_WINDOWS
345 if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
346 /* Use SIGALRM to break out from potential busy loops that
347 * would not allow the program to be killed. */
348 eloop.pending_terminate = 1;
349 signal(SIGALRM, eloop_handle_alarm);
350 alarm(2);
351 }
352 #endif /* CONFIG_NATIVE_WINDOWS */
353
354 eloop.signaled++;
355 for (i = 0; i < eloop.signal_count; i++) {
356 if (eloop.signals[i].sig == sig) {
357 eloop.signals[i].signaled++;
358 break;
359 }
360 }
361 }
362
363
364 static void eloop_process_pending_signals(void)
365 {
366 int i;
367
368 if (eloop.signaled == 0)
369 return;
370 eloop.signaled = 0;
371
372 if (eloop.pending_terminate) {
373 #ifndef CONFIG_NATIVE_WINDOWS
374 alarm(0);
375 #endif /* CONFIG_NATIVE_WINDOWS */
376 eloop.pending_terminate = 0;
377 }
378
379 for (i = 0; i < eloop.signal_count; i++) {
380 if (eloop.signals[i].signaled) {
381 eloop.signals[i].signaled = 0;
382 eloop.signals[i].handler(eloop.signals[i].sig,
383 eloop.user_data,
384 eloop.signals[i].user_data);
385 }
386 }
387 }
388
389
390 int eloop_register_signal(int sig, eloop_signal_handler handler,
391 void *user_data)
392 {
393 struct eloop_signal *tmp;
394
395 tmp = (struct eloop_signal *)
396 os_realloc(eloop.signals,
397 (eloop.signal_count + 1) *
398 sizeof(struct eloop_signal));
399 if (tmp == NULL)
400 return -1;
401
402 tmp[eloop.signal_count].sig = sig;
403 tmp[eloop.signal_count].user_data = user_data;
404 tmp[eloop.signal_count].handler = handler;
405 tmp[eloop.signal_count].signaled = 0;
406 eloop.signal_count++;
407 eloop.signals = tmp;
408 signal(sig, eloop_handle_signal);
409
410 return 0;
411 }
412
413
414 int eloop_register_signal_terminate(eloop_signal_handler handler,
415 void *user_data)
416 {
417 int ret = eloop_register_signal(SIGINT, handler, user_data);
418 if (ret == 0)
419 ret = eloop_register_signal(SIGTERM, handler, user_data);
619ec14 Add SIGSEGV processing to send terminating message
Dmitry Shmidt authored
420 if (ret == 0)
421 ret = eloop_register_signal(SIGSEGV, handler, user_data);
845e012 auto import from //depot/cupcake/@135843
The Android Open Source Project authored
422 return ret;
423 }
424
425
426 int eloop_register_signal_reconfig(eloop_signal_handler handler,
427 void *user_data)
428 {
429 #ifdef CONFIG_NATIVE_WINDOWS
430 return 0;
431 #else /* CONFIG_NATIVE_WINDOWS */
432 return eloop_register_signal(SIGHUP, handler, user_data);
433 #endif /* CONFIG_NATIVE_WINDOWS */
434 }
435
436
437 void eloop_run(void)
438 {
439 fd_set *rfds, *wfds, *efds;
440 int res;
441 struct timeval _tv;
442 struct os_time tv, now;
443
444 rfds = os_malloc(sizeof(*rfds));
445 wfds = os_malloc(sizeof(*wfds));
446 efds = os_malloc(sizeof(*efds));
447 if (rfds == NULL || wfds == NULL || efds == NULL) {
448 printf("eloop_run - malloc failed\n");
449 goto out;
450 }
451
452 while (!eloop.terminate &&
453 (eloop.timeout || eloop.readers.count > 0 ||
454 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
455 if (eloop.timeout) {
456 os_get_time(&now);
457 if (os_time_before(&now, &eloop.timeout->time))
458 os_time_sub(&eloop.timeout->time, &now, &tv);
459 else
460 tv.sec = tv.usec = 0;
461 #if 0
462 printf("next timeout in %lu.%06lu sec\n",
463 tv.sec, tv.usec);
464 #endif
465 _tv.tv_sec = tv.sec;
466 _tv.tv_usec = tv.usec;
467 }
468
469 eloop_sock_table_set_fds(&eloop.readers, rfds);
470 eloop_sock_table_set_fds(&eloop.writers, wfds);
471 eloop_sock_table_set_fds(&eloop.exceptions, efds);
472 res = select(eloop.max_sock + 1, rfds, wfds, efds,
473 eloop.timeout ? &_tv : NULL);
474 if (res < 0 && errno != EINTR && errno != 0) {
475 perror("select");
476 goto out;
477 }
478 eloop_process_pending_signals();
479
480 /* check if some registered timeouts have occurred */
481 if (eloop.timeout) {
482 struct eloop_timeout *tmp;
483
484 os_get_time(&now);
485 if (!os_time_before(&now, &eloop.timeout->time)) {
486 tmp = eloop.timeout;
487 eloop.timeout = eloop.timeout->next;
488 tmp->handler(tmp->eloop_data,
489 tmp->user_data);
490 os_free(tmp);
491 }
492
493 }
494
495 if (res <= 0)
496 continue;
497
498 eloop_sock_table_dispatch(&eloop.readers, rfds);
499 eloop_sock_table_dispatch(&eloop.writers, wfds);
500 eloop_sock_table_dispatch(&eloop.exceptions, efds);
501 }
502
503 out:
504 os_free(rfds);
505 os_free(wfds);
506 os_free(efds);
507 }
508
509
510 void eloop_terminate(void)
511 {
512 eloop.terminate = 1;
513 }
514
515
516 void eloop_destroy(void)
517 {
518 struct eloop_timeout *timeout, *prev;
519
520 timeout = eloop.timeout;
521 while (timeout != NULL) {
522 prev = timeout;
523 timeout = timeout->next;
524 os_free(prev);
525 }
526 eloop_sock_table_destroy(&eloop.readers);
527 eloop_sock_table_destroy(&eloop.writers);
528 eloop_sock_table_destroy(&eloop.exceptions);
529 os_free(eloop.signals);
530 }
531
532
533 int eloop_terminated(void)
534 {
535 return eloop.terminate;
536 }
537
538
539 void eloop_wait_for_read_sock(int sock)
540 {
541 fd_set rfds;
542
543 if (sock < 0)
544 return;
545
546 FD_ZERO(&rfds);
547 FD_SET(sock, &rfds);
548 select(sock + 1, &rfds, NULL, NULL, NULL);
549 }
550
551
552 void * eloop_get_user_data(void)
553 {
554 return eloop.user_data;
555 }
Something went wrong with that request. Please try again.