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 : 6166 : static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
93 : : {
94 : : int i;
95 [ + - ][ - + ]: 6166 : if (table == NULL || table->table == NULL)
96 : 6166 : return;
97 [ + + ]: 61061 : for (i = 0; i < table->count; i++) {
98 : 54895 : wpa_trace_add_ref(&table->table[i], eloop,
99 : : table->table[i].eloop_data);
100 : 54895 : wpa_trace_add_ref(&table->table[i], user,
101 : : table->table[i].user_data);
102 : : }
103 : : }
104 : :
105 : :
106 : 6166 : static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
107 : : {
108 : : int i;
109 [ + - ][ + + ]: 6166 : if (table == NULL || table->table == NULL)
110 : 6166 : return;
111 [ + + ]: 61053 : for (i = 0; i < table->count; i++) {
112 [ + + ]: 54895 : wpa_trace_remove_ref(&table->table[i], eloop,
113 : : table->table[i].eloop_data);
114 [ + + ]: 54895 : 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 : 6 : int eloop_init(void)
128 : : {
129 : 6 : os_memset(&eloop, 0, sizeof(eloop));
130 : 6 : dl_list_init(&eloop.timeout);
131 : : #ifdef WPA_TRACE
132 : 6 : signal(SIGSEGV, eloop_sigsegv_handler);
133 : : #endif /* WPA_TRACE */
134 : 6 : return 0;
135 : : }
136 : :
137 : :
138 : 3083 : 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 [ + + ]: 3083 : if (sock > eloop.max_sock)
146 : 234 : new_max_sock = sock;
147 : : else
148 : 2849 : new_max_sock = eloop.max_sock;
149 : :
150 [ - + ]: 3083 : 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 : 3083 : eloop_trace_sock_remove_ref(table);
179 : 3083 : tmp = os_realloc_array(table->table, table->count + 1,
180 : : sizeof(struct eloop_sock));
181 [ - + ]: 3083 : if (tmp == NULL)
182 : 0 : return -1;
183 : :
184 : 3083 : tmp[table->count].sock = sock;
185 : 3083 : tmp[table->count].eloop_data = eloop_data;
186 : 3083 : tmp[table->count].user_data = user_data;
187 : 3083 : tmp[table->count].handler = handler;
188 : 3083 : wpa_trace_record(&tmp[table->count]);
189 : 3083 : table->count++;
190 : 3083 : table->table = tmp;
191 : 3083 : eloop.max_sock = new_max_sock;
192 : 3083 : eloop.count++;
193 : 3083 : table->changed = 1;
194 : 3083 : eloop_trace_sock_add_ref(table);
195 : :
196 : 3083 : return 0;
197 : : }
198 : :
199 : :
200 : 3278 : static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
201 : : int sock)
202 : : {
203 : : int i;
204 : :
205 [ + - ][ + - ]: 3278 : if (table == NULL || table->table == NULL || table->count == 0)
[ + + ]
206 : 67 : return;
207 : :
208 [ + + ]: 26216 : for (i = 0; i < table->count; i++) {
209 [ + + ]: 26088 : if (table->table[i].sock == sock)
210 : 3083 : break;
211 : : }
212 [ + + ]: 3211 : if (i == table->count)
213 : 128 : return;
214 : 3083 : eloop_trace_sock_remove_ref(table);
215 [ + + ]: 3083 : if (i != table->count - 1) {
216 : 1198 : os_memmove(&table->table[i], &table->table[i + 1],
217 : : (table->count - i - 1) *
218 : : sizeof(struct eloop_sock));
219 : : }
220 : 3083 : table->count--;
221 : 3083 : eloop.count--;
222 : 3083 : table->changed = 1;
223 : 3278 : 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 : 276516 : static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
368 : : fd_set *fds)
369 : : {
370 : : int i;
371 : :
372 : 276516 : FD_ZERO(fds);
373 : :
374 [ + + ]: 276516 : if (table->table == NULL)
375 : 276516 : return;
376 : :
377 [ + + ]: 928981 : for (i = 0; i < table->count; i++)
378 : 816818 : FD_SET(table->table[i].sock, fds);
379 : : }
380 : :
381 : :
382 : 254322 : static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
383 : : fd_set *fds)
384 : : {
385 : : int i;
386 : :
387 [ + - ][ + + ]: 254322 : if (table == NULL || table->table == NULL)
388 : 254322 : return;
389 : :
390 : 101185 : table->changed = 0;
391 [ + + ]: 828769 : for (i = 0; i < table->count; i++) {
392 [ + + ]: 728806 : if (FD_ISSET(table->table[i].sock, fds)) {
393 : 92583 : table->table[i].handler(table->table[i].sock,
394 : 92583 : table->table[i].eloop_data,
395 : 92583 : table->table[i].user_data);
396 [ + + ]: 92583 : if (table->changed)
397 : 1222 : break;
398 : : }
399 : : }
400 : : }
401 : :
402 : : #endif /* CONFIG_ELOOP_POLL */
403 : :
404 : :
405 : 18 : static void eloop_sock_table_destroy(struct eloop_sock_table *table)
406 : : {
407 [ + - ]: 18 : if (table) {
408 : : int i;
409 [ - + ][ # # ]: 18 : 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 : 18 : os_free(table->table);
423 : : }
424 : 18 : }
425 : :
426 : :
427 : 2874 : int eloop_register_read_sock(int sock, eloop_sock_handler handler,
428 : : void *eloop_data, void *user_data)
429 : : {
430 : 2874 : return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
431 : : eloop_data, user_data);
432 : : }
433 : :
434 : :
435 : 2874 : void eloop_unregister_read_sock(int sock)
436 : : {
437 : 2874 : eloop_unregister_sock(sock, EVENT_TYPE_READ);
438 : 2874 : }
439 : :
440 : :
441 : 6361 : static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
442 : : {
443 [ + + - - ]: 6361 : switch (type) {
444 : : case EVENT_TYPE_READ:
445 : 6160 : return &eloop.readers;
446 : : case EVENT_TYPE_WRITE:
447 : 201 : return &eloop.writers;
448 : : case EVENT_TYPE_EXCEPTION:
449 : 0 : return &eloop.exceptions;
450 : : }
451 : :
452 : 6361 : return NULL;
453 : : }
454 : :
455 : :
456 : 3083 : 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 : 3083 : table = eloop_get_sock_table(type);
463 : 3083 : return eloop_sock_table_add_sock(table, sock, handler,
464 : : eloop_data, user_data);
465 : : }
466 : :
467 : :
468 : 3278 : void eloop_unregister_sock(int sock, eloop_event_type type)
469 : : {
470 : : struct eloop_sock_table *table;
471 : :
472 : 3278 : table = eloop_get_sock_table(type);
473 : 3278 : eloop_sock_table_remove_sock(table, sock);
474 : 3278 : }
475 : :
476 : :
477 : 19737 : 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 : 19737 : timeout = os_zalloc(sizeof(*timeout));
485 [ - + ]: 19737 : if (timeout == NULL)
486 : 0 : return -1;
487 [ - + ]: 19737 : if (os_get_reltime(&timeout->time) < 0) {
488 : 0 : os_free(timeout);
489 : 0 : return -1;
490 : : }
491 : 19737 : now_sec = timeout->time.sec;
492 : 19737 : timeout->time.sec += secs;
493 [ - + ]: 19737 : 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 : 19737 : timeout->time.usec += usecs;
504 [ + + ]: 20466 : while (timeout->time.usec >= 1000000) {
505 : 729 : timeout->time.sec++;
506 : 729 : timeout->time.usec -= 1000000;
507 : : }
508 : 19737 : timeout->eloop_data = eloop_data;
509 : 19737 : timeout->user_data = user_data;
510 : 19737 : timeout->handler = handler;
511 : 19737 : wpa_trace_add_ref(timeout, eloop, eloop_data);
512 : 19737 : wpa_trace_add_ref(timeout, user, user_data);
513 : 19737 : wpa_trace_record(timeout);
514 : :
515 : : /* Maintain timeouts in order of increasing time */
516 [ + + ]: 50290 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
517 [ + + ]: 48427 : if (os_reltime_before(&timeout->time, &tmp->time)) {
518 : 17874 : dl_list_add(tmp->list.prev, &timeout->list);
519 : 17874 : return 0;
520 : : }
521 : : }
522 : 1863 : dl_list_add_tail(&eloop.timeout, &timeout->list);
523 : :
524 : 19737 : return 0;
525 : : }
526 : :
527 : :
528 : 19737 : static void eloop_remove_timeout(struct eloop_timeout *timeout)
529 : : {
530 : 19737 : dl_list_del(&timeout->list);
531 [ + + ]: 19737 : wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
532 [ + + ]: 19737 : wpa_trace_remove_ref(timeout, user, timeout->user_data);
533 : 19737 : os_free(timeout);
534 : 19737 : }
535 : :
536 : :
537 : 50614 : int eloop_cancel_timeout(eloop_timeout_handler handler,
538 : : void *eloop_data, void *user_data)
539 : : {
540 : : struct eloop_timeout *timeout, *prev;
541 : 50614 : int removed = 0;
542 : :
543 [ + + ]: 305882 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
544 : : struct eloop_timeout, list) {
545 [ + + ][ + + ]: 255268 : if (timeout->handler == handler &&
546 [ - + ]: 411 : (timeout->eloop_data == eloop_data ||
547 [ + + ]: 16337 : eloop_data == ELOOP_ALL_CTX) &&
548 [ - + ]: 5825 : (timeout->user_data == user_data ||
549 : : user_data == ELOOP_ALL_CTX)) {
550 : 10512 : eloop_remove_timeout(timeout);
551 : 10512 : removed++;
552 : : }
553 : : }
554 : :
555 : 50614 : 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 : 479 : int eloop_is_timeout_registered(eloop_timeout_handler handler,
587 : : void *eloop_data, void *user_data)
588 : : {
589 : : struct eloop_timeout *tmp;
590 : :
591 [ + + ]: 3140 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
592 [ - + ][ # # ]: 2661 : 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 : 479 : return 0;
599 : : }
600 : :
601 : :
602 : 1455 : 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 [ + + ]: 6643 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
610 [ + + ][ + - ]: 5616 : if (tmp->handler == handler &&
611 [ + - ]: 428 : tmp->eloop_data == eloop_data &&
612 : 428 : tmp->user_data == user_data) {
613 : 428 : requested.sec = req_secs;
614 : 428 : requested.usec = req_usecs;
615 : 428 : os_get_reltime(&now);
616 : 428 : os_reltime_sub(&tmp->time, &now, &remaining);
617 [ + + ]: 428 : if (os_reltime_before(&requested, &remaining)) {
618 : 51 : eloop_cancel_timeout(handler, eloop_data,
619 : : user_data);
620 : 51 : eloop_register_timeout(requested.sec,
621 : 51 : requested.usec,
622 : : handler, eloop_data,
623 : : user_data);
624 : 51 : return 1;
625 : : }
626 : 377 : return 0;
627 : : }
628 : : }
629 : :
630 : 1455 : return -1;
631 : : }
632 : :
633 : :
634 : 1 : int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
635 : : eloop_timeout_handler handler, void *eloop_data,
636 : : void *user_data)
637 : : {
638 : : struct os_reltime now, requested, remaining;
639 : : struct eloop_timeout *tmp;
640 : :
641 [ + + ]: 9 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
642 [ - + ][ # # ]: 8 : if (tmp->handler == handler &&
643 [ # # ]: 0 : tmp->eloop_data == eloop_data &&
644 : 0 : tmp->user_data == user_data) {
645 : 0 : requested.sec = req_secs;
646 : 0 : requested.usec = req_usecs;
647 : 0 : os_get_reltime(&now);
648 : 0 : os_reltime_sub(&tmp->time, &now, &remaining);
649 [ # # ]: 0 : if (os_reltime_before(&remaining, &requested)) {
650 : 0 : eloop_cancel_timeout(handler, eloop_data,
651 : : user_data);
652 : 0 : eloop_register_timeout(requested.sec,
653 : 0 : requested.usec,
654 : : handler, eloop_data,
655 : : user_data);
656 : 0 : return 1;
657 : : }
658 : 0 : return 0;
659 : : }
660 : : }
661 : :
662 : 1 : return -1;
663 : : }
664 : :
665 : :
666 : : #ifndef CONFIG_NATIVE_WINDOWS
667 : 0 : static void eloop_handle_alarm(int sig)
668 : : {
669 : 0 : wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
670 : : "two seconds. Looks like there\n"
671 : : "is a bug that ends up in a busy loop that "
672 : : "prevents clean shutdown.\n"
673 : : "Killing program forcefully.\n");
674 : 0 : exit(1);
675 : : }
676 : : #endif /* CONFIG_NATIVE_WINDOWS */
677 : :
678 : :
679 : 6 : static void eloop_handle_signal(int sig)
680 : : {
681 : : int i;
682 : :
683 : : #ifndef CONFIG_NATIVE_WINDOWS
684 [ + - ][ + - ]: 6 : if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
[ + - ]
685 : : /* Use SIGALRM to break out from potential busy loops that
686 : : * would not allow the program to be killed. */
687 : 6 : eloop.pending_terminate = 1;
688 : 6 : signal(SIGALRM, eloop_handle_alarm);
689 : 6 : alarm(2);
690 : : }
691 : : #endif /* CONFIG_NATIVE_WINDOWS */
692 : :
693 : 6 : eloop.signaled++;
694 [ + - ]: 16 : for (i = 0; i < eloop.signal_count; i++) {
695 [ + + ]: 16 : if (eloop.signals[i].sig == sig) {
696 : 6 : eloop.signals[i].signaled++;
697 : 6 : break;
698 : : }
699 : : }
700 : 6 : }
701 : :
702 : :
703 : 92172 : static void eloop_process_pending_signals(void)
704 : : {
705 : : int i;
706 : :
707 [ + + ]: 92172 : if (eloop.signaled == 0)
708 : 92172 : return;
709 : 6 : eloop.signaled = 0;
710 : :
711 [ + - ]: 6 : if (eloop.pending_terminate) {
712 : : #ifndef CONFIG_NATIVE_WINDOWS
713 : 6 : alarm(0);
714 : : #endif /* CONFIG_NATIVE_WINDOWS */
715 : 6 : eloop.pending_terminate = 0;
716 : : }
717 : :
718 [ + + ]: 26 : for (i = 0; i < eloop.signal_count; i++) {
719 [ + + ]: 20 : if (eloop.signals[i].signaled) {
720 : 6 : eloop.signals[i].signaled = 0;
721 : 6 : eloop.signals[i].handler(eloop.signals[i].sig,
722 : 6 : eloop.signals[i].user_data);
723 : : }
724 : : }
725 : : }
726 : :
727 : :
728 : 20 : int eloop_register_signal(int sig, eloop_signal_handler handler,
729 : : void *user_data)
730 : : {
731 : : struct eloop_signal *tmp;
732 : :
733 : 20 : tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
734 : : sizeof(struct eloop_signal));
735 [ - + ]: 20 : if (tmp == NULL)
736 : 0 : return -1;
737 : :
738 : 20 : tmp[eloop.signal_count].sig = sig;
739 : 20 : tmp[eloop.signal_count].user_data = user_data;
740 : 20 : tmp[eloop.signal_count].handler = handler;
741 : 20 : tmp[eloop.signal_count].signaled = 0;
742 : 20 : eloop.signal_count++;
743 : 20 : eloop.signals = tmp;
744 : 20 : signal(sig, eloop_handle_signal);
745 : :
746 : 20 : return 0;
747 : : }
748 : :
749 : :
750 : 6 : int eloop_register_signal_terminate(eloop_signal_handler handler,
751 : : void *user_data)
752 : : {
753 : 6 : int ret = eloop_register_signal(SIGINT, handler, user_data);
754 [ + - ]: 6 : if (ret == 0)
755 : 6 : ret = eloop_register_signal(SIGTERM, handler, user_data);
756 : 6 : return ret;
757 : : }
758 : :
759 : :
760 : 4 : int eloop_register_signal_reconfig(eloop_signal_handler handler,
761 : : void *user_data)
762 : : {
763 : : #ifdef CONFIG_NATIVE_WINDOWS
764 : : return 0;
765 : : #else /* CONFIG_NATIVE_WINDOWS */
766 : 4 : return eloop_register_signal(SIGHUP, handler, user_data);
767 : : #endif /* CONFIG_NATIVE_WINDOWS */
768 : : }
769 : :
770 : :
771 : 6 : void eloop_run(void)
772 : : {
773 : : #ifdef CONFIG_ELOOP_POLL
774 : : int num_poll_fds;
775 : : int timeout_ms = 0;
776 : : #else /* CONFIG_ELOOP_POLL */
777 : : fd_set *rfds, *wfds, *efds;
778 : : struct timeval _tv;
779 : : #endif /* CONFIG_ELOOP_POLL */
780 : : int res;
781 : : struct os_reltime tv, now;
782 : :
783 : : #ifndef CONFIG_ELOOP_POLL
784 : 6 : rfds = os_malloc(sizeof(*rfds));
785 : 6 : wfds = os_malloc(sizeof(*wfds));
786 : 6 : efds = os_malloc(sizeof(*efds));
787 [ + - ][ + - ]: 6 : if (rfds == NULL || wfds == NULL || efds == NULL)
[ + - ]
788 : : goto out;
789 : : #endif /* CONFIG_ELOOP_POLL */
790 : :
791 [ + + + + ]: 184350 : while (!eloop.terminate &&
792 [ + - ][ # # ]: 111781 : (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
793 [ # # ]: 0 : eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
794 : : struct eloop_timeout *timeout;
795 [ + + ]: 92172 : timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
796 : : list);
797 [ + + ]: 92172 : if (timeout) {
798 : 72563 : os_get_reltime(&now);
799 [ + + ]: 72563 : if (os_reltime_before(&now, &timeout->time))
800 : 65178 : os_reltime_sub(&timeout->time, &now, &tv);
801 : : else
802 : 7385 : tv.sec = tv.usec = 0;
803 : : #ifdef CONFIG_ELOOP_POLL
804 : : timeout_ms = tv.sec * 1000 + tv.usec / 1000;
805 : : #else /* CONFIG_ELOOP_POLL */
806 : 72563 : _tv.tv_sec = tv.sec;
807 : 72563 : _tv.tv_usec = tv.usec;
808 : : #endif /* CONFIG_ELOOP_POLL */
809 : : }
810 : :
811 : : #ifdef CONFIG_ELOOP_POLL
812 : : num_poll_fds = eloop_sock_table_set_fds(
813 : : &eloop.readers, &eloop.writers, &eloop.exceptions,
814 : : eloop.pollfds, eloop.pollfds_map,
815 : : eloop.max_pollfd_map);
816 : : res = poll(eloop.pollfds, num_poll_fds,
817 : : timeout ? timeout_ms : -1);
818 : :
819 : : if (res < 0 && errno != EINTR && errno != 0) {
820 : : wpa_printf(MSG_INFO, "eloop: poll: %s",
821 : : strerror(errno));
822 : : goto out;
823 : : }
824 : : #else /* CONFIG_ELOOP_POLL */
825 : 92172 : eloop_sock_table_set_fds(&eloop.readers, rfds);
826 : 92172 : eloop_sock_table_set_fds(&eloop.writers, wfds);
827 : 92172 : eloop_sock_table_set_fds(&eloop.exceptions, efds);
828 [ + + ]: 92172 : res = select(eloop.max_sock + 1, rfds, wfds, efds,
829 : : timeout ? &_tv : NULL);
830 [ - + ][ # # ]: 92172 : if (res < 0 && errno != EINTR && errno != 0) {
[ + + ]
831 : 0 : wpa_printf(MSG_INFO, "eloop: select: %s",
832 : 0 : strerror(errno));
833 : 0 : goto out;
834 : : }
835 : : #endif /* CONFIG_ELOOP_POLL */
836 : 92172 : eloop_process_pending_signals();
837 : :
838 : : /* check if some registered timeouts have occurred */
839 [ + + ]: 92172 : timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
840 : : list);
841 [ + + ]: 92172 : if (timeout) {
842 : 72563 : os_get_reltime(&now);
843 [ + + ]: 72563 : if (!os_reltime_before(&now, &timeout->time)) {
844 : 9225 : void *eloop_data = timeout->eloop_data;
845 : 9225 : void *user_data = timeout->user_data;
846 : 9225 : eloop_timeout_handler handler =
847 : : timeout->handler;
848 : 9225 : eloop_remove_timeout(timeout);
849 : 9225 : handler(eloop_data, user_data);
850 : : }
851 : :
852 : : }
853 : :
854 [ + + ]: 92172 : if (res <= 0)
855 : 7398 : continue;
856 : :
857 : : #ifdef CONFIG_ELOOP_POLL
858 : : eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
859 : : &eloop.exceptions, eloop.pollfds_map,
860 : : eloop.max_pollfd_map);
861 : : #else /* CONFIG_ELOOP_POLL */
862 : 84774 : eloop_sock_table_dispatch(&eloop.readers, rfds);
863 : 84774 : eloop_sock_table_dispatch(&eloop.writers, wfds);
864 : 84774 : eloop_sock_table_dispatch(&eloop.exceptions, efds);
865 : : #endif /* CONFIG_ELOOP_POLL */
866 : : }
867 : :
868 : 6 : eloop.terminate = 0;
869 : : out:
870 : : #ifndef CONFIG_ELOOP_POLL
871 : 6 : os_free(rfds);
872 : 6 : os_free(wfds);
873 : 6 : os_free(efds);
874 : : #endif /* CONFIG_ELOOP_POLL */
875 : 6 : return;
876 : : }
877 : :
878 : :
879 : 6 : void eloop_terminate(void)
880 : : {
881 : 6 : eloop.terminate = 1;
882 : 6 : }
883 : :
884 : :
885 : 6 : void eloop_destroy(void)
886 : : {
887 : : struct eloop_timeout *timeout, *prev;
888 : : struct os_reltime now;
889 : :
890 : 6 : os_get_reltime(&now);
891 [ - + ]: 6 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
892 : : struct eloop_timeout, list) {
893 : : int sec, usec;
894 : 0 : sec = timeout->time.sec - now.sec;
895 : 0 : usec = timeout->time.usec - now.usec;
896 [ # # ]: 0 : if (timeout->time.usec < now.usec) {
897 : 0 : sec--;
898 : 0 : usec += 1000000;
899 : : }
900 : 0 : wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
901 : : "eloop_data=%p user_data=%p handler=%p",
902 : : sec, usec, timeout->eloop_data, timeout->user_data,
903 : : timeout->handler);
904 : 0 : wpa_trace_dump_funcname("eloop unregistered timeout handler",
905 : 0 : timeout->handler);
906 : 0 : wpa_trace_dump("eloop timeout", timeout);
907 : 0 : eloop_remove_timeout(timeout);
908 : : }
909 : 6 : eloop_sock_table_destroy(&eloop.readers);
910 : 6 : eloop_sock_table_destroy(&eloop.writers);
911 : 6 : eloop_sock_table_destroy(&eloop.exceptions);
912 : 6 : os_free(eloop.signals);
913 : :
914 : : #ifdef CONFIG_ELOOP_POLL
915 : : os_free(eloop.pollfds);
916 : : os_free(eloop.pollfds_map);
917 : : #endif /* CONFIG_ELOOP_POLL */
918 : 6 : }
919 : :
920 : :
921 : 719 : int eloop_terminated(void)
922 : : {
923 : 719 : return eloop.terminate;
924 : : }
925 : :
926 : :
927 : 0 : void eloop_wait_for_read_sock(int sock)
928 : : {
929 : : #ifdef CONFIG_ELOOP_POLL
930 : : struct pollfd pfd;
931 : :
932 : : if (sock < 0)
933 : : return;
934 : :
935 : : os_memset(&pfd, 0, sizeof(pfd));
936 : : pfd.fd = sock;
937 : : pfd.events = POLLIN;
938 : :
939 : : poll(&pfd, 1, -1);
940 : : #else /* CONFIG_ELOOP_POLL */
941 : : fd_set rfds;
942 : :
943 [ # # ]: 0 : if (sock < 0)
944 : 0 : return;
945 : :
946 : 0 : FD_ZERO(&rfds);
947 : 0 : FD_SET(sock, &rfds);
948 : 0 : select(sock + 1, &rfds, NULL, NULL, NULL);
949 : : #endif /* CONFIG_ELOOP_POLL */
950 : : }
|