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 : #include <assert.h>
11 :
12 : #include "common.h"
13 : #include "trace.h"
14 : #include "list.h"
15 : #include "eloop.h"
16 :
17 : #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL)
18 : #error Do not define both of poll and epoll
19 : #endif
20 :
21 : #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL)
22 : #define CONFIG_ELOOP_SELECT
23 : #endif
24 :
25 : #ifdef CONFIG_ELOOP_POLL
26 : #include <poll.h>
27 : #endif /* CONFIG_ELOOP_POLL */
28 :
29 : #ifdef CONFIG_ELOOP_EPOLL
30 : #include <sys/epoll.h>
31 : #endif /* CONFIG_ELOOP_EPOLL */
32 :
33 : struct eloop_sock {
34 : int sock;
35 : void *eloop_data;
36 : void *user_data;
37 : eloop_sock_handler handler;
38 : WPA_TRACE_REF(eloop);
39 : WPA_TRACE_REF(user);
40 : WPA_TRACE_INFO
41 : };
42 :
43 : struct eloop_timeout {
44 : struct dl_list list;
45 : struct os_reltime time;
46 : void *eloop_data;
47 : void *user_data;
48 : eloop_timeout_handler handler;
49 : WPA_TRACE_REF(eloop);
50 : WPA_TRACE_REF(user);
51 : WPA_TRACE_INFO
52 : };
53 :
54 : struct eloop_signal {
55 : int sig;
56 : void *user_data;
57 : eloop_signal_handler handler;
58 : int signaled;
59 : };
60 :
61 : struct eloop_sock_table {
62 : int count;
63 : struct eloop_sock *table;
64 : #ifdef CONFIG_ELOOP_EPOLL
65 : eloop_event_type type;
66 : #else /* CONFIG_ELOOP_EPOLL */
67 : int changed;
68 : #endif /* CONFIG_ELOOP_EPOLL */
69 : };
70 :
71 : struct eloop_data {
72 : int max_sock;
73 :
74 : int count; /* sum of all table counts */
75 : #ifdef CONFIG_ELOOP_POLL
76 : int max_pollfd_map; /* number of pollfds_map currently allocated */
77 : int max_poll_fds; /* number of pollfds currently allocated */
78 : struct pollfd *pollfds;
79 : struct pollfd **pollfds_map;
80 : #endif /* CONFIG_ELOOP_POLL */
81 : #ifdef CONFIG_ELOOP_EPOLL
82 : int epollfd;
83 : int epoll_max_event_num;
84 : int epoll_max_fd;
85 : struct eloop_sock *epoll_table;
86 : struct epoll_event *epoll_events;
87 : #endif /* CONFIG_ELOOP_EPOLL */
88 : struct eloop_sock_table readers;
89 : struct eloop_sock_table writers;
90 : struct eloop_sock_table exceptions;
91 :
92 : struct dl_list timeout;
93 :
94 : int signal_count;
95 : struct eloop_signal *signals;
96 : int signaled;
97 : int pending_terminate;
98 :
99 : int terminate;
100 : };
101 :
102 : static struct eloop_data eloop;
103 :
104 :
105 : #ifdef WPA_TRACE
106 :
107 0 : static void eloop_sigsegv_handler(int sig)
108 : {
109 0 : wpa_trace_show("eloop SIGSEGV");
110 0 : abort();
111 : }
112 :
113 14352 : static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
114 : {
115 : int i;
116 14352 : if (table == NULL || table->table == NULL)
117 14352 : return;
118 140502 : for (i = 0; i < table->count; i++) {
119 126150 : wpa_trace_add_ref(&table->table[i], eloop,
120 : table->table[i].eloop_data);
121 126150 : wpa_trace_add_ref(&table->table[i], user,
122 : table->table[i].user_data);
123 : }
124 : }
125 :
126 :
127 14352 : static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
128 : {
129 : int i;
130 14352 : if (table == NULL || table->table == NULL)
131 14360 : return;
132 140494 : for (i = 0; i < table->count; i++) {
133 126150 : wpa_trace_remove_ref(&table->table[i], eloop,
134 : table->table[i].eloop_data);
135 126150 : wpa_trace_remove_ref(&table->table[i], user,
136 : table->table[i].user_data);
137 : }
138 : }
139 :
140 : #else /* WPA_TRACE */
141 :
142 : #define eloop_trace_sock_add_ref(table) do { } while (0)
143 : #define eloop_trace_sock_remove_ref(table) do { } while (0)
144 :
145 : #endif /* WPA_TRACE */
146 :
147 :
148 6 : int eloop_init(void)
149 : {
150 6 : os_memset(&eloop, 0, sizeof(eloop));
151 6 : dl_list_init(&eloop.timeout);
152 : #ifdef CONFIG_ELOOP_EPOLL
153 : eloop.epollfd = epoll_create1(0);
154 : if (eloop.epollfd < 0) {
155 : wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n",
156 : __func__, strerror(errno));
157 : return -1;
158 : }
159 : eloop.readers.type = EVENT_TYPE_READ;
160 : eloop.writers.type = EVENT_TYPE_WRITE;
161 : eloop.exceptions.type = EVENT_TYPE_EXCEPTION;
162 : #endif /* CONFIG_ELOOP_EPOLL */
163 : #ifdef WPA_TRACE
164 6 : signal(SIGSEGV, eloop_sigsegv_handler);
165 : #endif /* WPA_TRACE */
166 6 : return 0;
167 : }
168 :
169 :
170 7176 : static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
171 : int sock, eloop_sock_handler handler,
172 : void *eloop_data, void *user_data)
173 : {
174 : #ifdef CONFIG_ELOOP_EPOLL
175 : struct eloop_sock *temp_table;
176 : struct epoll_event ev, *temp_events;
177 : int next;
178 : #endif /* CONFIG_ELOOP_EPOLL */
179 : struct eloop_sock *tmp;
180 : int new_max_sock;
181 :
182 7176 : if (sock > eloop.max_sock)
183 488 : new_max_sock = sock;
184 : else
185 6688 : new_max_sock = eloop.max_sock;
186 :
187 7176 : if (table == NULL)
188 0 : return -1;
189 :
190 : #ifdef CONFIG_ELOOP_POLL
191 : if (new_max_sock >= eloop.max_pollfd_map) {
192 : struct pollfd **nmap;
193 : nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
194 : sizeof(struct pollfd *));
195 : if (nmap == NULL)
196 : return -1;
197 :
198 : eloop.max_pollfd_map = new_max_sock + 50;
199 : eloop.pollfds_map = nmap;
200 : }
201 :
202 : if (eloop.count + 1 > eloop.max_poll_fds) {
203 : struct pollfd *n;
204 : int nmax = eloop.count + 1 + 50;
205 : n = os_realloc_array(eloop.pollfds, nmax,
206 : sizeof(struct pollfd));
207 : if (n == NULL)
208 : return -1;
209 :
210 : eloop.max_poll_fds = nmax;
211 : eloop.pollfds = n;
212 : }
213 : #endif /* CONFIG_ELOOP_POLL */
214 : #ifdef CONFIG_ELOOP_EPOLL
215 : if (new_max_sock >= eloop.epoll_max_fd) {
216 : next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2;
217 : temp_table = os_realloc_array(eloop.epoll_table, next,
218 : sizeof(struct eloop_sock));
219 : if (temp_table == NULL)
220 : return -1;
221 :
222 : eloop.epoll_max_fd = next;
223 : eloop.epoll_table = temp_table;
224 : }
225 :
226 : if (eloop.count + 1 > eloop.epoll_max_event_num) {
227 : next = eloop.epoll_max_event_num == 0 ? 8 :
228 : eloop.epoll_max_event_num * 2;
229 : temp_events = os_realloc_array(eloop.epoll_events, next,
230 : sizeof(struct epoll_event));
231 : if (temp_events == NULL) {
232 : wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. "
233 : "%s\n", __func__, strerror(errno));
234 : return -1;
235 : }
236 :
237 : eloop.epoll_max_event_num = next;
238 : eloop.epoll_events = temp_events;
239 : }
240 : #endif /* CONFIG_ELOOP_EPOLL */
241 :
242 7176 : eloop_trace_sock_remove_ref(table);
243 7176 : tmp = os_realloc_array(table->table, table->count + 1,
244 : sizeof(struct eloop_sock));
245 7176 : if (tmp == NULL)
246 0 : return -1;
247 :
248 7176 : tmp[table->count].sock = sock;
249 7176 : tmp[table->count].eloop_data = eloop_data;
250 7176 : tmp[table->count].user_data = user_data;
251 7176 : tmp[table->count].handler = handler;
252 7176 : wpa_trace_record(&tmp[table->count]);
253 7176 : table->count++;
254 7176 : table->table = tmp;
255 7176 : eloop.max_sock = new_max_sock;
256 7176 : eloop.count++;
257 : #ifndef CONFIG_ELOOP_EPOLL
258 7176 : table->changed = 1;
259 : #endif /* CONFIG_ELOOP_EPOLL */
260 7176 : eloop_trace_sock_add_ref(table);
261 :
262 : #ifdef CONFIG_ELOOP_EPOLL
263 : os_memset(&ev, 0, sizeof(ev));
264 : switch (table->type) {
265 : case EVENT_TYPE_READ:
266 : ev.events = EPOLLIN;
267 : break;
268 : case EVENT_TYPE_WRITE:
269 : ev.events = EPOLLOUT;
270 : break;
271 : /*
272 : * Exceptions are always checked when using epoll, but I suppose it's
273 : * possible that someone registered a socket *only* for exception
274 : * handling.
275 : */
276 : case EVENT_TYPE_EXCEPTION:
277 : ev.events = EPOLLERR | EPOLLHUP;
278 : break;
279 : }
280 : ev.data.fd = sock;
281 : if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
282 : wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d "
283 : "failed. %s\n", __func__, sock, strerror(errno));
284 : return -1;
285 : }
286 : os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
287 : sizeof(struct eloop_sock));
288 : #endif /* CONFIG_ELOOP_EPOLL */
289 7176 : return 0;
290 : }
291 :
292 :
293 7646 : static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
294 : int sock)
295 : {
296 : int i;
297 :
298 7646 : if (table == NULL || table->table == NULL || table->count == 0)
299 150 : return;
300 :
301 59124 : for (i = 0; i < table->count; i++) {
302 58804 : if (table->table[i].sock == sock)
303 7176 : break;
304 : }
305 7496 : if (i == table->count)
306 320 : return;
307 7176 : eloop_trace_sock_remove_ref(table);
308 7176 : if (i != table->count - 1) {
309 3041 : os_memmove(&table->table[i], &table->table[i + 1],
310 : (table->count - i - 1) *
311 : sizeof(struct eloop_sock));
312 : }
313 7176 : table->count--;
314 7176 : eloop.count--;
315 : #ifndef CONFIG_ELOOP_EPOLL
316 7176 : table->changed = 1;
317 : #endif /* CONFIG_ELOOP_EPOLL */
318 7176 : eloop_trace_sock_add_ref(table);
319 : #ifdef CONFIG_ELOOP_EPOLL
320 : if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
321 : wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d "
322 : "failed. %s\n", __func__, sock, strerror(errno));
323 : return;
324 : }
325 : os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
326 : #endif /* CONFIG_ELOOP_EPOLL */
327 : }
328 :
329 :
330 : #ifdef CONFIG_ELOOP_POLL
331 :
332 : static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
333 : {
334 : if (fd < mx && fd >= 0)
335 : return pollfds_map[fd];
336 : return NULL;
337 : }
338 :
339 :
340 : static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
341 : struct eloop_sock_table *writers,
342 : struct eloop_sock_table *exceptions,
343 : struct pollfd *pollfds,
344 : struct pollfd **pollfds_map,
345 : int max_pollfd_map)
346 : {
347 : int i;
348 : int nxt = 0;
349 : int fd;
350 : struct pollfd *pfd;
351 :
352 : /* Clear pollfd lookup map. It will be re-populated below. */
353 : os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
354 :
355 : if (readers && readers->table) {
356 : for (i = 0; i < readers->count; i++) {
357 : fd = readers->table[i].sock;
358 : assert(fd >= 0 && fd < max_pollfd_map);
359 : pollfds[nxt].fd = fd;
360 : pollfds[nxt].events = POLLIN;
361 : pollfds[nxt].revents = 0;
362 : pollfds_map[fd] = &(pollfds[nxt]);
363 : nxt++;
364 : }
365 : }
366 :
367 : if (writers && writers->table) {
368 : for (i = 0; i < writers->count; i++) {
369 : /*
370 : * See if we already added this descriptor, update it
371 : * if so.
372 : */
373 : fd = writers->table[i].sock;
374 : assert(fd >= 0 && fd < max_pollfd_map);
375 : pfd = pollfds_map[fd];
376 : if (!pfd) {
377 : pfd = &(pollfds[nxt]);
378 : pfd->events = 0;
379 : pfd->fd = fd;
380 : pollfds[i].revents = 0;
381 : pollfds_map[fd] = pfd;
382 : nxt++;
383 : }
384 : pfd->events |= POLLOUT;
385 : }
386 : }
387 :
388 : /*
389 : * Exceptions are always checked when using poll, but I suppose it's
390 : * possible that someone registered a socket *only* for exception
391 : * handling. Set the POLLIN bit in this case.
392 : */
393 : if (exceptions && exceptions->table) {
394 : for (i = 0; i < exceptions->count; i++) {
395 : /*
396 : * See if we already added this descriptor, just use it
397 : * if so.
398 : */
399 : fd = exceptions->table[i].sock;
400 : assert(fd >= 0 && fd < max_pollfd_map);
401 : pfd = pollfds_map[fd];
402 : if (!pfd) {
403 : pfd = &(pollfds[nxt]);
404 : pfd->events = POLLIN;
405 : pfd->fd = fd;
406 : pollfds[i].revents = 0;
407 : pollfds_map[fd] = pfd;
408 : nxt++;
409 : }
410 : }
411 : }
412 :
413 : return nxt;
414 : }
415 :
416 :
417 : static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
418 : struct pollfd **pollfds_map,
419 : int max_pollfd_map,
420 : short int revents)
421 : {
422 : int i;
423 : struct pollfd *pfd;
424 :
425 : if (!table || !table->table)
426 : return 0;
427 :
428 : table->changed = 0;
429 : for (i = 0; i < table->count; i++) {
430 : pfd = find_pollfd(pollfds_map, table->table[i].sock,
431 : max_pollfd_map);
432 : if (!pfd)
433 : continue;
434 :
435 : if (!(pfd->revents & revents))
436 : continue;
437 :
438 : table->table[i].handler(table->table[i].sock,
439 : table->table[i].eloop_data,
440 : table->table[i].user_data);
441 : if (table->changed)
442 : return 1;
443 : }
444 :
445 : return 0;
446 : }
447 :
448 :
449 : static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
450 : struct eloop_sock_table *writers,
451 : struct eloop_sock_table *exceptions,
452 : struct pollfd **pollfds_map,
453 : int max_pollfd_map)
454 : {
455 : if (eloop_sock_table_dispatch_table(readers, pollfds_map,
456 : max_pollfd_map, POLLIN | POLLERR |
457 : POLLHUP))
458 : return; /* pollfds may be invalid at this point */
459 :
460 : if (eloop_sock_table_dispatch_table(writers, pollfds_map,
461 : max_pollfd_map, POLLOUT))
462 : return; /* pollfds may be invalid at this point */
463 :
464 : eloop_sock_table_dispatch_table(exceptions, pollfds_map,
465 : max_pollfd_map, POLLERR | POLLHUP);
466 : }
467 :
468 : #endif /* CONFIG_ELOOP_POLL */
469 :
470 : #ifdef CONFIG_ELOOP_SELECT
471 :
472 700491 : static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
473 : fd_set *fds)
474 : {
475 : int i;
476 :
477 700491 : FD_ZERO(fds);
478 :
479 700491 : if (table->table == NULL)
480 1068119 : return;
481 :
482 2367606 : for (i = 0; i < table->count; i++) {
483 2034743 : assert(table->table[i].sock >= 0);
484 2034743 : FD_SET(table->table[i].sock, fds);
485 : }
486 : }
487 :
488 :
489 639912 : static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
490 : fd_set *fds)
491 : {
492 : int i;
493 :
494 639912 : if (table == NULL || table->table == NULL)
495 980993 : return;
496 :
497 298831 : table->changed = 0;
498 2091017 : for (i = 0; i < table->count; i++) {
499 1795253 : if (FD_ISSET(table->table[i].sock, fds)) {
500 695190 : table->table[i].handler(table->table[i].sock,
501 231730 : table->table[i].eloop_data,
502 231730 : table->table[i].user_data);
503 231730 : if (table->changed)
504 3067 : break;
505 : }
506 : }
507 : }
508 :
509 : #endif /* CONFIG_ELOOP_SELECT */
510 :
511 :
512 : #ifdef CONFIG_ELOOP_EPOLL
513 : static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
514 : {
515 : struct eloop_sock *table;
516 : int i;
517 :
518 : for (i = 0; i < nfds; i++) {
519 : table = &eloop.epoll_table[events[i].data.fd];
520 : if (table->handler == NULL)
521 : continue;
522 : table->handler(table->sock, table->eloop_data,
523 : table->user_data);
524 : }
525 : }
526 : #endif /* CONFIG_ELOOP_EPOLL */
527 :
528 :
529 18 : static void eloop_sock_table_destroy(struct eloop_sock_table *table)
530 : {
531 18 : if (table) {
532 : int i;
533 18 : for (i = 0; i < table->count && table->table; i++) {
534 0 : wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
535 : "sock=%d eloop_data=%p user_data=%p "
536 : "handler=%p",
537 0 : table->table[i].sock,
538 0 : table->table[i].eloop_data,
539 0 : table->table[i].user_data,
540 0 : table->table[i].handler);
541 0 : wpa_trace_dump_funcname("eloop unregistered socket "
542 : "handler",
543 0 : table->table[i].handler);
544 0 : wpa_trace_dump("eloop sock", &table->table[i]);
545 : }
546 18 : os_free(table->table);
547 : }
548 18 : }
549 :
550 :
551 6648 : int eloop_register_read_sock(int sock, eloop_sock_handler handler,
552 : void *eloop_data, void *user_data)
553 : {
554 6648 : return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
555 : eloop_data, user_data);
556 : }
557 :
558 :
559 6649 : void eloop_unregister_read_sock(int sock)
560 : {
561 6649 : eloop_unregister_sock(sock, EVENT_TYPE_READ);
562 6649 : }
563 :
564 :
565 14822 : static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
566 : {
567 14822 : switch (type) {
568 : case EVENT_TYPE_READ:
569 14370 : return &eloop.readers;
570 : case EVENT_TYPE_WRITE:
571 452 : return &eloop.writers;
572 : case EVENT_TYPE_EXCEPTION:
573 0 : return &eloop.exceptions;
574 : }
575 :
576 0 : return NULL;
577 : }
578 :
579 :
580 7176 : int eloop_register_sock(int sock, eloop_event_type type,
581 : eloop_sock_handler handler,
582 : void *eloop_data, void *user_data)
583 : {
584 : struct eloop_sock_table *table;
585 :
586 7176 : assert(sock >= 0);
587 7176 : table = eloop_get_sock_table(type);
588 7176 : return eloop_sock_table_add_sock(table, sock, handler,
589 : eloop_data, user_data);
590 : }
591 :
592 :
593 7646 : void eloop_unregister_sock(int sock, eloop_event_type type)
594 : {
595 : struct eloop_sock_table *table;
596 :
597 7646 : table = eloop_get_sock_table(type);
598 7646 : eloop_sock_table_remove_sock(table, sock);
599 7646 : }
600 :
601 :
602 48528 : int eloop_register_timeout(unsigned int secs, unsigned int usecs,
603 : eloop_timeout_handler handler,
604 : void *eloop_data, void *user_data)
605 : {
606 : struct eloop_timeout *timeout, *tmp;
607 : os_time_t now_sec;
608 :
609 48528 : timeout = os_zalloc(sizeof(*timeout));
610 48528 : if (timeout == NULL)
611 0 : return -1;
612 48528 : if (os_get_reltime(&timeout->time) < 0) {
613 0 : os_free(timeout);
614 0 : return -1;
615 : }
616 48528 : now_sec = timeout->time.sec;
617 48528 : timeout->time.sec += secs;
618 48528 : if (timeout->time.sec < now_sec) {
619 : /*
620 : * Integer overflow - assume long enough timeout to be assumed
621 : * to be infinite, i.e., the timeout would never happen.
622 : */
623 0 : wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
624 : "ever happen - ignore it", secs);
625 0 : os_free(timeout);
626 0 : return 0;
627 : }
628 48528 : timeout->time.usec += usecs;
629 98844 : while (timeout->time.usec >= 1000000) {
630 1788 : timeout->time.sec++;
631 1788 : timeout->time.usec -= 1000000;
632 : }
633 48528 : timeout->eloop_data = eloop_data;
634 48528 : timeout->user_data = user_data;
635 48528 : timeout->handler = handler;
636 48528 : wpa_trace_add_ref(timeout, eloop, eloop_data);
637 48528 : wpa_trace_add_ref(timeout, user, user_data);
638 48528 : wpa_trace_record(timeout);
639 :
640 : /* Maintain timeouts in order of increasing time */
641 132038 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
642 125692 : if (os_reltime_before(&timeout->time, &tmp->time)) {
643 42182 : dl_list_add(tmp->list.prev, &timeout->list);
644 42182 : return 0;
645 : }
646 : }
647 6346 : dl_list_add_tail(&eloop.timeout, &timeout->list);
648 :
649 6346 : return 0;
650 : }
651 :
652 :
653 48528 : static void eloop_remove_timeout(struct eloop_timeout *timeout)
654 : {
655 48528 : dl_list_del(&timeout->list);
656 48528 : wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
657 48528 : wpa_trace_remove_ref(timeout, user, timeout->user_data);
658 48528 : os_free(timeout);
659 48528 : }
660 :
661 :
662 125371 : int eloop_cancel_timeout(eloop_timeout_handler handler,
663 : void *eloop_data, void *user_data)
664 : {
665 : struct eloop_timeout *timeout, *prev;
666 125371 : int removed = 0;
667 :
668 724649 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
669 : struct eloop_timeout, list) {
670 637288 : if (timeout->handler == handler &&
671 40918 : (timeout->eloop_data == eloop_data ||
672 35102 : eloop_data == ELOOP_ALL_CTX) &&
673 46556 : (timeout->user_data == user_data ||
674 : user_data == ELOOP_ALL_CTX)) {
675 23668 : eloop_remove_timeout(timeout);
676 23668 : removed++;
677 : }
678 : }
679 :
680 125371 : return removed;
681 : }
682 :
683 :
684 2 : int eloop_cancel_timeout_one(eloop_timeout_handler handler,
685 : void *eloop_data, void *user_data,
686 : struct os_reltime *remaining)
687 : {
688 : struct eloop_timeout *timeout, *prev;
689 2 : int removed = 0;
690 : struct os_reltime now;
691 :
692 2 : os_get_reltime(&now);
693 2 : remaining->sec = remaining->usec = 0;
694 :
695 4 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
696 : struct eloop_timeout, list) {
697 4 : if (timeout->handler == handler &&
698 2 : (timeout->eloop_data == eloop_data) &&
699 1 : (timeout->user_data == user_data)) {
700 1 : removed = 1;
701 1 : if (os_reltime_before(&now, &timeout->time))
702 1 : os_reltime_sub(&timeout->time, &now, remaining);
703 1 : eloop_remove_timeout(timeout);
704 1 : break;
705 : }
706 : }
707 2 : return removed;
708 : }
709 :
710 :
711 1061 : int eloop_is_timeout_registered(eloop_timeout_handler handler,
712 : void *eloop_data, void *user_data)
713 : {
714 : struct eloop_timeout *tmp;
715 :
716 6772 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
717 5715 : if (tmp->handler == handler &&
718 4 : tmp->eloop_data == eloop_data &&
719 2 : tmp->user_data == user_data)
720 2 : return 1;
721 : }
722 :
723 1059 : return 0;
724 : }
725 :
726 :
727 3316 : int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
728 : eloop_timeout_handler handler, void *eloop_data,
729 : void *user_data)
730 : {
731 : struct os_reltime now, requested, remaining;
732 : struct eloop_timeout *tmp;
733 :
734 14630 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
735 13276 : if (tmp->handler == handler &&
736 1962 : tmp->eloop_data == eloop_data &&
737 981 : tmp->user_data == user_data) {
738 981 : requested.sec = req_secs;
739 981 : requested.usec = req_usecs;
740 981 : os_get_reltime(&now);
741 981 : os_reltime_sub(&tmp->time, &now, &remaining);
742 981 : if (os_reltime_before(&requested, &remaining)) {
743 103 : eloop_cancel_timeout(handler, eloop_data,
744 : user_data);
745 103 : eloop_register_timeout(requested.sec,
746 103 : requested.usec,
747 : handler, eloop_data,
748 : user_data);
749 103 : return 1;
750 : }
751 878 : return 0;
752 : }
753 : }
754 :
755 2335 : return -1;
756 : }
757 :
758 :
759 9 : int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
760 : eloop_timeout_handler handler, void *eloop_data,
761 : void *user_data)
762 : {
763 : struct os_reltime now, requested, remaining;
764 : struct eloop_timeout *tmp;
765 :
766 17 : dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
767 24 : if (tmp->handler == handler &&
768 16 : tmp->eloop_data == eloop_data &&
769 8 : tmp->user_data == user_data) {
770 8 : requested.sec = req_secs;
771 8 : requested.usec = req_usecs;
772 8 : os_get_reltime(&now);
773 8 : os_reltime_sub(&tmp->time, &now, &remaining);
774 8 : if (os_reltime_before(&remaining, &requested)) {
775 8 : eloop_cancel_timeout(handler, eloop_data,
776 : user_data);
777 8 : eloop_register_timeout(requested.sec,
778 8 : requested.usec,
779 : handler, eloop_data,
780 : user_data);
781 8 : return 1;
782 : }
783 0 : return 0;
784 : }
785 : }
786 :
787 1 : return -1;
788 : }
789 :
790 :
791 : #ifndef CONFIG_NATIVE_WINDOWS
792 0 : static void eloop_handle_alarm(int sig)
793 : {
794 0 : wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
795 : "two seconds. Looks like there\n"
796 : "is a bug that ends up in a busy loop that "
797 : "prevents clean shutdown.\n"
798 : "Killing program forcefully.\n");
799 0 : exit(1);
800 : }
801 : #endif /* CONFIG_NATIVE_WINDOWS */
802 :
803 :
804 6 : static void eloop_handle_signal(int sig)
805 : {
806 : int i;
807 :
808 : #ifndef CONFIG_NATIVE_WINDOWS
809 6 : if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
810 : /* Use SIGALRM to break out from potential busy loops that
811 : * would not allow the program to be killed. */
812 6 : eloop.pending_terminate = 1;
813 6 : signal(SIGALRM, eloop_handle_alarm);
814 6 : alarm(2);
815 : }
816 : #endif /* CONFIG_NATIVE_WINDOWS */
817 :
818 6 : eloop.signaled++;
819 16 : for (i = 0; i < eloop.signal_count; i++) {
820 16 : if (eloop.signals[i].sig == sig) {
821 6 : eloop.signals[i].signaled++;
822 6 : break;
823 : }
824 : }
825 6 : }
826 :
827 :
828 233497 : static void eloop_process_pending_signals(void)
829 : {
830 : int i;
831 :
832 233497 : if (eloop.signaled == 0)
833 466988 : return;
834 6 : eloop.signaled = 0;
835 :
836 6 : if (eloop.pending_terminate) {
837 : #ifndef CONFIG_NATIVE_WINDOWS
838 6 : alarm(0);
839 : #endif /* CONFIG_NATIVE_WINDOWS */
840 6 : eloop.pending_terminate = 0;
841 : }
842 :
843 26 : for (i = 0; i < eloop.signal_count; i++) {
844 20 : if (eloop.signals[i].signaled) {
845 6 : eloop.signals[i].signaled = 0;
846 12 : eloop.signals[i].handler(eloop.signals[i].sig,
847 6 : eloop.signals[i].user_data);
848 : }
849 : }
850 : }
851 :
852 :
853 20 : int eloop_register_signal(int sig, eloop_signal_handler handler,
854 : void *user_data)
855 : {
856 : struct eloop_signal *tmp;
857 :
858 20 : tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
859 : sizeof(struct eloop_signal));
860 20 : if (tmp == NULL)
861 0 : return -1;
862 :
863 20 : tmp[eloop.signal_count].sig = sig;
864 20 : tmp[eloop.signal_count].user_data = user_data;
865 20 : tmp[eloop.signal_count].handler = handler;
866 20 : tmp[eloop.signal_count].signaled = 0;
867 20 : eloop.signal_count++;
868 20 : eloop.signals = tmp;
869 20 : signal(sig, eloop_handle_signal);
870 :
871 20 : return 0;
872 : }
873 :
874 :
875 6 : int eloop_register_signal_terminate(eloop_signal_handler handler,
876 : void *user_data)
877 : {
878 6 : int ret = eloop_register_signal(SIGINT, handler, user_data);
879 6 : if (ret == 0)
880 6 : ret = eloop_register_signal(SIGTERM, handler, user_data);
881 6 : return ret;
882 : }
883 :
884 :
885 4 : int eloop_register_signal_reconfig(eloop_signal_handler handler,
886 : void *user_data)
887 : {
888 : #ifdef CONFIG_NATIVE_WINDOWS
889 : return 0;
890 : #else /* CONFIG_NATIVE_WINDOWS */
891 4 : return eloop_register_signal(SIGHUP, handler, user_data);
892 : #endif /* CONFIG_NATIVE_WINDOWS */
893 : }
894 :
895 :
896 6 : void eloop_run(void)
897 : {
898 : #ifdef CONFIG_ELOOP_POLL
899 : int num_poll_fds;
900 : int timeout_ms = 0;
901 : #endif /* CONFIG_ELOOP_POLL */
902 : #ifdef CONFIG_ELOOP_SELECT
903 : fd_set *rfds, *wfds, *efds;
904 : struct timeval _tv;
905 : #endif /* CONFIG_ELOOP_SELECT */
906 : #ifdef CONFIG_ELOOP_EPOLL
907 : int timeout_ms = -1;
908 : #endif /* CONFIG_ELOOP_EPOLL */
909 : int res;
910 : struct os_reltime tv, now;
911 :
912 : #ifdef CONFIG_ELOOP_SELECT
913 6 : rfds = os_malloc(sizeof(*rfds));
914 6 : wfds = os_malloc(sizeof(*wfds));
915 6 : efds = os_malloc(sizeof(*efds));
916 6 : if (rfds == NULL || wfds == NULL || efds == NULL)
917 : goto out;
918 : #endif /* CONFIG_ELOOP_SELECT */
919 :
920 467006 : while (!eloop.terminate &&
921 281819 : (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
922 0 : eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
923 : struct eloop_timeout *timeout;
924 233497 : timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
925 : list);
926 233497 : if (timeout) {
927 185175 : os_get_reltime(&now);
928 185175 : if (os_reltime_before(&now, &timeout->time))
929 165611 : os_reltime_sub(&timeout->time, &now, &tv);
930 : else
931 19564 : tv.sec = tv.usec = 0;
932 : #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
933 : timeout_ms = tv.sec * 1000 + tv.usec / 1000;
934 : #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
935 : #ifdef CONFIG_ELOOP_SELECT
936 185175 : _tv.tv_sec = tv.sec;
937 185175 : _tv.tv_usec = tv.usec;
938 : #endif /* CONFIG_ELOOP_SELECT */
939 : }
940 :
941 : #ifdef CONFIG_ELOOP_POLL
942 : num_poll_fds = eloop_sock_table_set_fds(
943 : &eloop.readers, &eloop.writers, &eloop.exceptions,
944 : eloop.pollfds, eloop.pollfds_map,
945 : eloop.max_pollfd_map);
946 : res = poll(eloop.pollfds, num_poll_fds,
947 : timeout ? timeout_ms : -1);
948 : #endif /* CONFIG_ELOOP_POLL */
949 : #ifdef CONFIG_ELOOP_SELECT
950 233497 : eloop_sock_table_set_fds(&eloop.readers, rfds);
951 233497 : eloop_sock_table_set_fds(&eloop.writers, wfds);
952 233497 : eloop_sock_table_set_fds(&eloop.exceptions, efds);
953 233497 : res = select(eloop.max_sock + 1, rfds, wfds, efds,
954 : timeout ? &_tv : NULL);
955 : #endif /* CONFIG_ELOOP_SELECT */
956 : #ifdef CONFIG_ELOOP_EPOLL
957 : if (eloop.count == 0) {
958 : res = 0;
959 : } else {
960 : res = epoll_wait(eloop.epollfd, eloop.epoll_events,
961 : eloop.count, timeout_ms);
962 : }
963 : #endif /* CONFIG_ELOOP_EPOLL */
964 233497 : if (res < 0 && errno != EINTR && errno != 0) {
965 0 : wpa_printf(MSG_ERROR, "eloop: %s: %s",
966 : #ifdef CONFIG_ELOOP_POLL
967 : "poll"
968 : #endif /* CONFIG_ELOOP_POLL */
969 : #ifdef CONFIG_ELOOP_SELECT
970 : "select"
971 : #endif /* CONFIG_ELOOP_SELECT */
972 : #ifdef CONFIG_ELOOP_EPOLL
973 : "epoll"
974 : #endif /* CONFIG_ELOOP_EPOLL */
975 0 : , strerror(errno));
976 0 : goto out;
977 : }
978 233497 : eloop_process_pending_signals();
979 :
980 : /* check if some registered timeouts have occurred */
981 233497 : timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
982 : list);
983 233497 : if (timeout) {
984 185175 : os_get_reltime(&now);
985 185175 : if (!os_reltime_before(&now, &timeout->time)) {
986 24859 : void *eloop_data = timeout->eloop_data;
987 24859 : void *user_data = timeout->user_data;
988 24859 : eloop_timeout_handler handler =
989 : timeout->handler;
990 24859 : eloop_remove_timeout(timeout);
991 24859 : handler(eloop_data, user_data);
992 : }
993 :
994 : }
995 :
996 233497 : if (res <= 0)
997 20193 : continue;
998 :
999 : #ifdef CONFIG_ELOOP_POLL
1000 : eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
1001 : &eloop.exceptions, eloop.pollfds_map,
1002 : eloop.max_pollfd_map);
1003 : #endif /* CONFIG_ELOOP_POLL */
1004 : #ifdef CONFIG_ELOOP_SELECT
1005 213304 : eloop_sock_table_dispatch(&eloop.readers, rfds);
1006 213304 : eloop_sock_table_dispatch(&eloop.writers, wfds);
1007 213304 : eloop_sock_table_dispatch(&eloop.exceptions, efds);
1008 : #endif /* CONFIG_ELOOP_SELECT */
1009 : #ifdef CONFIG_ELOOP_EPOLL
1010 : eloop_sock_table_dispatch(eloop.epoll_events, res);
1011 : #endif /* CONFIG_ELOOP_EPOLL */
1012 : }
1013 :
1014 6 : eloop.terminate = 0;
1015 : out:
1016 : #ifdef CONFIG_ELOOP_SELECT
1017 6 : os_free(rfds);
1018 6 : os_free(wfds);
1019 6 : os_free(efds);
1020 : #endif /* CONFIG_ELOOP_SELECT */
1021 6 : return;
1022 : }
1023 :
1024 :
1025 6 : void eloop_terminate(void)
1026 : {
1027 6 : eloop.terminate = 1;
1028 6 : }
1029 :
1030 :
1031 6 : void eloop_destroy(void)
1032 : {
1033 : struct eloop_timeout *timeout, *prev;
1034 : struct os_reltime now;
1035 :
1036 6 : os_get_reltime(&now);
1037 6 : dl_list_for_each_safe(timeout, prev, &eloop.timeout,
1038 : struct eloop_timeout, list) {
1039 : int sec, usec;
1040 0 : sec = timeout->time.sec - now.sec;
1041 0 : usec = timeout->time.usec - now.usec;
1042 0 : if (timeout->time.usec < now.usec) {
1043 0 : sec--;
1044 0 : usec += 1000000;
1045 : }
1046 0 : wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
1047 : "eloop_data=%p user_data=%p handler=%p",
1048 : sec, usec, timeout->eloop_data, timeout->user_data,
1049 : timeout->handler);
1050 0 : wpa_trace_dump_funcname("eloop unregistered timeout handler",
1051 0 : timeout->handler);
1052 0 : wpa_trace_dump("eloop timeout", timeout);
1053 0 : eloop_remove_timeout(timeout);
1054 : }
1055 6 : eloop_sock_table_destroy(&eloop.readers);
1056 6 : eloop_sock_table_destroy(&eloop.writers);
1057 6 : eloop_sock_table_destroy(&eloop.exceptions);
1058 6 : os_free(eloop.signals);
1059 :
1060 : #ifdef CONFIG_ELOOP_POLL
1061 : os_free(eloop.pollfds);
1062 : os_free(eloop.pollfds_map);
1063 : #endif /* CONFIG_ELOOP_POLL */
1064 : #ifdef CONFIG_ELOOP_EPOLL
1065 : os_free(eloop.epoll_table);
1066 : os_free(eloop.epoll_events);
1067 : close(eloop.epollfd);
1068 : #endif /* CONFIG_ELOOP_EPOLL */
1069 6 : }
1070 :
1071 :
1072 1924 : int eloop_terminated(void)
1073 : {
1074 1924 : return eloop.terminate;
1075 : }
1076 :
1077 :
1078 0 : void eloop_wait_for_read_sock(int sock)
1079 : {
1080 : #ifdef CONFIG_ELOOP_POLL
1081 : struct pollfd pfd;
1082 :
1083 : if (sock < 0)
1084 : return;
1085 :
1086 : os_memset(&pfd, 0, sizeof(pfd));
1087 : pfd.fd = sock;
1088 : pfd.events = POLLIN;
1089 :
1090 : poll(&pfd, 1, -1);
1091 : #endif /* CONFIG_ELOOP_POLL */
1092 : #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
1093 : /*
1094 : * We can use epoll() here. But epoll() requres 4 system calls.
1095 : * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
1096 : * epoll fd. So select() is better for performance here.
1097 : */
1098 : fd_set rfds;
1099 :
1100 0 : if (sock < 0)
1101 0 : return;
1102 :
1103 0 : FD_ZERO(&rfds);
1104 0 : FD_SET(sock, &rfds);
1105 0 : select(sock + 1, &rfds, NULL, NULL, NULL);
1106 : #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
1107 : }
1108 :
1109 : #ifdef CONFIG_ELOOP_SELECT
1110 : #undef CONFIG_ELOOP_SELECT
1111 : #endif /* CONFIG_ELOOP_SELECT */
|