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 1422976643 Lines: 281 324 86.7 %
Date: 2015-02-03 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       32140 : static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
     114             : {
     115             :         int i;
     116       32140 :         if (table == NULL || table->table == NULL)
     117       32140 :                 return;
     118      346480 :         for (i = 0; i < table->count; i++) {
     119      314340 :                 wpa_trace_add_ref(&table->table[i], eloop,
     120             :                                   table->table[i].eloop_data);
     121      314340 :                 wpa_trace_add_ref(&table->table[i], user,
     122             :                                   table->table[i].user_data);
     123             :         }
     124             : }
     125             : 
     126             : 
     127       32140 : static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
     128             : {
     129             :         int i;
     130       32140 :         if (table == NULL || table->table == NULL)
     131       32185 :                 return;
     132      346435 :         for (i = 0; i < table->count; i++) {
     133      314340 :                 wpa_trace_remove_ref(&table->table[i], eloop,
     134             :                                      table->table[i].eloop_data);
     135      314340 :                 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          65 : int eloop_init(void)
     149             : {
     150          65 :         os_memset(&eloop, 0, sizeof(eloop));
     151          65 :         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          65 :         signal(SIGSEGV, eloop_sigsegv_handler);
     165             : #endif /* WPA_TRACE */
     166          65 :         return 0;
     167             : }
     168             : 
     169             : 
     170       16072 : 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       16072 :         if (sock > eloop.max_sock)
     183         529 :                 new_max_sock = sock;
     184             :         else
     185       15543 :                 new_max_sock = eloop.max_sock;
     186             : 
     187       16072 :         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       16072 :         eloop_trace_sock_remove_ref(table);
     243       16072 :         tmp = os_realloc_array(table->table, table->count + 1,
     244             :                                sizeof(struct eloop_sock));
     245       16072 :         if (tmp == NULL) {
     246           4 :                 eloop_trace_sock_add_ref(table);
     247           4 :                 return -1;
     248             :         }
     249             : 
     250       16068 :         tmp[table->count].sock = sock;
     251       16068 :         tmp[table->count].eloop_data = eloop_data;
     252       16068 :         tmp[table->count].user_data = user_data;
     253       16068 :         tmp[table->count].handler = handler;
     254       16068 :         wpa_trace_record(&tmp[table->count]);
     255       16068 :         table->count++;
     256       16068 :         table->table = tmp;
     257       16068 :         eloop.max_sock = new_max_sock;
     258       16068 :         eloop.count++;
     259             : #ifndef CONFIG_ELOOP_EPOLL
     260       16068 :         table->changed = 1;
     261             : #endif /* CONFIG_ELOOP_EPOLL */
     262       16068 :         eloop_trace_sock_add_ref(table);
     263             : 
     264             : #ifdef CONFIG_ELOOP_EPOLL
     265             :         os_memset(&ev, 0, sizeof(ev));
     266             :         switch (table->type) {
     267             :         case EVENT_TYPE_READ:
     268             :                 ev.events = EPOLLIN;
     269             :                 break;
     270             :         case EVENT_TYPE_WRITE:
     271             :                 ev.events = EPOLLOUT;
     272             :                 break;
     273             :         /*
     274             :          * Exceptions are always checked when using epoll, but I suppose it's
     275             :          * possible that someone registered a socket *only* for exception
     276             :          * handling.
     277             :          */
     278             :         case EVENT_TYPE_EXCEPTION:
     279             :                 ev.events = EPOLLERR | EPOLLHUP;
     280             :                 break;
     281             :         }
     282             :         ev.data.fd = sock;
     283             :         if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
     284             :                 wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d "
     285             :                            "failed. %s\n", __func__, sock, strerror(errno));
     286             :                 return -1;
     287             :         }
     288             :         os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1],
     289             :                   sizeof(struct eloop_sock));
     290             : #endif /* CONFIG_ELOOP_EPOLL */
     291       16068 :         return 0;
     292             : }
     293             : 
     294             : 
     295       16564 : static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
     296             :                                          int sock)
     297             : {
     298             :         int i;
     299             : 
     300       16564 :         if (table == NULL || table->table == NULL || table->count == 0)
     301         165 :                 return;
     302             : 
     303      148115 :         for (i = 0; i < table->count; i++) {
     304      147784 :                 if (table->table[i].sock == sock)
     305       16068 :                         break;
     306             :         }
     307       16399 :         if (i == table->count)
     308         331 :                 return;
     309       16068 :         eloop_trace_sock_remove_ref(table);
     310       16068 :         if (i != table->count - 1) {
     311        6460 :                 os_memmove(&table->table[i], &table->table[i + 1],
     312             :                            (table->count - i - 1) *
     313             :                            sizeof(struct eloop_sock));
     314             :         }
     315       16068 :         table->count--;
     316       16068 :         eloop.count--;
     317             : #ifndef CONFIG_ELOOP_EPOLL
     318       16068 :         table->changed = 1;
     319             : #endif /* CONFIG_ELOOP_EPOLL */
     320       16068 :         eloop_trace_sock_add_ref(table);
     321             : #ifdef CONFIG_ELOOP_EPOLL
     322             :         if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) {
     323             :                 wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d "
     324             :                            "failed. %s\n", __func__, sock, strerror(errno));
     325             :                 return;
     326             :         }
     327             :         os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock));
     328             : #endif /* CONFIG_ELOOP_EPOLL */
     329             : }
     330             : 
     331             : 
     332             : #ifdef CONFIG_ELOOP_POLL
     333             : 
     334             : static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
     335             : {
     336             :         if (fd < mx && fd >= 0)
     337             :                 return pollfds_map[fd];
     338             :         return NULL;
     339             : }
     340             : 
     341             : 
     342             : static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
     343             :                                     struct eloop_sock_table *writers,
     344             :                                     struct eloop_sock_table *exceptions,
     345             :                                     struct pollfd *pollfds,
     346             :                                     struct pollfd **pollfds_map,
     347             :                                     int max_pollfd_map)
     348             : {
     349             :         int i;
     350             :         int nxt = 0;
     351             :         int fd;
     352             :         struct pollfd *pfd;
     353             : 
     354             :         /* Clear pollfd lookup map. It will be re-populated below. */
     355             :         os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
     356             : 
     357             :         if (readers && readers->table) {
     358             :                 for (i = 0; i < readers->count; i++) {
     359             :                         fd = readers->table[i].sock;
     360             :                         assert(fd >= 0 && fd < max_pollfd_map);
     361             :                         pollfds[nxt].fd = fd;
     362             :                         pollfds[nxt].events = POLLIN;
     363             :                         pollfds[nxt].revents = 0;
     364             :                         pollfds_map[fd] = &(pollfds[nxt]);
     365             :                         nxt++;
     366             :                 }
     367             :         }
     368             : 
     369             :         if (writers && writers->table) {
     370             :                 for (i = 0; i < writers->count; i++) {
     371             :                         /*
     372             :                          * See if we already added this descriptor, update it
     373             :                          * if so.
     374             :                          */
     375             :                         fd = writers->table[i].sock;
     376             :                         assert(fd >= 0 && fd < max_pollfd_map);
     377             :                         pfd = pollfds_map[fd];
     378             :                         if (!pfd) {
     379             :                                 pfd = &(pollfds[nxt]);
     380             :                                 pfd->events = 0;
     381             :                                 pfd->fd = fd;
     382             :                                 pollfds[i].revents = 0;
     383             :                                 pollfds_map[fd] = pfd;
     384             :                                 nxt++;
     385             :                         }
     386             :                         pfd->events |= POLLOUT;
     387             :                 }
     388             :         }
     389             : 
     390             :         /*
     391             :          * Exceptions are always checked when using poll, but I suppose it's
     392             :          * possible that someone registered a socket *only* for exception
     393             :          * handling. Set the POLLIN bit in this case.
     394             :          */
     395             :         if (exceptions && exceptions->table) {
     396             :                 for (i = 0; i < exceptions->count; i++) {
     397             :                         /*
     398             :                          * See if we already added this descriptor, just use it
     399             :                          * if so.
     400             :                          */
     401             :                         fd = exceptions->table[i].sock;
     402             :                         assert(fd >= 0 && fd < max_pollfd_map);
     403             :                         pfd = pollfds_map[fd];
     404             :                         if (!pfd) {
     405             :                                 pfd = &(pollfds[nxt]);
     406             :                                 pfd->events = POLLIN;
     407             :                                 pfd->fd = fd;
     408             :                                 pollfds[i].revents = 0;
     409             :                                 pollfds_map[fd] = pfd;
     410             :                                 nxt++;
     411             :                         }
     412             :                 }
     413             :         }
     414             : 
     415             :         return nxt;
     416             : }
     417             : 
     418             : 
     419             : static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
     420             :                                            struct pollfd **pollfds_map,
     421             :                                            int max_pollfd_map,
     422             :                                            short int revents)
     423             : {
     424             :         int i;
     425             :         struct pollfd *pfd;
     426             : 
     427             :         if (!table || !table->table)
     428             :                 return 0;
     429             : 
     430             :         table->changed = 0;
     431             :         for (i = 0; i < table->count; i++) {
     432             :                 pfd = find_pollfd(pollfds_map, table->table[i].sock,
     433             :                                   max_pollfd_map);
     434             :                 if (!pfd)
     435             :                         continue;
     436             : 
     437             :                 if (!(pfd->revents & revents))
     438             :                         continue;
     439             : 
     440             :                 table->table[i].handler(table->table[i].sock,
     441             :                                         table->table[i].eloop_data,
     442             :                                         table->table[i].user_data);
     443             :                 if (table->changed)
     444             :                         return 1;
     445             :         }
     446             : 
     447             :         return 0;
     448             : }
     449             : 
     450             : 
     451             : static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
     452             :                                       struct eloop_sock_table *writers,
     453             :                                       struct eloop_sock_table *exceptions,
     454             :                                       struct pollfd **pollfds_map,
     455             :                                       int max_pollfd_map)
     456             : {
     457             :         if (eloop_sock_table_dispatch_table(readers, pollfds_map,
     458             :                                             max_pollfd_map, POLLIN | POLLERR |
     459             :                                             POLLHUP))
     460             :                 return; /* pollfds may be invalid at this point */
     461             : 
     462             :         if (eloop_sock_table_dispatch_table(writers, pollfds_map,
     463             :                                             max_pollfd_map, POLLOUT))
     464             :                 return; /* pollfds may be invalid at this point */
     465             : 
     466             :         eloop_sock_table_dispatch_table(exceptions, pollfds_map,
     467             :                                         max_pollfd_map, POLLERR | POLLHUP);
     468             : }
     469             : 
     470             : #endif /* CONFIG_ELOOP_POLL */
     471             : 
     472             : #ifdef CONFIG_ELOOP_SELECT
     473             : 
     474     1386477 : static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
     475             :                                      fd_set *fds)
     476             : {
     477             :         int i;
     478             : 
     479     1386477 :         FD_ZERO(fds);
     480             : 
     481     1386477 :         if (table->table == NULL)
     482     2034265 :                 return;
     483             : 
     484     5179354 :         for (i = 0; i < table->count; i++) {
     485     4440665 :                 assert(table->table[i].sock >= 0);
     486     4440665 :                 FD_SET(table->table[i].sock, fds);
     487             :         }
     488             : }
     489             : 
     490             : 
     491     1237629 : static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
     492             :                                       fd_set *fds)
     493             : {
     494             :         int i;
     495             : 
     496     1237629 :         if (table == NULL || table->table == NULL)
     497     1829453 :                 return;
     498             : 
     499      645805 :         table->changed = 0;
     500     4441531 :         for (i = 0; i < table->count; i++) {
     501     3804146 :                 if (FD_ISSET(table->table[i].sock, fds)) {
     502     1470642 :                         table->table[i].handler(table->table[i].sock,
     503      490214 :                                                 table->table[i].eloop_data,
     504      490214 :                                                 table->table[i].user_data);
     505      490214 :                         if (table->changed)
     506        8420 :                                 break;
     507             :                 }
     508             :         }
     509             : }
     510             : 
     511             : #endif /* CONFIG_ELOOP_SELECT */
     512             : 
     513             : 
     514             : #ifdef CONFIG_ELOOP_EPOLL
     515             : static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds)
     516             : {
     517             :         struct eloop_sock *table;
     518             :         int i;
     519             : 
     520             :         for (i = 0; i < nfds; i++) {
     521             :                 table = &eloop.epoll_table[events[i].data.fd];
     522             :                 if (table->handler == NULL)
     523             :                         continue;
     524             :                 table->handler(table->sock, table->eloop_data,
     525             :                                table->user_data);
     526             :         }
     527             : }
     528             : #endif /* CONFIG_ELOOP_EPOLL */
     529             : 
     530             : 
     531         195 : static void eloop_sock_table_destroy(struct eloop_sock_table *table)
     532             : {
     533         195 :         if (table) {
     534             :                 int i;
     535         195 :                 for (i = 0; i < table->count && table->table; i++) {
     536           0 :                         wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
     537             :                                    "sock=%d eloop_data=%p user_data=%p "
     538             :                                    "handler=%p",
     539           0 :                                    table->table[i].sock,
     540           0 :                                    table->table[i].eloop_data,
     541           0 :                                    table->table[i].user_data,
     542           0 :                                    table->table[i].handler);
     543           0 :                         wpa_trace_dump_funcname("eloop unregistered socket "
     544             :                                                 "handler",
     545           0 :                                                 table->table[i].handler);
     546           0 :                         wpa_trace_dump("eloop sock", &table->table[i]);
     547             :                 }
     548         195 :                 os_free(table->table);
     549             :         }
     550         195 : }
     551             : 
     552             : 
     553       15512 : int eloop_register_read_sock(int sock, eloop_sock_handler handler,
     554             :                              void *eloop_data, void *user_data)
     555             : {
     556       15512 :         return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
     557             :                                    eloop_data, user_data);
     558             : }
     559             : 
     560             : 
     561       15512 : void eloop_unregister_read_sock(int sock)
     562             : {
     563       15512 :         eloop_unregister_sock(sock, EVENT_TYPE_READ);
     564       15512 : }
     565             : 
     566             : 
     567       32636 : static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
     568             : {
     569       32636 :         switch (type) {
     570             :         case EVENT_TYPE_READ:
     571       32147 :                 return &eloop.readers;
     572             :         case EVENT_TYPE_WRITE:
     573         474 :                 return &eloop.writers;
     574             :         case EVENT_TYPE_EXCEPTION:
     575          15 :                 return &eloop.exceptions;
     576             :         }
     577             : 
     578           0 :         return NULL;
     579             : }
     580             : 
     581             : 
     582       16072 : int eloop_register_sock(int sock, eloop_event_type type,
     583             :                         eloop_sock_handler handler,
     584             :                         void *eloop_data, void *user_data)
     585             : {
     586             :         struct eloop_sock_table *table;
     587             : 
     588       16072 :         assert(sock >= 0);
     589       16072 :         table = eloop_get_sock_table(type);
     590       16072 :         return eloop_sock_table_add_sock(table, sock, handler,
     591             :                                          eloop_data, user_data);
     592             : }
     593             : 
     594             : 
     595       16564 : void eloop_unregister_sock(int sock, eloop_event_type type)
     596             : {
     597             :         struct eloop_sock_table *table;
     598             : 
     599       16564 :         table = eloop_get_sock_table(type);
     600       16564 :         eloop_sock_table_remove_sock(table, sock);
     601       16564 : }
     602             : 
     603             : 
     604      114598 : int eloop_register_timeout(unsigned int secs, unsigned int usecs,
     605             :                            eloop_timeout_handler handler,
     606             :                            void *eloop_data, void *user_data)
     607             : {
     608             :         struct eloop_timeout *timeout, *tmp;
     609             :         os_time_t now_sec;
     610             : 
     611      114598 :         timeout = os_zalloc(sizeof(*timeout));
     612      114598 :         if (timeout == NULL)
     613          34 :                 return -1;
     614      114564 :         if (os_get_reltime(&timeout->time) < 0) {
     615           0 :                 os_free(timeout);
     616           0 :                 return -1;
     617             :         }
     618      114564 :         now_sec = timeout->time.sec;
     619      114564 :         timeout->time.sec += secs;
     620      114564 :         if (timeout->time.sec < now_sec) {
     621             :                 /*
     622             :                  * Integer overflow - assume long enough timeout to be assumed
     623             :                  * to be infinite, i.e., the timeout would never happen.
     624             :                  */
     625           0 :                 wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
     626             :                            "ever happen - ignore it", secs);
     627           0 :                 os_free(timeout);
     628           0 :                 return 0;
     629             :         }
     630      114564 :         timeout->time.usec += usecs;
     631      233174 :         while (timeout->time.usec >= 1000000) {
     632        4046 :                 timeout->time.sec++;
     633        4046 :                 timeout->time.usec -= 1000000;
     634             :         }
     635      114564 :         timeout->eloop_data = eloop_data;
     636      114564 :         timeout->user_data = user_data;
     637      114564 :         timeout->handler = handler;
     638      114564 :         wpa_trace_add_ref(timeout, eloop, eloop_data);
     639      114564 :         wpa_trace_add_ref(timeout, user, user_data);
     640      114564 :         wpa_trace_record(timeout);
     641             : 
     642             :         /* Maintain timeouts in order of increasing time */
     643      334907 :         dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
     644      322277 :                 if (os_reltime_before(&timeout->time, &tmp->time)) {
     645      101934 :                         dl_list_add(tmp->list.prev, &timeout->list);
     646      101934 :                         return 0;
     647             :                 }
     648             :         }
     649       12630 :         dl_list_add_tail(&eloop.timeout, &timeout->list);
     650             : 
     651       12630 :         return 0;
     652             : }
     653             : 
     654             : 
     655      114564 : static void eloop_remove_timeout(struct eloop_timeout *timeout)
     656             : {
     657      114564 :         dl_list_del(&timeout->list);
     658      114564 :         wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
     659      114564 :         wpa_trace_remove_ref(timeout, user, timeout->user_data);
     660      114564 :         os_free(timeout);
     661      114564 : }
     662             : 
     663             : 
     664      277602 : int eloop_cancel_timeout(eloop_timeout_handler handler,
     665             :                          void *eloop_data, void *user_data)
     666             : {
     667             :         struct eloop_timeout *timeout, *prev;
     668      277602 :         int removed = 0;
     669             : 
     670     1875069 :         dl_list_for_each_safe(timeout, prev, &eloop.timeout,
     671             :                               struct eloop_timeout, list) {
     672     1679755 :                 if (timeout->handler == handler &&
     673       85960 :                     (timeout->eloop_data == eloop_data ||
     674       78622 :                      eloop_data == ELOOP_ALL_CTX) &&
     675      106975 :                     (timeout->user_data == user_data ||
     676             :                      user_data == ELOOP_ALL_CTX)) {
     677       50270 :                         eloop_remove_timeout(timeout);
     678       50270 :                         removed++;
     679             :                 }
     680             :         }
     681             : 
     682      277602 :         return removed;
     683             : }
     684             : 
     685             : 
     686          19 : int eloop_cancel_timeout_one(eloop_timeout_handler handler,
     687             :                              void *eloop_data, void *user_data,
     688             :                              struct os_reltime *remaining)
     689             : {
     690             :         struct eloop_timeout *timeout, *prev;
     691          19 :         int removed = 0;
     692             :         struct os_reltime now;
     693             : 
     694          19 :         os_get_reltime(&now);
     695          19 :         remaining->sec = remaining->usec = 0;
     696             : 
     697          50 :         dl_list_for_each_safe(timeout, prev, &eloop.timeout,
     698             :                               struct eloop_timeout, list) {
     699          43 :                 if (timeout->handler == handler &&
     700          12 :                     (timeout->eloop_data == eloop_data) &&
     701           6 :                     (timeout->user_data == user_data)) {
     702           6 :                         removed = 1;
     703           6 :                         if (os_reltime_before(&now, &timeout->time))
     704           6 :                                 os_reltime_sub(&timeout->time, &now, remaining);
     705           6 :                         eloop_remove_timeout(timeout);
     706           6 :                         break;
     707             :                 }
     708             :         }
     709          19 :         return removed;
     710             : }
     711             : 
     712             : 
     713       31563 : int eloop_is_timeout_registered(eloop_timeout_handler handler,
     714             :                                 void *eloop_data, void *user_data)
     715             : {
     716             :         struct eloop_timeout *tmp;
     717             : 
     718      143681 :         dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
     719      141072 :                 if (tmp->handler == handler &&
     720       31926 :                     tmp->eloop_data == eloop_data &&
     721       15963 :                     tmp->user_data == user_data)
     722       12991 :                         return 1;
     723             :         }
     724             : 
     725       18572 :         return 0;
     726             : }
     727             : 
     728             : 
     729        5974 : int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
     730             :                           eloop_timeout_handler handler, void *eloop_data,
     731             :                           void *user_data)
     732             : {
     733             :         struct os_reltime now, requested, remaining;
     734             :         struct eloop_timeout *tmp;
     735             : 
     736       28170 :         dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
     737       25856 :                 if (tmp->handler == handler &&
     738        3660 :                     tmp->eloop_data == eloop_data &&
     739        1830 :                     tmp->user_data == user_data) {
     740        1830 :                         requested.sec = req_secs;
     741        1830 :                         requested.usec = req_usecs;
     742        1830 :                         os_get_reltime(&now);
     743        1830 :                         os_reltime_sub(&tmp->time, &now, &remaining);
     744        1830 :                         if (os_reltime_before(&requested, &remaining)) {
     745         127 :                                 eloop_cancel_timeout(handler, eloop_data,
     746             :                                                      user_data);
     747         127 :                                 eloop_register_timeout(requested.sec,
     748         127 :                                                        requested.usec,
     749             :                                                        handler, eloop_data,
     750             :                                                        user_data);
     751         127 :                                 return 1;
     752             :                         }
     753        1703 :                         return 0;
     754             :                 }
     755             :         }
     756             : 
     757        4144 :         return -1;
     758             : }
     759             : 
     760             : 
     761           9 : int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
     762             :                             eloop_timeout_handler handler, void *eloop_data,
     763             :                             void *user_data)
     764             : {
     765             :         struct os_reltime now, requested, remaining;
     766             :         struct eloop_timeout *tmp;
     767             : 
     768          17 :         dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
     769          24 :                 if (tmp->handler == handler &&
     770          16 :                     tmp->eloop_data == eloop_data &&
     771           8 :                     tmp->user_data == user_data) {
     772           8 :                         requested.sec = req_secs;
     773           8 :                         requested.usec = req_usecs;
     774           8 :                         os_get_reltime(&now);
     775           8 :                         os_reltime_sub(&tmp->time, &now, &remaining);
     776           8 :                         if (os_reltime_before(&remaining, &requested)) {
     777           8 :                                 eloop_cancel_timeout(handler, eloop_data,
     778             :                                                      user_data);
     779           8 :                                 eloop_register_timeout(requested.sec,
     780           8 :                                                        requested.usec,
     781             :                                                        handler, eloop_data,
     782             :                                                        user_data);
     783           8 :                                 return 1;
     784             :                         }
     785           0 :                         return 0;
     786             :                 }
     787             :         }
     788             : 
     789           1 :         return -1;
     790             : }
     791             : 
     792             : 
     793             : #ifndef CONFIG_NATIVE_WINDOWS
     794           0 : static void eloop_handle_alarm(int sig)
     795             : {
     796           0 :         wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
     797             :                    "two seconds. Looks like there\n"
     798             :                    "is a bug that ends up in a busy loop that "
     799             :                    "prevents clean shutdown.\n"
     800             :                    "Killing program forcefully.\n");
     801           0 :         exit(1);
     802             : }
     803             : #endif /* CONFIG_NATIVE_WINDOWS */
     804             : 
     805             : 
     806        1319 : static void eloop_handle_signal(int sig)
     807             : {
     808             :         int i;
     809             : 
     810             : #ifndef CONFIG_NATIVE_WINDOWS
     811        1319 :         if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
     812             :                 /* Use SIGALRM to break out from potential busy loops that
     813             :                  * would not allow the program to be killed. */
     814          30 :                 eloop.pending_terminate = 1;
     815          30 :                 signal(SIGALRM, eloop_handle_alarm);
     816          30 :                 alarm(2);
     817             :         }
     818             : #endif /* CONFIG_NATIVE_WINDOWS */
     819             : 
     820        1319 :         eloop.signaled++;
     821        1374 :         for (i = 0; i < eloop.signal_count; i++) {
     822        1374 :                 if (eloop.signals[i].sig == sig) {
     823        1319 :                         eloop.signals[i].signaled++;
     824        1319 :                         break;
     825             :                 }
     826             :         }
     827        1319 : }
     828             : 
     829             : 
     830      462159 : static void eloop_process_pending_signals(void)
     831             : {
     832             :         int i;
     833             : 
     834      462159 :         if (eloop.signaled == 0)
     835      923010 :                 return;
     836        1308 :         eloop.signaled = 0;
     837             : 
     838        1308 :         if (eloop.pending_terminate) {
     839             : #ifndef CONFIG_NATIVE_WINDOWS
     840          30 :                 alarm(0);
     841             : #endif /* CONFIG_NATIVE_WINDOWS */
     842          30 :                 eloop.pending_terminate = 0;
     843             :         }
     844             : 
     845        6525 :         for (i = 0; i < eloop.signal_count; i++) {
     846        5217 :                 if (eloop.signals[i].signaled) {
     847        1309 :                         eloop.signals[i].signaled = 0;
     848        2618 :                         eloop.signals[i].handler(eloop.signals[i].sig,
     849        1309 :                                                  eloop.signals[i].user_data);
     850             :                 }
     851             :         }
     852             : }
     853             : 
     854             : 
     855         145 : int eloop_register_signal(int sig, eloop_signal_handler handler,
     856             :                           void *user_data)
     857             : {
     858             :         struct eloop_signal *tmp;
     859             : 
     860         145 :         tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
     861             :                                sizeof(struct eloop_signal));
     862         145 :         if (tmp == NULL)
     863           0 :                 return -1;
     864             : 
     865         145 :         tmp[eloop.signal_count].sig = sig;
     866         145 :         tmp[eloop.signal_count].user_data = user_data;
     867         145 :         tmp[eloop.signal_count].handler = handler;
     868         145 :         tmp[eloop.signal_count].signaled = 0;
     869         145 :         eloop.signal_count++;
     870         145 :         eloop.signals = tmp;
     871         145 :         signal(sig, eloop_handle_signal);
     872             : 
     873         145 :         return 0;
     874             : }
     875             : 
     876             : 
     877          50 : int eloop_register_signal_terminate(eloop_signal_handler handler,
     878             :                                     void *user_data)
     879             : {
     880          50 :         int ret = eloop_register_signal(SIGINT, handler, user_data);
     881          50 :         if (ret == 0)
     882          50 :                 ret = eloop_register_signal(SIGTERM, handler, user_data);
     883          50 :         return ret;
     884             : }
     885             : 
     886             : 
     887          20 : int eloop_register_signal_reconfig(eloop_signal_handler handler,
     888             :                                    void *user_data)
     889             : {
     890             : #ifdef CONFIG_NATIVE_WINDOWS
     891             :         return 0;
     892             : #else /* CONFIG_NATIVE_WINDOWS */
     893          20 :         return eloop_register_signal(SIGHUP, handler, user_data);
     894             : #endif /* CONFIG_NATIVE_WINDOWS */
     895             : }
     896             : 
     897             : 
     898          30 : void eloop_run(void)
     899             : {
     900             : #ifdef CONFIG_ELOOP_POLL
     901             :         int num_poll_fds;
     902             :         int timeout_ms = 0;
     903             : #endif /* CONFIG_ELOOP_POLL */
     904             : #ifdef CONFIG_ELOOP_SELECT
     905             :         fd_set *rfds, *wfds, *efds;
     906             :         struct timeval _tv;
     907             : #endif /* CONFIG_ELOOP_SELECT */
     908             : #ifdef CONFIG_ELOOP_EPOLL
     909             :         int timeout_ms = -1;
     910             : #endif /* CONFIG_ELOOP_EPOLL */
     911             :         int res;
     912             :         struct os_reltime tv, now;
     913             : 
     914             : #ifdef CONFIG_ELOOP_SELECT
     915          30 :         rfds = os_malloc(sizeof(*rfds));
     916          30 :         wfds = os_malloc(sizeof(*wfds));
     917          30 :         efds = os_malloc(sizeof(*efds));
     918          30 :         if (rfds == NULL || wfds == NULL || efds == NULL)
     919             :                 goto out;
     920             : #endif /* CONFIG_ELOOP_SELECT */
     921             : 
     922      924378 :         while (!eloop.terminate &&
     923      545137 :                (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
     924           0 :                 eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
     925             :                 struct eloop_timeout *timeout;
     926      462159 :                 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
     927             :                                         list);
     928      462159 :                 if (timeout) {
     929      379181 :                         os_get_reltime(&now);
     930      379181 :                         if (os_reltime_before(&now, &timeout->time))
     931      330747 :                                 os_reltime_sub(&timeout->time, &now, &tv);
     932             :                         else
     933       48434 :                                 tv.sec = tv.usec = 0;
     934             : #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
     935             :                         timeout_ms = tv.sec * 1000 + tv.usec / 1000;
     936             : #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
     937             : #ifdef CONFIG_ELOOP_SELECT
     938      379181 :                         _tv.tv_sec = tv.sec;
     939      379181 :                         _tv.tv_usec = tv.usec;
     940             : #endif /* CONFIG_ELOOP_SELECT */
     941             :                 }
     942             : 
     943             : #ifdef CONFIG_ELOOP_POLL
     944             :                 num_poll_fds = eloop_sock_table_set_fds(
     945             :                         &eloop.readers, &eloop.writers, &eloop.exceptions,
     946             :                         eloop.pollfds, eloop.pollfds_map,
     947             :                         eloop.max_pollfd_map);
     948             :                 res = poll(eloop.pollfds, num_poll_fds,
     949             :                            timeout ? timeout_ms : -1);
     950             : #endif /* CONFIG_ELOOP_POLL */
     951             : #ifdef CONFIG_ELOOP_SELECT
     952      462159 :                 eloop_sock_table_set_fds(&eloop.readers, rfds);
     953      462159 :                 eloop_sock_table_set_fds(&eloop.writers, wfds);
     954      462159 :                 eloop_sock_table_set_fds(&eloop.exceptions, efds);
     955      462159 :                 res = select(eloop.max_sock + 1, rfds, wfds, efds,
     956             :                              timeout ? &_tv : NULL);
     957             : #endif /* CONFIG_ELOOP_SELECT */
     958             : #ifdef CONFIG_ELOOP_EPOLL
     959             :                 if (eloop.count == 0) {
     960             :                         res = 0;
     961             :                 } else {
     962             :                         res = epoll_wait(eloop.epollfd, eloop.epoll_events,
     963             :                                          eloop.count, timeout_ms);
     964             :                 }
     965             : #endif /* CONFIG_ELOOP_EPOLL */
     966      462159 :                 if (res < 0 && errno != EINTR && errno != 0) {
     967           0 :                         wpa_printf(MSG_ERROR, "eloop: %s: %s",
     968             : #ifdef CONFIG_ELOOP_POLL
     969             :                                    "poll"
     970             : #endif /* CONFIG_ELOOP_POLL */
     971             : #ifdef CONFIG_ELOOP_SELECT
     972             :                                    "select"
     973             : #endif /* CONFIG_ELOOP_SELECT */
     974             : #ifdef CONFIG_ELOOP_EPOLL
     975             :                                    "epoll"
     976             : #endif /* CONFIG_ELOOP_EPOLL */
     977           0 :                                    , strerror(errno));
     978           0 :                         goto out;
     979             :                 }
     980      462159 :                 eloop_process_pending_signals();
     981             : 
     982             :                 /* check if some registered timeouts have occurred */
     983      462159 :                 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
     984             :                                         list);
     985      462159 :                 if (timeout) {
     986      379181 :                         os_get_reltime(&now);
     987      379181 :                         if (!os_reltime_before(&now, &timeout->time)) {
     988       64288 :                                 void *eloop_data = timeout->eloop_data;
     989       64288 :                                 void *user_data = timeout->user_data;
     990       64288 :                                 eloop_timeout_handler handler =
     991             :                                         timeout->handler;
     992       64288 :                                 eloop_remove_timeout(timeout);
     993       64288 :                                 handler(eloop_data, user_data);
     994             :                         }
     995             : 
     996             :                 }
     997             : 
     998      462159 :                 if (res <= 0)
     999       49616 :                         continue;
    1000             : 
    1001             : #ifdef CONFIG_ELOOP_POLL
    1002             :                 eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
    1003             :                                           &eloop.exceptions, eloop.pollfds_map,
    1004             :                                           eloop.max_pollfd_map);
    1005             : #endif /* CONFIG_ELOOP_POLL */
    1006             : #ifdef CONFIG_ELOOP_SELECT
    1007      412543 :                 eloop_sock_table_dispatch(&eloop.readers, rfds);
    1008      412543 :                 eloop_sock_table_dispatch(&eloop.writers, wfds);
    1009      412543 :                 eloop_sock_table_dispatch(&eloop.exceptions, efds);
    1010             : #endif /* CONFIG_ELOOP_SELECT */
    1011             : #ifdef CONFIG_ELOOP_EPOLL
    1012             :                 eloop_sock_table_dispatch(eloop.epoll_events, res);
    1013             : #endif /* CONFIG_ELOOP_EPOLL */
    1014             :         }
    1015             : 
    1016          30 :         eloop.terminate = 0;
    1017             : out:
    1018             : #ifdef CONFIG_ELOOP_SELECT
    1019          30 :         os_free(rfds);
    1020          30 :         os_free(wfds);
    1021          30 :         os_free(efds);
    1022             : #endif /* CONFIG_ELOOP_SELECT */
    1023          30 :         return;
    1024             : }
    1025             : 
    1026             : 
    1027          30 : void eloop_terminate(void)
    1028             : {
    1029          30 :         eloop.terminate = 1;
    1030          30 : }
    1031             : 
    1032             : 
    1033          65 : void eloop_destroy(void)
    1034             : {
    1035             :         struct eloop_timeout *timeout, *prev;
    1036             :         struct os_reltime now;
    1037             : 
    1038          65 :         os_get_reltime(&now);
    1039          65 :         dl_list_for_each_safe(timeout, prev, &eloop.timeout,
    1040             :                               struct eloop_timeout, list) {
    1041             :                 int sec, usec;
    1042           0 :                 sec = timeout->time.sec - now.sec;
    1043           0 :                 usec = timeout->time.usec - now.usec;
    1044           0 :                 if (timeout->time.usec < now.usec) {
    1045           0 :                         sec--;
    1046           0 :                         usec += 1000000;
    1047             :                 }
    1048           0 :                 wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
    1049             :                            "eloop_data=%p user_data=%p handler=%p",
    1050             :                            sec, usec, timeout->eloop_data, timeout->user_data,
    1051             :                            timeout->handler);
    1052           0 :                 wpa_trace_dump_funcname("eloop unregistered timeout handler",
    1053           0 :                                         timeout->handler);
    1054           0 :                 wpa_trace_dump("eloop timeout", timeout);
    1055           0 :                 eloop_remove_timeout(timeout);
    1056             :         }
    1057          65 :         eloop_sock_table_destroy(&eloop.readers);
    1058          65 :         eloop_sock_table_destroy(&eloop.writers);
    1059          65 :         eloop_sock_table_destroy(&eloop.exceptions);
    1060          65 :         os_free(eloop.signals);
    1061             : 
    1062             : #ifdef CONFIG_ELOOP_POLL
    1063             :         os_free(eloop.pollfds);
    1064             :         os_free(eloop.pollfds_map);
    1065             : #endif /* CONFIG_ELOOP_POLL */
    1066             : #ifdef CONFIG_ELOOP_EPOLL
    1067             :         os_free(eloop.epoll_table);
    1068             :         os_free(eloop.epoll_events);
    1069             :         close(eloop.epollfd);
    1070             : #endif /* CONFIG_ELOOP_EPOLL */
    1071          65 : }
    1072             : 
    1073             : 
    1074        4330 : int eloop_terminated(void)
    1075             : {
    1076        4330 :         return eloop.terminate;
    1077             : }
    1078             : 
    1079             : 
    1080           0 : void eloop_wait_for_read_sock(int sock)
    1081             : {
    1082             : #ifdef CONFIG_ELOOP_POLL
    1083             :         struct pollfd pfd;
    1084             : 
    1085             :         if (sock < 0)
    1086             :                 return;
    1087             : 
    1088             :         os_memset(&pfd, 0, sizeof(pfd));
    1089             :         pfd.fd = sock;
    1090             :         pfd.events = POLLIN;
    1091             : 
    1092             :         poll(&pfd, 1, -1);
    1093             : #endif /* CONFIG_ELOOP_POLL */
    1094             : #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL)
    1095             :         /*
    1096             :          * We can use epoll() here. But epoll() requres 4 system calls.
    1097             :          * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for
    1098             :          * epoll fd. So select() is better for performance here.
    1099             :          */
    1100             :         fd_set rfds;
    1101             : 
    1102           0 :         if (sock < 0)
    1103           0 :                 return;
    1104             : 
    1105           0 :         FD_ZERO(&rfds);
    1106           0 :         FD_SET(sock, &rfds);
    1107           0 :         select(sock + 1, &rfds, NULL, NULL, NULL);
    1108             : #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */
    1109             : }
    1110             : 
    1111             : #ifdef CONFIG_ELOOP_SELECT
    1112             : #undef CONFIG_ELOOP_SELECT
    1113             : #endif /* CONFIG_ELOOP_SELECT */

Generated by: LCOV version 1.10