Branch data Line data Source code
1 : : /*
2 : : * Event loop based on select() loop
3 : : * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "trace.h"
13 : : #include "list.h"
14 : : #include "eloop.h"
15 : :
16 : : #ifdef CONFIG_ELOOP_POLL
17 : : #include <assert.h>
18 : : #include <poll.h>
19 : : #endif /* CONFIG_ELOOP_POLL */
20 : :
21 : :
22 : : struct eloop_sock {
23 : : int sock;
24 : : void *eloop_data;
25 : : void *user_data;
26 : : eloop_sock_handler handler;
27 : : WPA_TRACE_REF(eloop);
28 : : WPA_TRACE_REF(user);
29 : : WPA_TRACE_INFO
30 : : };
31 : :
32 : : struct eloop_timeout {
33 : : struct dl_list list;
34 : : struct os_reltime time;
35 : : void *eloop_data;
36 : : void *user_data;
37 : : eloop_timeout_handler handler;
38 : : WPA_TRACE_REF(eloop);
39 : : WPA_TRACE_REF(user);
40 : : WPA_TRACE_INFO
41 : : };
42 : :
43 : : struct eloop_signal {
44 : : int sig;
45 : : void *user_data;
46 : : eloop_signal_handler handler;
47 : : int signaled;
48 : : };
49 : :
50 : : struct eloop_sock_table {
51 : : int count;
52 : : struct eloop_sock *table;
53 : : int changed;
54 : : };
55 : :
56 : : struct eloop_data {
57 : : int max_sock;
58 : :
59 : : int count; /* sum of all table counts */
60 : : #ifdef CONFIG_ELOOP_POLL
61 : : int max_pollfd_map; /* number of pollfds_map currently allocated */
62 : : int max_poll_fds; /* number of pollfds currently allocated */
63 : : struct pollfd *pollfds;
64 : : struct pollfd **pollfds_map;
65 : : #endif /* CONFIG_ELOOP_POLL */
66 : : struct eloop_sock_table readers;
67 : : struct eloop_sock_table writers;
68 : : struct eloop_sock_table exceptions;
69 : :
70 : : struct dl_list timeout;
71 : :
72 : : int signal_count;
73 : : struct eloop_signal *signals;
74 : : int signaled;
75 : : int pending_terminate;
76 : :
77 : : int terminate;
78 : : int reader_table_changed;
79 : : };
80 : :
81 : : static struct eloop_data eloop;
82 : :
83 : :
84 : : #ifdef WPA_TRACE
85 : :
86 : 0 : static void eloop_sigsegv_handler(int sig)
87 : : {
88 : 0 : wpa_trace_show("eloop SIGSEGV");
89 : 0 : abort();
90 : : }
91 : :
92 : 3104 : static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
93 : : {
94 : : int i;
95 [ + - ][ - + ]: 3104 : if (table == NULL || table->table == NULL)
96 : 3104 : return;
97 [ + + ]: 29162 : for (i = 0; i < table->count; i++) {
98 : 26058 : wpa_trace_add_ref(&table->table[i], eloop,
99 : : table->table[i].eloop_data);
100 : 26058 : wpa_trace_add_ref(&table->table[i], user,
101 : : table->table[i].user_data);
102 : : }
103 : : }
104 : :
105 : :
106 : 3104 : static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
107 : : {
108 : : int i;
109 [ + - ][ + + ]: 3104 : if (table == NULL || table->table == NULL)
110 : 3104 : return;
111 [ + + ]: 29160 : for (i = 0; i < table->count; i++) {
112 [ + + ]: 26058 : wpa_trace_remove_ref(&table->table[i], eloop,
113 : : table->table[i].eloop_data);
114 [ + + ]: 26058 : wpa_trace_remove_ref(&table->table[i], user,
115 : : table->table[i].user_data);
116 : : }
117 : : }
118 : :
119 : : #else /* WPA_TRACE */
120 : :
121 : : #define eloop_trace_sock_add_ref(table) do { } while (0)
122 : : #define eloop_trace_sock_remove_ref(table) do { } while (0)
123 : :
124 : : #endif /* WPA_TRACE */
125 : :
126 : :
127 : 1 : int eloop_init(void)
128 : : {
129 : 1 : os_memset(&eloop, 0, sizeof(eloop));
130 : 1 : dl_list_init(&eloop.timeout);
131 : : #ifdef WPA_TRACE
132 : 1 : signal(SIGSEGV, eloop_sigsegv_handler);
133 : : #endif /* WPA_TRACE */
134 : 1 : return 0;
135 : : }
136 : :
137 : :
138 : 1552 : static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
139 : : int sock, eloop_sock_handler handler,
140 : : void *eloop_data, void *user_data)
141 : : {
142 : : struct eloop_sock *tmp;
143 : : int new_max_sock;
144 : :
145 [ + + ]: 1552 : if (sock > eloop.max_sock)
146 : 138 : new_max_sock = sock;
147 : : else
148 : 1414 : new_max_sock = eloop.max_sock;
149 : :
150 [ - + ]: 1552 : if (table == NULL)
151 : 0 : return -1;
152 : :
153 : : #ifdef CONFIG_ELOOP_POLL
154 : : if (new_max_sock >= eloop.max_pollfd_map) {
155 : : struct pollfd **nmap;
156 : : nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
157 : : sizeof(struct pollfd *));
158 : : if (nmap == NULL)
159 : : return -1;
160 : :
161 : : eloop.max_pollfd_map = new_max_sock + 50;
162 : : eloop.pollfds_map = nmap;
163 : : }
164 : :
165 : : if (eloop.count + 1 > eloop.max_poll_fds) {
166 : : struct pollfd *n;
167 : : int nmax = eloop.count + 1 + 50;
168 : : n = os_realloc_array(eloop.pollfds, nmax,
169 : : sizeof(struct pollfd));
170 : : if (n == NULL)
171 : : return -1;
172 : :
173 : : eloop.max_poll_fds = nmax;
174 : : eloop.pollfds = n;
175 : : }
176 : : #endif /* CONFIG_ELOOP_POLL */
177 : :
178 : 1552 : eloop_trace_sock_remove_ref(table);
179 : 1552 : tmp = os_realloc_array(table->table, table->count + 1,
180 : : sizeof(struct eloop_sock));
181 [ - + ]: 1552 : if (tmp == NULL)
182 : 0 : return -1;
183 : :
184 : 1552 : tmp[table->count].sock = sock;
185 : 1552 : tmp[table->count].eloop_data = eloop_data;
186 : 1552 : tmp[table->count].user_data = user_data;
187 : 1552 : tmp[table->count].handler = handler;
188 : 1552 : wpa_trace_record(&tmp[table->count]);
189 : 1552 : table->count++;
190 : 1552 : table->table = tmp;
191 : 1552 : eloop.max_sock = new_max_sock;
192 : 1552 : eloop.count++;
193 : 1552 : table->changed = 1;
194 : 1552 : eloop_trace_sock_add_ref(table);
195 : :
196 : 1552 : return 0;
197 : : }
198 : :
199 : :
200 : 1568 : static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
201 : : int sock)
202 : : {
203 : : int i;
204 : :
205 [ + - ][ + - ]: 1568 : if (table == NULL || table->table == NULL || table->count == 0)
[ + + ]
206 : 16 : return;
207 : :
208 [ + - ]: 10625 : for (i = 0; i < table->count; i++) {
209 [ + + ]: 10625 : if (table->table[i].sock == sock)
210 : 1552 : break;
211 : : }
212 [ - + ]: 1552 : if (i == table->count)
213 : 0 : return;
214 : 1552 : eloop_trace_sock_remove_ref(table);
215 [ + + ]: 1552 : if (i != table->count - 1) {
216 : 800 : os_memmove(&table->table[i], &table->table[i + 1],
217 : : (table->count - i - 1) *
218 : : sizeof(struct eloop_sock));
219 : : }
220 : 1552 : table->count--;
221 : 1552 : eloop.count--;
222 : 1552 : table->changed = 1;
223 : 1568 : eloop_trace_sock_add_ref(table);
224 : : }
225 : :
226 : :
227 : : #ifdef CONFIG_ELOOP_POLL
228 : :
229 : : static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
230 : : {
231 : : if (fd < mx && fd >= 0)
232 : : return pollfds_map[fd];
233 : : return NULL;
234 : : }
235 : :
236 : :
237 : : static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
238 : : struct eloop_sock_table *writers,
239 : : struct eloop_sock_table *exceptions,
240 : : struct pollfd *pollfds,
241 : : struct pollfd **pollfds_map,
242 : : int max_pollfd_map)
243 : : {
244 : : int i;
245 : : int nxt = 0;
246 : : int fd;
247 : : struct pollfd *pfd;
248 : :
249 : : /* Clear pollfd lookup map. It will be re-populated below. */
250 : : os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
251 : :
252 : : if (readers && readers->table) {
253 : : for (i = 0; i < readers->count; i++) {
254 : : fd = readers->table[i].sock;
255 : : assert(fd >= 0 && fd < max_pollfd_map);
256 : : pollfds[nxt].fd = fd;
257 : : pollfds[nxt].events = POLLIN;
258 : : pollfds[nxt].revents = 0;
259 : : pollfds_map[fd] = &(pollfds[nxt]);
260 : : nxt++;
261 : : }
262 : : }
263 : :
264 : : if (writers && writers->table) {
265 : : for (i = 0; i < writers->count; i++) {
266 : : /*
267 : : * See if we already added this descriptor, update it
268 : : * if so.
269 : : */
270 : : fd = writers->table[i].sock;
271 : : assert(fd >= 0 && fd < max_pollfd_map);
272 : : pfd = pollfds_map[fd];
273 : : if (!pfd) {
274 : : pfd = &(pollfds[nxt]);
275 : : pfd->events = 0;
276 : : pfd->fd = fd;
277 : : pollfds[i].revents = 0;
278 : : pollfds_map[fd] = pfd;
279 : : nxt++;
280 : : }
281 : : pfd->events |= POLLOUT;
282 : : }
283 : : }
284 : :
285 : : /*
286 : : * Exceptions are always checked when using poll, but I suppose it's
287 : : * possible that someone registered a socket *only* for exception
288 : : * handling. Set the POLLIN bit in this case.
289 : : */
290 : : if (exceptions && exceptions->table) {
291 : : for (i = 0; i < exceptions->count; i++) {
292 : : /*
293 : : * See if we already added this descriptor, just use it
294 : : * if so.
295 : : */
296 : : fd = exceptions->table[i].sock;
297 : : assert(fd >= 0 && fd < max_pollfd_map);
298 : : pfd = pollfds_map[fd];
299 : : if (!pfd) {
300 : : pfd = &(pollfds[nxt]);
301 : : pfd->events = POLLIN;
302 : : pfd->fd = fd;
303 : : pollfds[i].revents = 0;
304 : : pollfds_map[fd] = pfd;
305 : : nxt++;
306 : : }
307 : : }
308 : : }
309 : :
310 : : return nxt;
311 : : }
312 : :
313 : :
314 : : static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
315 : : struct pollfd **pollfds_map,
316 : : int max_pollfd_map,
317 : : short int revents)
318 : : {
319 : : int i;
320 : : struct pollfd *pfd;
321 : :
322 : : if (!table || !table->table)
323 : : return 0;
324 : :
325 : : table->changed = 0;
326 : : for (i = 0; i < table->count; i++) {
327 : : pfd = find_pollfd(pollfds_map, table->table[i].sock,
328 : : max_pollfd_map);
329 : : if (!pfd)
330 : : continue;
331 : :
332 : : if (!(pfd->revents & revents))
333 : : continue;
334 : :
335 : : table->table[i].handler(table->table[i].sock,
336 : : table->table[i].eloop_data,
337 : : table->table[i].user_data);
338 : : if (table->changed)
339 : : return 1;
340 : : }
341 : :
342 : : return 0;
343 : : }
344 : :
345 : :
346 : : static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
347 : : struct eloop_sock_table *writers,
348 : : struct eloop_sock_table *exceptions,
349 : : struct pollfd **pollfds_map,
350 : : int max_pollfd_map)
351 : : {
352 : : if (eloop_sock_table_dispatch_table(readers, pollfds_map,
353 : : max_pollfd_map, POLLIN | POLLERR |
354 : : POLLHUP))
355 : : return; /* pollfds may be invalid at this point */
356 : :
357 : : if (eloop_sock_table_dispatch_table(writers, pollfds_map,
358 : : max_pollfd_map, POLLOUT))
359 : : return; /* pollfds may be invalid at this point */
360 : :
361 : : eloop_sock_table_dispatch_table(exceptions, pollfds_map,
362 : : max_pollfd_map, POLLERR | POLLHUP);
363 : : }
364 : :
365 : : #else /* CONFIG_ELOOP_POLL */
366 : :
367 : 60579 : static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
368 : : fd_set *fds)
369 : : {
370 : : int i;
371 : :
372 : 60579 : FD_ZERO(fds);
373 : :
374 [ + + ]: 60579 : if (table->table == NULL)
375 : 60579 : return;
376 : :
377 [ + + ]: 212251 : for (i = 0; i < table->count; i++)
378 : 183559 : FD_SET(table->table[i].sock, fds);
379 : : }
380 : :
381 : :
382 : 54978 : static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
383 : : fd_set *fds)
384 : : {
385 : : int i;
386 : :
387 [ + - ][ + + ]: 54978 : if (table == NULL || table->table == NULL)
388 : 54978 : return;
389 : :
390 : 25084 : table->changed = 0;
391 [ + + ]: 180061 : for (i = 0; i < table->count; i++) {
392 [ + + ]: 155591 : if (FD_ISSET(table->table[i].sock, fds)) {
393 : 22368 : table->table[i].handler(table->table[i].sock,
394 : 22368 : table->table[i].eloop_data,
395 : 22368 : table->table[i].user_data);
396 [ + + ]: 22368 : if (table->changed)
397 : 614 : break;
398 : : }
399 : : }
400 : : }
401 : :
402 : : #endif /* CONFIG_ELOOP_POLL */
403 : :
404 : :
405 : 3 : static void eloop_sock_table_destroy(struct eloop_sock_table *table)
406 : : {
407 [ + - ]: 3 : if (table) {
408 : : int i;
409 [ - + ][ # # ]: 3 : for (i = 0; i < table->count && table->table; i++) {
410 : 0 : wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
411 : : "sock=%d eloop_data=%p user_data=%p "
412 : : "handler=%p",
413 : 0 : table->table[i].sock,
414 : 0 : table->table[i].eloop_data,
415 : 0 : table->table[i].user_data,
416 : 0 : table->table[i].handler);
417 : 0 : wpa_trace_dump_funcname("eloop unregistered socket "
418 : : "handler",
419 : 0 : table->table[i].handler);
420 : 0 : wpa_trace_dump("eloop sock", &table->table[i]);
421 : : }
422 : 3 : os_free(table->table);
423 : : }
424 : 3 : }
425 : :
426 : :
427 : 1490 : int eloop_register_read_sock(int sock, eloop_sock_handler handler,
428 : : void *eloop_data, void *user_data)
429 : : {
430 : 1490 : return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
431 : : eloop_data, user_data);
432 : : }
433 : :
434 : :
435 : 1490 : void eloop_unregister_read_sock(int sock)
436 : : {
437 : 1490 : eloop_unregister_sock(sock, EVENT_TYPE_READ);
438 : 1490 : }
439 : :
440 : :
441 : 3120 : static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
442 : : {
443 [ + + - - ]: 3120 : switch (type) {
444 : : case EVENT_TYPE_READ:
445 : 3072 : return &eloop.readers;
446 : : case EVENT_TYPE_WRITE:
447 : 48 : return &eloop.writers;
448 : : case EVENT_TYPE_EXCEPTION:
449 : 0 : return &eloop.exceptions;
450 : : }
451 : :
452 : 3120 : return NULL;
453 : : }
454 : :
455 : :
456 : 1552 : int eloop_register_sock(int sock, eloop_event_type type,
457 : : eloop_sock_handler handler,
458 : : void *eloop_data, void *user_data)
459 : : {
460 : : struct eloop_sock_table *table;
461 : :
462 : 1552 : table = eloop_get_sock_table(type);
463 : 1552 : return eloop_sock_table_add_sock(table, sock, handler,
464 : : eloop_data, user_data);
465 : : }
466 : :
467 : :
468 : 1568 : void eloop_unregister_sock(int sock, eloop_event_type type)
469 : : {
470 : : struct eloop_sock_table *table;
471 : :
472 : 1568 : table = eloop_get_sock_table(type);
473 : 1568 : eloop_sock_table_remove_sock(table, sock);
474 : 1568 : }
475 : :
476 : :
477 : 5062 : int eloop_register_timeout(unsigned int secs, unsigned int usecs,
478 : : eloop_timeout_handler handler,
479 : : void *eloop_data, void *user_data)
480 : : {
481 : : struct eloop_timeout *timeout, *tmp;
482 : : os_time_t now_sec;
483 : :
484 : 5062 : timeout = os_zalloc(sizeof(*timeout));
485 [ - + ]: 5062 : if (timeout == NULL)
486 : 0 : return -1;
487 [ - + ]: 5062 : if (os_get_reltime(&timeout->time) < 0) {
488 : 0 : os_free(timeout);
489 : 0 : return -1;
490 : : }
491 : 5062 : now_sec = timeout->time.sec;
492 : 5062 : timeout->time.sec += secs;
493 [ - + ]: 5062 : if (timeout->time.sec < now_sec) {
494 : : /*
495 : : * Integer overflow - assume long enough timeout to be assumed
496 : : * to be infinite, i.e., the timeout would never happen.
497 : : */
498 : 0 : wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
499 : : "ever happen - ignore it", secs);
500 : 0 : os_free(timeout);
501 : 0 : return 0;
502 : : }
503 : 5062 : timeout->time.usec += usecs;
504 [ + + ]: 5095 : while (timeout->time.usec >= 1000000) {
505 : 33 : timeout->time.sec++;
506 : 33 : timeout->time.usec -= 1000000;
507 : : }
508 : 5062 : timeout->eloop_data = eloop_data;
509 : 5062 : timeout->user_data = user_data;
510 : 5062 : timeout->handler = handler;
511 : 5062 : wpa_trace_add_ref(timeout, eloop, eloop_data);
512 : 5062 : wpa_trace_add_ref(timeout, user, user_data);
513 : 5062 : wpa_trace_record(timeout);
514 : :
515 : : /* Maintain timeouts in order of increasing time */
516 [ + + ]: 10758 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
517 [ + + ]: 10254 : if (os_reltime_before(&timeout->time, &tmp->time)) {
518 : 4558 : dl_list_add(tmp->list.prev, &timeout->list);
519 : 4558 : return 0;
520 : : }
521 : : }
522 : 504 : dl_list_add_tail(&eloop.timeout, &timeout->list);
523 : :
524 : 5062 : return 0;
525 : : }
526 : :
527 : :
528 : 5062 : static void eloop_remove_timeout(struct eloop_timeout *timeout)
529 : : {
530 : 5062 : dl_list_del(&timeout->list);
531 [ + + ]: 5062 : wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
532 [ + + ]: 5062 : wpa_trace_remove_ref(timeout, user, timeout->user_data);
533 : 5062 : os_free(timeout);
534 : 5062 : }
535 : :
536 : :
537 : 7101 : int eloop_cancel_timeout(eloop_timeout_handler handler,
538 : : void *eloop_data, void *user_data)
539 : : {
540 : : struct eloop_timeout *timeout, *prev;
541 : 7101 : int removed = 0;
542 : :
543 [ + + ]: 44152 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
544 : : struct eloop_timeout, list) {
545 [ + + ][ + + ]: 37051 : if (timeout->handler == handler &&
546 [ - + ]: 241 : (timeout->eloop_data == eloop_data ||
547 [ + + ]: 2520 : eloop_data == ELOOP_ALL_CTX) &&
548 [ - + ]: 62 : (timeout->user_data == user_data ||
549 : : user_data == ELOOP_ALL_CTX)) {
550 : 2458 : eloop_remove_timeout(timeout);
551 : 2458 : removed++;
552 : : }
553 : : }
554 : :
555 : 7101 : return removed;
556 : : }
557 : :
558 : :
559 : 0 : int eloop_cancel_timeout_one(eloop_timeout_handler handler,
560 : : void *eloop_data, void *user_data,
561 : : struct os_reltime *remaining)
562 : : {
563 : : struct eloop_timeout *timeout, *prev;
564 : 0 : int removed = 0;
565 : : struct os_reltime now;
566 : :
567 : 0 : os_get_reltime(&now);
568 : 0 : remaining->sec = remaining->usec = 0;
569 : :
570 [ # # ]: 0 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
571 : : struct eloop_timeout, list) {
572 [ # # ][ # # ]: 0 : if (timeout->handler == handler &&
573 [ # # ]: 0 : (timeout->eloop_data == eloop_data) &&
574 : 0 : (timeout->user_data == user_data)) {
575 : 0 : removed = 1;
576 [ # # ]: 0 : if (os_reltime_before(&now, &timeout->time))
577 : 0 : os_reltime_sub(&timeout->time, &now, remaining);
578 : 0 : eloop_remove_timeout(timeout);
579 : 0 : break;
580 : : }
581 : : }
582 : 0 : return removed;
583 : : }
584 : :
585 : :
586 : 0 : int eloop_is_timeout_registered(eloop_timeout_handler handler,
587 : : void *eloop_data, void *user_data)
588 : : {
589 : : struct eloop_timeout *tmp;
590 : :
591 [ # # ]: 0 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
592 [ # # ][ # # ]: 0 : if (tmp->handler == handler &&
593 [ # # ]: 0 : tmp->eloop_data == eloop_data &&
594 : 0 : tmp->user_data == user_data)
595 : 0 : return 1;
596 : : }
597 : :
598 : 0 : return 0;
599 : : }
600 : :
601 : :
602 : 19 : int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
603 : : eloop_timeout_handler handler, void *eloop_data,
604 : : void *user_data)
605 : : {
606 : : struct os_reltime now, requested, remaining;
607 : : struct eloop_timeout *tmp;
608 : :
609 [ + + ]: 157 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
610 [ + + ][ + - ]: 143 : if (tmp->handler == handler &&
611 [ + - ]: 5 : tmp->eloop_data == eloop_data &&
612 : 5 : tmp->user_data == user_data) {
613 : 5 : requested.sec = req_secs;
614 : 5 : requested.usec = req_usecs;
615 : 5 : os_get_reltime(&now);
616 : 5 : os_reltime_sub(&tmp->time, &now, &remaining);
617 [ + - ]: 5 : if (os_reltime_before(&requested, &remaining)) {
618 : 5 : eloop_cancel_timeout(handler, eloop_data,
619 : : user_data);
620 : 5 : eloop_register_timeout(requested.sec,
621 : 5 : requested.usec,
622 : : handler, eloop_data,
623 : : user_data);
624 : 5 : return 1;
625 : : }
626 : : }
627 : : }
628 : :
629 : 19 : return 0;
630 : : }
631 : :
632 : :
633 : 1 : int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
634 : : eloop_timeout_handler handler, void *eloop_data,
635 : : void *user_data)
636 : : {
637 : : struct os_reltime now, requested, remaining;
638 : : struct eloop_timeout *tmp;
639 : :
640 [ + + ]: 9 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
641 [ - + ][ # # ]: 8 : if (tmp->handler == handler &&
642 [ # # ]: 0 : tmp->eloop_data == eloop_data &&
643 : 0 : tmp->user_data == user_data) {
644 : 0 : requested.sec = req_secs;
645 : 0 : requested.usec = req_usecs;
646 : 0 : os_get_reltime(&now);
647 : 0 : os_reltime_sub(&tmp->time, &now, &remaining);
648 [ # # ]: 0 : if (os_reltime_before(&remaining, &requested)) {
649 : 0 : eloop_cancel_timeout(handler, eloop_data,
650 : : user_data);
651 : 0 : eloop_register_timeout(requested.sec,
652 : 0 : requested.usec,
653 : : handler, eloop_data,
654 : : user_data);
655 : 0 : return 1;
656 : : }
657 : : }
658 : : }
659 : :
660 : 1 : return 0;
661 : : }
662 : :
663 : :
664 : : #ifndef CONFIG_NATIVE_WINDOWS
665 : 0 : static void eloop_handle_alarm(int sig)
666 : : {
667 : 0 : wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
668 : : "two seconds. Looks like there\n"
669 : : "is a bug that ends up in a busy loop that "
670 : : "prevents clean shutdown.\n"
671 : : "Killing program forcefully.\n");
672 : 0 : exit(1);
673 : : }
674 : : #endif /* CONFIG_NATIVE_WINDOWS */
675 : :
676 : :
677 : 1 : static void eloop_handle_signal(int sig)
678 : : {
679 : : int i;
680 : :
681 : : #ifndef CONFIG_NATIVE_WINDOWS
682 [ + - ][ + - ]: 1 : if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
[ + - ]
683 : : /* Use SIGALRM to break out from potential busy loops that
684 : : * would not allow the program to be killed. */
685 : 1 : eloop.pending_terminate = 1;
686 : 1 : signal(SIGALRM, eloop_handle_alarm);
687 : 1 : alarm(2);
688 : : }
689 : : #endif /* CONFIG_NATIVE_WINDOWS */
690 : :
691 : 1 : eloop.signaled++;
692 [ + - ]: 4 : for (i = 0; i < eloop.signal_count; i++) {
693 [ + + ]: 4 : if (eloop.signals[i].sig == sig) {
694 : 1 : eloop.signals[i].signaled++;
695 : 1 : break;
696 : : }
697 : : }
698 : 1 : }
699 : :
700 : :
701 : 20193 : static void eloop_process_pending_signals(void)
702 : : {
703 : : int i;
704 : :
705 [ + + ]: 20193 : if (eloop.signaled == 0)
706 : 20193 : return;
707 : 1 : eloop.signaled = 0;
708 : :
709 [ + - ]: 1 : if (eloop.pending_terminate) {
710 : : #ifndef CONFIG_NATIVE_WINDOWS
711 : 1 : alarm(0);
712 : : #endif /* CONFIG_NATIVE_WINDOWS */
713 : 1 : eloop.pending_terminate = 0;
714 : : }
715 : :
716 [ + + ]: 5 : for (i = 0; i < eloop.signal_count; i++) {
717 [ + + ]: 4 : if (eloop.signals[i].signaled) {
718 : 1 : eloop.signals[i].signaled = 0;
719 : 1 : eloop.signals[i].handler(eloop.signals[i].sig,
720 : 1 : eloop.signals[i].user_data);
721 : : }
722 : : }
723 : : }
724 : :
725 : :
726 : 4 : int eloop_register_signal(int sig, eloop_signal_handler handler,
727 : : void *user_data)
728 : : {
729 : : struct eloop_signal *tmp;
730 : :
731 : 4 : tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
732 : : sizeof(struct eloop_signal));
733 [ - + ]: 4 : if (tmp == NULL)
734 : 0 : return -1;
735 : :
736 : 4 : tmp[eloop.signal_count].sig = sig;
737 : 4 : tmp[eloop.signal_count].user_data = user_data;
738 : 4 : tmp[eloop.signal_count].handler = handler;
739 : 4 : tmp[eloop.signal_count].signaled = 0;
740 : 4 : eloop.signal_count++;
741 : 4 : eloop.signals = tmp;
742 : 4 : signal(sig, eloop_handle_signal);
743 : :
744 : 4 : return 0;
745 : : }
746 : :
747 : :
748 : 1 : int eloop_register_signal_terminate(eloop_signal_handler handler,
749 : : void *user_data)
750 : : {
751 : 1 : int ret = eloop_register_signal(SIGINT, handler, user_data);
752 [ + - ]: 1 : if (ret == 0)
753 : 1 : ret = eloop_register_signal(SIGTERM, handler, user_data);
754 : 1 : return ret;
755 : : }
756 : :
757 : :
758 : 0 : int eloop_register_signal_reconfig(eloop_signal_handler handler,
759 : : void *user_data)
760 : : {
761 : : #ifdef CONFIG_NATIVE_WINDOWS
762 : : return 0;
763 : : #else /* CONFIG_NATIVE_WINDOWS */
764 : 0 : return eloop_register_signal(SIGHUP, handler, user_data);
765 : : #endif /* CONFIG_NATIVE_WINDOWS */
766 : : }
767 : :
768 : :
769 : 1 : void eloop_run(void)
770 : : {
771 : : #ifdef CONFIG_ELOOP_POLL
772 : : int num_poll_fds;
773 : : int timeout_ms = 0;
774 : : #else /* CONFIG_ELOOP_POLL */
775 : : fd_set *rfds, *wfds, *efds;
776 : : struct timeval _tv;
777 : : #endif /* CONFIG_ELOOP_POLL */
778 : : int res;
779 : : struct os_reltime tv, now;
780 : :
781 : : #ifndef CONFIG_ELOOP_POLL
782 : 1 : rfds = os_malloc(sizeof(*rfds));
783 : 1 : wfds = os_malloc(sizeof(*wfds));
784 : 1 : efds = os_malloc(sizeof(*efds));
785 [ + - ][ + - ]: 1 : if (rfds == NULL || wfds == NULL || efds == NULL)
[ + - ]
786 : : goto out;
787 : : #endif /* CONFIG_ELOOP_POLL */
788 : :
789 [ + + + + ]: 40387 : while (!eloop.terminate &&
790 [ + - ][ # # ]: 28600 : (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
791 [ # # ]: 0 : eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
792 : : struct eloop_timeout *timeout;
793 [ + + ]: 20193 : timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
794 : : list);
795 [ + + ]: 20193 : if (timeout) {
796 : 11786 : os_get_reltime(&now);
797 [ + + ]: 11786 : if (os_reltime_before(&now, &timeout->time))
798 : 9249 : os_reltime_sub(&timeout->time, &now, &tv);
799 : : else
800 : 2537 : tv.sec = tv.usec = 0;
801 : : #ifdef CONFIG_ELOOP_POLL
802 : : timeout_ms = tv.sec * 1000 + tv.usec / 1000;
803 : : #else /* CONFIG_ELOOP_POLL */
804 : 11786 : _tv.tv_sec = tv.sec;
805 : 11786 : _tv.tv_usec = tv.usec;
806 : : #endif /* CONFIG_ELOOP_POLL */
807 : : }
808 : :
809 : : #ifdef CONFIG_ELOOP_POLL
810 : : num_poll_fds = eloop_sock_table_set_fds(
811 : : &eloop.readers, &eloop.writers, &eloop.exceptions,
812 : : eloop.pollfds, eloop.pollfds_map,
813 : : eloop.max_pollfd_map);
814 : : res = poll(eloop.pollfds, num_poll_fds,
815 : : timeout ? timeout_ms : -1);
816 : :
817 : : if (res < 0 && errno != EINTR && errno != 0) {
818 : : wpa_printf(MSG_INFO, "eloop: poll: %s",
819 : : strerror(errno));
820 : : goto out;
821 : : }
822 : : #else /* CONFIG_ELOOP_POLL */
823 : 20193 : eloop_sock_table_set_fds(&eloop.readers, rfds);
824 : 20193 : eloop_sock_table_set_fds(&eloop.writers, wfds);
825 : 20193 : eloop_sock_table_set_fds(&eloop.exceptions, efds);
826 [ + + ]: 20193 : res = select(eloop.max_sock + 1, rfds, wfds, efds,
827 : : timeout ? &_tv : NULL);
828 [ + + ][ - + ]: 20193 : if (res < 0 && errno != EINTR && errno != 0) {
[ # # ]
829 : 0 : wpa_printf(MSG_INFO, "eloop: select: %s",
830 : 0 : strerror(errno));
831 : 0 : goto out;
832 : : }
833 : : #endif /* CONFIG_ELOOP_POLL */
834 : 20193 : eloop_process_pending_signals();
835 : :
836 : : /* check if some registered timeouts have occurred */
837 [ + + ]: 20193 : timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
838 : : list);
839 [ + + ]: 20193 : if (timeout) {
840 : 11786 : os_get_reltime(&now);
841 [ + + ]: 11786 : if (!os_reltime_before(&now, &timeout->time)) {
842 : 2604 : void *eloop_data = timeout->eloop_data;
843 : 2604 : void *user_data = timeout->user_data;
844 : 2604 : eloop_timeout_handler handler =
845 : : timeout->handler;
846 : 2604 : eloop_remove_timeout(timeout);
847 : 2604 : handler(eloop_data, user_data);
848 : : }
849 : :
850 : : }
851 : :
852 [ + + ]: 20193 : if (res <= 0)
853 : 1867 : continue;
854 : :
855 : : #ifdef CONFIG_ELOOP_POLL
856 : : eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
857 : : &eloop.exceptions, eloop.pollfds_map,
858 : : eloop.max_pollfd_map);
859 : : #else /* CONFIG_ELOOP_POLL */
860 : 18326 : eloop_sock_table_dispatch(&eloop.readers, rfds);
861 : 18326 : eloop_sock_table_dispatch(&eloop.writers, wfds);
862 : 18326 : eloop_sock_table_dispatch(&eloop.exceptions, efds);
863 : : #endif /* CONFIG_ELOOP_POLL */
864 : : }
865 : :
866 : 1 : eloop.terminate = 0;
867 : : out:
868 : : #ifndef CONFIG_ELOOP_POLL
869 : 1 : os_free(rfds);
870 : 1 : os_free(wfds);
871 : 1 : os_free(efds);
872 : : #endif /* CONFIG_ELOOP_POLL */
873 : 1 : return;
874 : : }
875 : :
876 : :
877 : 1 : void eloop_terminate(void)
878 : : {
879 : 1 : eloop.terminate = 1;
880 : 1 : }
881 : :
882 : :
883 : 1 : void eloop_destroy(void)
884 : : {
885 : : struct eloop_timeout *timeout, *prev;
886 : : struct os_reltime now;
887 : :
888 : 1 : os_get_reltime(&now);
889 [ - + ]: 1 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
890 : : struct eloop_timeout, list) {
891 : : int sec, usec;
892 : 0 : sec = timeout->time.sec - now.sec;
893 : 0 : usec = timeout->time.usec - now.usec;
894 [ # # ]: 0 : if (timeout->time.usec < now.usec) {
895 : 0 : sec--;
896 : 0 : usec += 1000000;
897 : : }
898 : 0 : wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
899 : : "eloop_data=%p user_data=%p handler=%p",
900 : : sec, usec, timeout->eloop_data, timeout->user_data,
901 : : timeout->handler);
902 : 0 : wpa_trace_dump_funcname("eloop unregistered timeout handler",
903 : 0 : timeout->handler);
904 : 0 : wpa_trace_dump("eloop timeout", timeout);
905 : 0 : eloop_remove_timeout(timeout);
906 : : }
907 : 1 : eloop_sock_table_destroy(&eloop.readers);
908 : 1 : eloop_sock_table_destroy(&eloop.writers);
909 : 1 : eloop_sock_table_destroy(&eloop.exceptions);
910 : 1 : os_free(eloop.signals);
911 : :
912 : : #ifdef CONFIG_ELOOP_POLL
913 : : os_free(eloop.pollfds);
914 : : os_free(eloop.pollfds_map);
915 : : #endif /* CONFIG_ELOOP_POLL */
916 : 1 : }
917 : :
918 : :
919 : 402 : int eloop_terminated(void)
920 : : {
921 : 402 : return eloop.terminate;
922 : : }
923 : :
924 : :
925 : 0 : void eloop_wait_for_read_sock(int sock)
926 : : {
927 : : #ifdef CONFIG_ELOOP_POLL
928 : : struct pollfd pfd;
929 : :
930 : : if (sock < 0)
931 : : return;
932 : :
933 : : os_memset(&pfd, 0, sizeof(pfd));
934 : : pfd.fd = sock;
935 : : pfd.events = POLLIN;
936 : :
937 : : poll(&pfd, 1, -1);
938 : : #else /* CONFIG_ELOOP_POLL */
939 : : fd_set rfds;
940 : :
941 [ # # ]: 0 : if (sock < 0)
942 : 0 : return;
943 : :
944 : 0 : FD_ZERO(&rfds);
945 : 0 : FD_SET(sock, &rfds);
946 : 0 : select(sock + 1, &rfds, NULL, NULL, NULL);
947 : : #endif /* CONFIG_ELOOP_POLL */
948 : : }
|