LCOV - code coverage report
Current view: top level - src/utils - eloop.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 277 323 85.8 %
Date: 2014-05-28 Functions: 29 32 90.6 %

          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 */

Generated by: LCOV version 1.10