139beb93cSSam Leffler /* 239beb93cSSam Leffler * Event loop based on select() loop 3e28a4053SRui Paulo * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 105b9c547cSRui Paulo #include <assert.h> 1139beb93cSSam Leffler 1239beb93cSSam Leffler #include "common.h" 13e28a4053SRui Paulo #include "trace.h" 14e28a4053SRui Paulo #include "list.h" 1539beb93cSSam Leffler #include "eloop.h" 1639beb93cSSam Leffler 175b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL) 185b9c547cSRui Paulo #error Do not define both of poll and epoll 195b9c547cSRui Paulo #endif 205b9c547cSRui Paulo 215b9c547cSRui Paulo #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) 225b9c547cSRui Paulo #define CONFIG_ELOOP_SELECT 235b9c547cSRui Paulo #endif 245b9c547cSRui Paulo 25f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 26f05cddf9SRui Paulo #include <poll.h> 27f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 28f05cddf9SRui Paulo 295b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 305b9c547cSRui Paulo #include <sys/epoll.h> 315b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 3239beb93cSSam Leffler 3339beb93cSSam Leffler struct eloop_sock { 3439beb93cSSam Leffler int sock; 3539beb93cSSam Leffler void *eloop_data; 3639beb93cSSam Leffler void *user_data; 3739beb93cSSam Leffler eloop_sock_handler handler; 38e28a4053SRui Paulo WPA_TRACE_REF(eloop); 39e28a4053SRui Paulo WPA_TRACE_REF(user); 40e28a4053SRui Paulo WPA_TRACE_INFO 4139beb93cSSam Leffler }; 4239beb93cSSam Leffler 4339beb93cSSam Leffler struct eloop_timeout { 44e28a4053SRui Paulo struct dl_list list; 455b9c547cSRui Paulo struct os_reltime time; 4639beb93cSSam Leffler void *eloop_data; 4739beb93cSSam Leffler void *user_data; 4839beb93cSSam Leffler eloop_timeout_handler handler; 49e28a4053SRui Paulo WPA_TRACE_REF(eloop); 50e28a4053SRui Paulo WPA_TRACE_REF(user); 51e28a4053SRui Paulo WPA_TRACE_INFO 5239beb93cSSam Leffler }; 5339beb93cSSam Leffler 5439beb93cSSam Leffler struct eloop_signal { 5539beb93cSSam Leffler int sig; 5639beb93cSSam Leffler void *user_data; 5739beb93cSSam Leffler eloop_signal_handler handler; 5839beb93cSSam Leffler int signaled; 5939beb93cSSam Leffler }; 6039beb93cSSam Leffler 6139beb93cSSam Leffler struct eloop_sock_table { 6239beb93cSSam Leffler int count; 6339beb93cSSam Leffler struct eloop_sock *table; 645b9c547cSRui Paulo eloop_event_type type; 6539beb93cSSam Leffler int changed; 6639beb93cSSam Leffler }; 6739beb93cSSam Leffler 6839beb93cSSam Leffler struct eloop_data { 6939beb93cSSam Leffler int max_sock; 7039beb93cSSam Leffler 71f05cddf9SRui Paulo int count; /* sum of all table counts */ 72f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 73f05cddf9SRui Paulo int max_pollfd_map; /* number of pollfds_map currently allocated */ 74f05cddf9SRui Paulo int max_poll_fds; /* number of pollfds currently allocated */ 75f05cddf9SRui Paulo struct pollfd *pollfds; 76f05cddf9SRui Paulo struct pollfd **pollfds_map; 77f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 785b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 795b9c547cSRui Paulo int epollfd; 805b9c547cSRui Paulo int epoll_max_event_num; 815b9c547cSRui Paulo int epoll_max_fd; 825b9c547cSRui Paulo struct eloop_sock *epoll_table; 835b9c547cSRui Paulo struct epoll_event *epoll_events; 845b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 8539beb93cSSam Leffler struct eloop_sock_table readers; 8639beb93cSSam Leffler struct eloop_sock_table writers; 8739beb93cSSam Leffler struct eloop_sock_table exceptions; 8839beb93cSSam Leffler 89e28a4053SRui Paulo struct dl_list timeout; 9039beb93cSSam Leffler 9139beb93cSSam Leffler int signal_count; 9239beb93cSSam Leffler struct eloop_signal *signals; 9339beb93cSSam Leffler int signaled; 9439beb93cSSam Leffler int pending_terminate; 9539beb93cSSam Leffler 9639beb93cSSam Leffler int terminate; 9739beb93cSSam Leffler }; 9839beb93cSSam Leffler 9939beb93cSSam Leffler static struct eloop_data eloop; 10039beb93cSSam Leffler 10139beb93cSSam Leffler 102e28a4053SRui Paulo #ifdef WPA_TRACE 103e28a4053SRui Paulo 104e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig) 105e28a4053SRui Paulo { 106e28a4053SRui Paulo wpa_trace_show("eloop SIGSEGV"); 107e28a4053SRui Paulo abort(); 108e28a4053SRui Paulo } 109e28a4053SRui Paulo 110e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 111e28a4053SRui Paulo { 112e28a4053SRui Paulo int i; 113e28a4053SRui Paulo if (table == NULL || table->table == NULL) 114e28a4053SRui Paulo return; 115e28a4053SRui Paulo for (i = 0; i < table->count; i++) { 116e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], eloop, 117e28a4053SRui Paulo table->table[i].eloop_data); 118e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], user, 119e28a4053SRui Paulo table->table[i].user_data); 120e28a4053SRui Paulo } 121e28a4053SRui Paulo } 122e28a4053SRui Paulo 123e28a4053SRui Paulo 124e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 125e28a4053SRui Paulo { 126e28a4053SRui Paulo int i; 127e28a4053SRui Paulo if (table == NULL || table->table == NULL) 128e28a4053SRui Paulo return; 129e28a4053SRui Paulo for (i = 0; i < table->count; i++) { 130e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], eloop, 131e28a4053SRui Paulo table->table[i].eloop_data); 132e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], user, 133e28a4053SRui Paulo table->table[i].user_data); 134e28a4053SRui Paulo } 135e28a4053SRui Paulo } 136e28a4053SRui Paulo 137e28a4053SRui Paulo #else /* WPA_TRACE */ 138e28a4053SRui Paulo 139e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0) 140e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0) 141e28a4053SRui Paulo 142e28a4053SRui Paulo #endif /* WPA_TRACE */ 143e28a4053SRui Paulo 144e28a4053SRui Paulo 145e28a4053SRui Paulo int eloop_init(void) 14639beb93cSSam Leffler { 14739beb93cSSam Leffler os_memset(&eloop, 0, sizeof(eloop)); 148e28a4053SRui Paulo dl_list_init(&eloop.timeout); 1495b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 1505b9c547cSRui Paulo eloop.epollfd = epoll_create1(0); 1515b9c547cSRui Paulo if (eloop.epollfd < 0) { 1525b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n", 1535b9c547cSRui Paulo __func__, strerror(errno)); 1545b9c547cSRui Paulo return -1; 1555b9c547cSRui Paulo } 1565b9c547cSRui Paulo eloop.readers.type = EVENT_TYPE_READ; 1575b9c547cSRui Paulo eloop.writers.type = EVENT_TYPE_WRITE; 1585b9c547cSRui Paulo eloop.exceptions.type = EVENT_TYPE_EXCEPTION; 1595b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 160e28a4053SRui Paulo #ifdef WPA_TRACE 161e28a4053SRui Paulo signal(SIGSEGV, eloop_sigsegv_handler); 162e28a4053SRui Paulo #endif /* WPA_TRACE */ 16339beb93cSSam Leffler return 0; 16439beb93cSSam Leffler } 16539beb93cSSam Leffler 16639beb93cSSam Leffler 16739beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 16839beb93cSSam Leffler int sock, eloop_sock_handler handler, 16939beb93cSSam Leffler void *eloop_data, void *user_data) 17039beb93cSSam Leffler { 1715b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 1725b9c547cSRui Paulo struct eloop_sock *temp_table; 1735b9c547cSRui Paulo struct epoll_event ev, *temp_events; 1745b9c547cSRui Paulo int next; 1755b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 17639beb93cSSam Leffler struct eloop_sock *tmp; 177f05cddf9SRui Paulo int new_max_sock; 178f05cddf9SRui Paulo 179f05cddf9SRui Paulo if (sock > eloop.max_sock) 180f05cddf9SRui Paulo new_max_sock = sock; 181f05cddf9SRui Paulo else 182f05cddf9SRui Paulo new_max_sock = eloop.max_sock; 18339beb93cSSam Leffler 18439beb93cSSam Leffler if (table == NULL) 18539beb93cSSam Leffler return -1; 18639beb93cSSam Leffler 187f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 188f05cddf9SRui Paulo if (new_max_sock >= eloop.max_pollfd_map) { 189f05cddf9SRui Paulo struct pollfd **nmap; 190f05cddf9SRui Paulo nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50, 191f05cddf9SRui Paulo sizeof(struct pollfd *)); 192f05cddf9SRui Paulo if (nmap == NULL) 193f05cddf9SRui Paulo return -1; 194f05cddf9SRui Paulo 195f05cddf9SRui Paulo eloop.max_pollfd_map = new_max_sock + 50; 196f05cddf9SRui Paulo eloop.pollfds_map = nmap; 197f05cddf9SRui Paulo } 198f05cddf9SRui Paulo 199f05cddf9SRui Paulo if (eloop.count + 1 > eloop.max_poll_fds) { 200f05cddf9SRui Paulo struct pollfd *n; 201f05cddf9SRui Paulo int nmax = eloop.count + 1 + 50; 202f05cddf9SRui Paulo n = os_realloc_array(eloop.pollfds, nmax, 203f05cddf9SRui Paulo sizeof(struct pollfd)); 204f05cddf9SRui Paulo if (n == NULL) 205f05cddf9SRui Paulo return -1; 206f05cddf9SRui Paulo 207f05cddf9SRui Paulo eloop.max_poll_fds = nmax; 208f05cddf9SRui Paulo eloop.pollfds = n; 209f05cddf9SRui Paulo } 210f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 2115b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 2125b9c547cSRui Paulo if (new_max_sock >= eloop.epoll_max_fd) { 2135b9c547cSRui Paulo next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2; 2145b9c547cSRui Paulo temp_table = os_realloc_array(eloop.epoll_table, next, 2155b9c547cSRui Paulo sizeof(struct eloop_sock)); 2165b9c547cSRui Paulo if (temp_table == NULL) 2175b9c547cSRui Paulo return -1; 2185b9c547cSRui Paulo 2195b9c547cSRui Paulo eloop.epoll_max_fd = next; 2205b9c547cSRui Paulo eloop.epoll_table = temp_table; 2215b9c547cSRui Paulo } 2225b9c547cSRui Paulo 2235b9c547cSRui Paulo if (eloop.count + 1 > eloop.epoll_max_event_num) { 2245b9c547cSRui Paulo next = eloop.epoll_max_event_num == 0 ? 8 : 2255b9c547cSRui Paulo eloop.epoll_max_event_num * 2; 2265b9c547cSRui Paulo temp_events = os_realloc_array(eloop.epoll_events, next, 2275b9c547cSRui Paulo sizeof(struct epoll_event)); 2285b9c547cSRui Paulo if (temp_events == NULL) { 2295b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. " 2305b9c547cSRui Paulo "%s\n", __func__, strerror(errno)); 2315b9c547cSRui Paulo return -1; 2325b9c547cSRui Paulo } 2335b9c547cSRui Paulo 2345b9c547cSRui Paulo eloop.epoll_max_event_num = next; 2355b9c547cSRui Paulo eloop.epoll_events = temp_events; 2365b9c547cSRui Paulo } 2375b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 238f05cddf9SRui Paulo 239e28a4053SRui Paulo eloop_trace_sock_remove_ref(table); 240f05cddf9SRui Paulo tmp = os_realloc_array(table->table, table->count + 1, 241f05cddf9SRui Paulo sizeof(struct eloop_sock)); 2425b9c547cSRui Paulo if (tmp == NULL) { 2435b9c547cSRui Paulo eloop_trace_sock_add_ref(table); 24439beb93cSSam Leffler return -1; 2455b9c547cSRui Paulo } 24639beb93cSSam Leffler 24739beb93cSSam Leffler tmp[table->count].sock = sock; 24839beb93cSSam Leffler tmp[table->count].eloop_data = eloop_data; 24939beb93cSSam Leffler tmp[table->count].user_data = user_data; 25039beb93cSSam Leffler tmp[table->count].handler = handler; 251e28a4053SRui Paulo wpa_trace_record(&tmp[table->count]); 25239beb93cSSam Leffler table->count++; 25339beb93cSSam Leffler table->table = tmp; 254f05cddf9SRui Paulo eloop.max_sock = new_max_sock; 255f05cddf9SRui Paulo eloop.count++; 25639beb93cSSam Leffler table->changed = 1; 257e28a4053SRui Paulo eloop_trace_sock_add_ref(table); 25839beb93cSSam Leffler 2595b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 2605b9c547cSRui Paulo os_memset(&ev, 0, sizeof(ev)); 2615b9c547cSRui Paulo switch (table->type) { 2625b9c547cSRui Paulo case EVENT_TYPE_READ: 2635b9c547cSRui Paulo ev.events = EPOLLIN; 2645b9c547cSRui Paulo break; 2655b9c547cSRui Paulo case EVENT_TYPE_WRITE: 2665b9c547cSRui Paulo ev.events = EPOLLOUT; 2675b9c547cSRui Paulo break; 2685b9c547cSRui Paulo /* 2695b9c547cSRui Paulo * Exceptions are always checked when using epoll, but I suppose it's 2705b9c547cSRui Paulo * possible that someone registered a socket *only* for exception 2715b9c547cSRui Paulo * handling. 2725b9c547cSRui Paulo */ 2735b9c547cSRui Paulo case EVENT_TYPE_EXCEPTION: 2745b9c547cSRui Paulo ev.events = EPOLLERR | EPOLLHUP; 2755b9c547cSRui Paulo break; 2765b9c547cSRui Paulo } 2775b9c547cSRui Paulo ev.data.fd = sock; 2785b9c547cSRui Paulo if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { 2795b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d " 2805b9c547cSRui Paulo "failed. %s\n", __func__, sock, strerror(errno)); 2815b9c547cSRui Paulo return -1; 2825b9c547cSRui Paulo } 2835b9c547cSRui Paulo os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1], 2845b9c547cSRui Paulo sizeof(struct eloop_sock)); 2855b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 28639beb93cSSam Leffler return 0; 28739beb93cSSam Leffler } 28839beb93cSSam Leffler 28939beb93cSSam Leffler 29039beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 29139beb93cSSam Leffler int sock) 29239beb93cSSam Leffler { 29339beb93cSSam Leffler int i; 29439beb93cSSam Leffler 29539beb93cSSam Leffler if (table == NULL || table->table == NULL || table->count == 0) 29639beb93cSSam Leffler return; 29739beb93cSSam Leffler 29839beb93cSSam Leffler for (i = 0; i < table->count; i++) { 29939beb93cSSam Leffler if (table->table[i].sock == sock) 30039beb93cSSam Leffler break; 30139beb93cSSam Leffler } 30239beb93cSSam Leffler if (i == table->count) 30339beb93cSSam Leffler return; 304e28a4053SRui Paulo eloop_trace_sock_remove_ref(table); 30539beb93cSSam Leffler if (i != table->count - 1) { 30639beb93cSSam Leffler os_memmove(&table->table[i], &table->table[i + 1], 30739beb93cSSam Leffler (table->count - i - 1) * 30839beb93cSSam Leffler sizeof(struct eloop_sock)); 30939beb93cSSam Leffler } 31039beb93cSSam Leffler table->count--; 311f05cddf9SRui Paulo eloop.count--; 31239beb93cSSam Leffler table->changed = 1; 313e28a4053SRui Paulo eloop_trace_sock_add_ref(table); 3145b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 3155b9c547cSRui Paulo if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) { 3165b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d " 3175b9c547cSRui Paulo "failed. %s\n", __func__, sock, strerror(errno)); 3185b9c547cSRui Paulo return; 3195b9c547cSRui Paulo } 3205b9c547cSRui Paulo os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock)); 3215b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 32239beb93cSSam Leffler } 32339beb93cSSam Leffler 32439beb93cSSam Leffler 325f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 326f05cddf9SRui Paulo 327f05cddf9SRui Paulo static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx) 328f05cddf9SRui Paulo { 329f05cddf9SRui Paulo if (fd < mx && fd >= 0) 330f05cddf9SRui Paulo return pollfds_map[fd]; 331f05cddf9SRui Paulo return NULL; 332f05cddf9SRui Paulo } 333f05cddf9SRui Paulo 334f05cddf9SRui Paulo 335f05cddf9SRui Paulo static int eloop_sock_table_set_fds(struct eloop_sock_table *readers, 336f05cddf9SRui Paulo struct eloop_sock_table *writers, 337f05cddf9SRui Paulo struct eloop_sock_table *exceptions, 338f05cddf9SRui Paulo struct pollfd *pollfds, 339f05cddf9SRui Paulo struct pollfd **pollfds_map, 340f05cddf9SRui Paulo int max_pollfd_map) 341f05cddf9SRui Paulo { 342f05cddf9SRui Paulo int i; 343f05cddf9SRui Paulo int nxt = 0; 344f05cddf9SRui Paulo int fd; 345f05cddf9SRui Paulo struct pollfd *pfd; 346f05cddf9SRui Paulo 347f05cddf9SRui Paulo /* Clear pollfd lookup map. It will be re-populated below. */ 348f05cddf9SRui Paulo os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map); 349f05cddf9SRui Paulo 350f05cddf9SRui Paulo if (readers && readers->table) { 351f05cddf9SRui Paulo for (i = 0; i < readers->count; i++) { 352f05cddf9SRui Paulo fd = readers->table[i].sock; 353f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map); 354f05cddf9SRui Paulo pollfds[nxt].fd = fd; 355f05cddf9SRui Paulo pollfds[nxt].events = POLLIN; 356f05cddf9SRui Paulo pollfds[nxt].revents = 0; 357f05cddf9SRui Paulo pollfds_map[fd] = &(pollfds[nxt]); 358f05cddf9SRui Paulo nxt++; 359f05cddf9SRui Paulo } 360f05cddf9SRui Paulo } 361f05cddf9SRui Paulo 362f05cddf9SRui Paulo if (writers && writers->table) { 363f05cddf9SRui Paulo for (i = 0; i < writers->count; i++) { 364f05cddf9SRui Paulo /* 365f05cddf9SRui Paulo * See if we already added this descriptor, update it 366f05cddf9SRui Paulo * if so. 367f05cddf9SRui Paulo */ 368f05cddf9SRui Paulo fd = writers->table[i].sock; 369f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map); 370f05cddf9SRui Paulo pfd = pollfds_map[fd]; 371f05cddf9SRui Paulo if (!pfd) { 372f05cddf9SRui Paulo pfd = &(pollfds[nxt]); 373f05cddf9SRui Paulo pfd->events = 0; 374f05cddf9SRui Paulo pfd->fd = fd; 375f05cddf9SRui Paulo pollfds[i].revents = 0; 376f05cddf9SRui Paulo pollfds_map[fd] = pfd; 377f05cddf9SRui Paulo nxt++; 378f05cddf9SRui Paulo } 379f05cddf9SRui Paulo pfd->events |= POLLOUT; 380f05cddf9SRui Paulo } 381f05cddf9SRui Paulo } 382f05cddf9SRui Paulo 383f05cddf9SRui Paulo /* 384f05cddf9SRui Paulo * Exceptions are always checked when using poll, but I suppose it's 385f05cddf9SRui Paulo * possible that someone registered a socket *only* for exception 386f05cddf9SRui Paulo * handling. Set the POLLIN bit in this case. 387f05cddf9SRui Paulo */ 388f05cddf9SRui Paulo if (exceptions && exceptions->table) { 389f05cddf9SRui Paulo for (i = 0; i < exceptions->count; i++) { 390f05cddf9SRui Paulo /* 391f05cddf9SRui Paulo * See if we already added this descriptor, just use it 392f05cddf9SRui Paulo * if so. 393f05cddf9SRui Paulo */ 394f05cddf9SRui Paulo fd = exceptions->table[i].sock; 395f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map); 396f05cddf9SRui Paulo pfd = pollfds_map[fd]; 397f05cddf9SRui Paulo if (!pfd) { 398f05cddf9SRui Paulo pfd = &(pollfds[nxt]); 399f05cddf9SRui Paulo pfd->events = POLLIN; 400f05cddf9SRui Paulo pfd->fd = fd; 401f05cddf9SRui Paulo pollfds[i].revents = 0; 402f05cddf9SRui Paulo pollfds_map[fd] = pfd; 403f05cddf9SRui Paulo nxt++; 404f05cddf9SRui Paulo } 405f05cddf9SRui Paulo } 406f05cddf9SRui Paulo } 407f05cddf9SRui Paulo 408f05cddf9SRui Paulo return nxt; 409f05cddf9SRui Paulo } 410f05cddf9SRui Paulo 411f05cddf9SRui Paulo 412f05cddf9SRui Paulo static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table, 413f05cddf9SRui Paulo struct pollfd **pollfds_map, 414f05cddf9SRui Paulo int max_pollfd_map, 415f05cddf9SRui Paulo short int revents) 416f05cddf9SRui Paulo { 417f05cddf9SRui Paulo int i; 418f05cddf9SRui Paulo struct pollfd *pfd; 419f05cddf9SRui Paulo 420f05cddf9SRui Paulo if (!table || !table->table) 421f05cddf9SRui Paulo return 0; 422f05cddf9SRui Paulo 423f05cddf9SRui Paulo table->changed = 0; 424f05cddf9SRui Paulo for (i = 0; i < table->count; i++) { 425f05cddf9SRui Paulo pfd = find_pollfd(pollfds_map, table->table[i].sock, 426f05cddf9SRui Paulo max_pollfd_map); 427f05cddf9SRui Paulo if (!pfd) 428f05cddf9SRui Paulo continue; 429f05cddf9SRui Paulo 430f05cddf9SRui Paulo if (!(pfd->revents & revents)) 431f05cddf9SRui Paulo continue; 432f05cddf9SRui Paulo 433f05cddf9SRui Paulo table->table[i].handler(table->table[i].sock, 434f05cddf9SRui Paulo table->table[i].eloop_data, 435f05cddf9SRui Paulo table->table[i].user_data); 436f05cddf9SRui Paulo if (table->changed) 437f05cddf9SRui Paulo return 1; 438f05cddf9SRui Paulo } 439f05cddf9SRui Paulo 440f05cddf9SRui Paulo return 0; 441f05cddf9SRui Paulo } 442f05cddf9SRui Paulo 443f05cddf9SRui Paulo 444f05cddf9SRui Paulo static void eloop_sock_table_dispatch(struct eloop_sock_table *readers, 445f05cddf9SRui Paulo struct eloop_sock_table *writers, 446f05cddf9SRui Paulo struct eloop_sock_table *exceptions, 447f05cddf9SRui Paulo struct pollfd **pollfds_map, 448f05cddf9SRui Paulo int max_pollfd_map) 449f05cddf9SRui Paulo { 450f05cddf9SRui Paulo if (eloop_sock_table_dispatch_table(readers, pollfds_map, 451f05cddf9SRui Paulo max_pollfd_map, POLLIN | POLLERR | 452f05cddf9SRui Paulo POLLHUP)) 453f05cddf9SRui Paulo return; /* pollfds may be invalid at this point */ 454f05cddf9SRui Paulo 455f05cddf9SRui Paulo if (eloop_sock_table_dispatch_table(writers, pollfds_map, 456f05cddf9SRui Paulo max_pollfd_map, POLLOUT)) 457f05cddf9SRui Paulo return; /* pollfds may be invalid at this point */ 458f05cddf9SRui Paulo 459f05cddf9SRui Paulo eloop_sock_table_dispatch_table(exceptions, pollfds_map, 460f05cddf9SRui Paulo max_pollfd_map, POLLERR | POLLHUP); 461f05cddf9SRui Paulo } 462f05cddf9SRui Paulo 4635b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 4645b9c547cSRui Paulo 4655b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 466f05cddf9SRui Paulo 46739beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table, 46839beb93cSSam Leffler fd_set *fds) 46939beb93cSSam Leffler { 47039beb93cSSam Leffler int i; 47139beb93cSSam Leffler 47239beb93cSSam Leffler FD_ZERO(fds); 47339beb93cSSam Leffler 47439beb93cSSam Leffler if (table->table == NULL) 47539beb93cSSam Leffler return; 47639beb93cSSam Leffler 4775b9c547cSRui Paulo for (i = 0; i < table->count; i++) { 4785b9c547cSRui Paulo assert(table->table[i].sock >= 0); 47939beb93cSSam Leffler FD_SET(table->table[i].sock, fds); 48039beb93cSSam Leffler } 4815b9c547cSRui Paulo } 48239beb93cSSam Leffler 48339beb93cSSam Leffler 48439beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table, 48539beb93cSSam Leffler fd_set *fds) 48639beb93cSSam Leffler { 48739beb93cSSam Leffler int i; 48839beb93cSSam Leffler 48939beb93cSSam Leffler if (table == NULL || table->table == NULL) 49039beb93cSSam Leffler return; 49139beb93cSSam Leffler 49239beb93cSSam Leffler table->changed = 0; 49339beb93cSSam Leffler for (i = 0; i < table->count; i++) { 49439beb93cSSam Leffler if (FD_ISSET(table->table[i].sock, fds)) { 49539beb93cSSam Leffler table->table[i].handler(table->table[i].sock, 49639beb93cSSam Leffler table->table[i].eloop_data, 49739beb93cSSam Leffler table->table[i].user_data); 49839beb93cSSam Leffler if (table->changed) 49939beb93cSSam Leffler break; 50039beb93cSSam Leffler } 50139beb93cSSam Leffler } 50239beb93cSSam Leffler } 50339beb93cSSam Leffler 5045b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 5055b9c547cSRui Paulo 5065b9c547cSRui Paulo 5075b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 5085b9c547cSRui Paulo static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) 5095b9c547cSRui Paulo { 5105b9c547cSRui Paulo struct eloop_sock *table; 5115b9c547cSRui Paulo int i; 5125b9c547cSRui Paulo 5135b9c547cSRui Paulo for (i = 0; i < nfds; i++) { 5145b9c547cSRui Paulo table = &eloop.epoll_table[events[i].data.fd]; 5155b9c547cSRui Paulo if (table->handler == NULL) 5165b9c547cSRui Paulo continue; 5175b9c547cSRui Paulo table->handler(table->sock, table->eloop_data, 5185b9c547cSRui Paulo table->user_data); 519*325151a3SRui Paulo if (eloop.readers.changed || 520*325151a3SRui Paulo eloop.writers.changed || 521*325151a3SRui Paulo eloop.exceptions.changed) 522*325151a3SRui Paulo break; 5235b9c547cSRui Paulo } 5245b9c547cSRui Paulo } 5255b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 526f05cddf9SRui Paulo 52739beb93cSSam Leffler 52839beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table) 52939beb93cSSam Leffler { 53039beb93cSSam Leffler if (table) { 53139beb93cSSam Leffler int i; 53239beb93cSSam Leffler for (i = 0; i < table->count && table->table; i++) { 533e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining socket: " 534e28a4053SRui Paulo "sock=%d eloop_data=%p user_data=%p " 535e28a4053SRui Paulo "handler=%p", 53639beb93cSSam Leffler table->table[i].sock, 53739beb93cSSam Leffler table->table[i].eloop_data, 53839beb93cSSam Leffler table->table[i].user_data, 53939beb93cSSam Leffler table->table[i].handler); 540e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered socket " 541e28a4053SRui Paulo "handler", 542e28a4053SRui Paulo table->table[i].handler); 543e28a4053SRui Paulo wpa_trace_dump("eloop sock", &table->table[i]); 54439beb93cSSam Leffler } 54539beb93cSSam Leffler os_free(table->table); 54639beb93cSSam Leffler } 54739beb93cSSam Leffler } 54839beb93cSSam Leffler 54939beb93cSSam Leffler 55039beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler, 55139beb93cSSam Leffler void *eloop_data, void *user_data) 55239beb93cSSam Leffler { 55339beb93cSSam Leffler return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 55439beb93cSSam Leffler eloop_data, user_data); 55539beb93cSSam Leffler } 55639beb93cSSam Leffler 55739beb93cSSam Leffler 55839beb93cSSam Leffler void eloop_unregister_read_sock(int sock) 55939beb93cSSam Leffler { 56039beb93cSSam Leffler eloop_unregister_sock(sock, EVENT_TYPE_READ); 56139beb93cSSam Leffler } 56239beb93cSSam Leffler 56339beb93cSSam Leffler 56439beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 56539beb93cSSam Leffler { 56639beb93cSSam Leffler switch (type) { 56739beb93cSSam Leffler case EVENT_TYPE_READ: 56839beb93cSSam Leffler return &eloop.readers; 56939beb93cSSam Leffler case EVENT_TYPE_WRITE: 57039beb93cSSam Leffler return &eloop.writers; 57139beb93cSSam Leffler case EVENT_TYPE_EXCEPTION: 57239beb93cSSam Leffler return &eloop.exceptions; 57339beb93cSSam Leffler } 57439beb93cSSam Leffler 57539beb93cSSam Leffler return NULL; 57639beb93cSSam Leffler } 57739beb93cSSam Leffler 57839beb93cSSam Leffler 57939beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type, 58039beb93cSSam Leffler eloop_sock_handler handler, 58139beb93cSSam Leffler void *eloop_data, void *user_data) 58239beb93cSSam Leffler { 58339beb93cSSam Leffler struct eloop_sock_table *table; 58439beb93cSSam Leffler 5855b9c547cSRui Paulo assert(sock >= 0); 58639beb93cSSam Leffler table = eloop_get_sock_table(type); 58739beb93cSSam Leffler return eloop_sock_table_add_sock(table, sock, handler, 58839beb93cSSam Leffler eloop_data, user_data); 58939beb93cSSam Leffler } 59039beb93cSSam Leffler 59139beb93cSSam Leffler 59239beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type) 59339beb93cSSam Leffler { 59439beb93cSSam Leffler struct eloop_sock_table *table; 59539beb93cSSam Leffler 59639beb93cSSam Leffler table = eloop_get_sock_table(type); 59739beb93cSSam Leffler eloop_sock_table_remove_sock(table, sock); 59839beb93cSSam Leffler } 59939beb93cSSam Leffler 60039beb93cSSam Leffler 60139beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs, 60239beb93cSSam Leffler eloop_timeout_handler handler, 60339beb93cSSam Leffler void *eloop_data, void *user_data) 60439beb93cSSam Leffler { 605e28a4053SRui Paulo struct eloop_timeout *timeout, *tmp; 606f05cddf9SRui Paulo os_time_t now_sec; 60739beb93cSSam Leffler 608e28a4053SRui Paulo timeout = os_zalloc(sizeof(*timeout)); 60939beb93cSSam Leffler if (timeout == NULL) 61039beb93cSSam Leffler return -1; 6115b9c547cSRui Paulo if (os_get_reltime(&timeout->time) < 0) { 61239beb93cSSam Leffler os_free(timeout); 61339beb93cSSam Leffler return -1; 61439beb93cSSam Leffler } 615f05cddf9SRui Paulo now_sec = timeout->time.sec; 61639beb93cSSam Leffler timeout->time.sec += secs; 617f05cddf9SRui Paulo if (timeout->time.sec < now_sec) { 618f05cddf9SRui Paulo /* 619f05cddf9SRui Paulo * Integer overflow - assume long enough timeout to be assumed 620f05cddf9SRui Paulo * to be infinite, i.e., the timeout would never happen. 621f05cddf9SRui Paulo */ 622f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " 623f05cddf9SRui Paulo "ever happen - ignore it", secs); 624f05cddf9SRui Paulo os_free(timeout); 625f05cddf9SRui Paulo return 0; 626f05cddf9SRui Paulo } 62739beb93cSSam Leffler timeout->time.usec += usecs; 62839beb93cSSam Leffler while (timeout->time.usec >= 1000000) { 62939beb93cSSam Leffler timeout->time.sec++; 63039beb93cSSam Leffler timeout->time.usec -= 1000000; 63139beb93cSSam Leffler } 63239beb93cSSam Leffler timeout->eloop_data = eloop_data; 63339beb93cSSam Leffler timeout->user_data = user_data; 63439beb93cSSam Leffler timeout->handler = handler; 635e28a4053SRui Paulo wpa_trace_add_ref(timeout, eloop, eloop_data); 636e28a4053SRui Paulo wpa_trace_add_ref(timeout, user, user_data); 637e28a4053SRui Paulo wpa_trace_record(timeout); 63839beb93cSSam Leffler 639e28a4053SRui Paulo /* Maintain timeouts in order of increasing time */ 640e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 6415b9c547cSRui Paulo if (os_reltime_before(&timeout->time, &tmp->time)) { 642e28a4053SRui Paulo dl_list_add(tmp->list.prev, &timeout->list); 643e28a4053SRui Paulo return 0; 644e28a4053SRui Paulo } 645e28a4053SRui Paulo } 646e28a4053SRui Paulo dl_list_add_tail(&eloop.timeout, &timeout->list); 647e28a4053SRui Paulo 64839beb93cSSam Leffler return 0; 64939beb93cSSam Leffler } 65039beb93cSSam Leffler 65139beb93cSSam Leffler 652e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout) 653e28a4053SRui Paulo { 654e28a4053SRui Paulo dl_list_del(&timeout->list); 655e28a4053SRui Paulo wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 656e28a4053SRui Paulo wpa_trace_remove_ref(timeout, user, timeout->user_data); 657e28a4053SRui Paulo os_free(timeout); 65839beb93cSSam Leffler } 65939beb93cSSam Leffler 66039beb93cSSam Leffler 66139beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler, 66239beb93cSSam Leffler void *eloop_data, void *user_data) 66339beb93cSSam Leffler { 664e28a4053SRui Paulo struct eloop_timeout *timeout, *prev; 66539beb93cSSam Leffler int removed = 0; 66639beb93cSSam Leffler 667e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 668e28a4053SRui Paulo struct eloop_timeout, list) { 66939beb93cSSam Leffler if (timeout->handler == handler && 67039beb93cSSam Leffler (timeout->eloop_data == eloop_data || 67139beb93cSSam Leffler eloop_data == ELOOP_ALL_CTX) && 67239beb93cSSam Leffler (timeout->user_data == user_data || 67339beb93cSSam Leffler user_data == ELOOP_ALL_CTX)) { 674e28a4053SRui Paulo eloop_remove_timeout(timeout); 67539beb93cSSam Leffler removed++; 676e28a4053SRui Paulo } 67739beb93cSSam Leffler } 67839beb93cSSam Leffler 67939beb93cSSam Leffler return removed; 68039beb93cSSam Leffler } 68139beb93cSSam Leffler 68239beb93cSSam Leffler 6835b9c547cSRui Paulo int eloop_cancel_timeout_one(eloop_timeout_handler handler, 6845b9c547cSRui Paulo void *eloop_data, void *user_data, 6855b9c547cSRui Paulo struct os_reltime *remaining) 6865b9c547cSRui Paulo { 6875b9c547cSRui Paulo struct eloop_timeout *timeout, *prev; 6885b9c547cSRui Paulo int removed = 0; 6895b9c547cSRui Paulo struct os_reltime now; 6905b9c547cSRui Paulo 6915b9c547cSRui Paulo os_get_reltime(&now); 6925b9c547cSRui Paulo remaining->sec = remaining->usec = 0; 6935b9c547cSRui Paulo 6945b9c547cSRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 6955b9c547cSRui Paulo struct eloop_timeout, list) { 6965b9c547cSRui Paulo if (timeout->handler == handler && 6975b9c547cSRui Paulo (timeout->eloop_data == eloop_data) && 6985b9c547cSRui Paulo (timeout->user_data == user_data)) { 6995b9c547cSRui Paulo removed = 1; 7005b9c547cSRui Paulo if (os_reltime_before(&now, &timeout->time)) 7015b9c547cSRui Paulo os_reltime_sub(&timeout->time, &now, remaining); 7025b9c547cSRui Paulo eloop_remove_timeout(timeout); 7035b9c547cSRui Paulo break; 7045b9c547cSRui Paulo } 7055b9c547cSRui Paulo } 7065b9c547cSRui Paulo return removed; 7075b9c547cSRui Paulo } 7085b9c547cSRui Paulo 7095b9c547cSRui Paulo 71039beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler, 71139beb93cSSam Leffler void *eloop_data, void *user_data) 71239beb93cSSam Leffler { 71339beb93cSSam Leffler struct eloop_timeout *tmp; 71439beb93cSSam Leffler 715e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 71639beb93cSSam Leffler if (tmp->handler == handler && 71739beb93cSSam Leffler tmp->eloop_data == eloop_data && 71839beb93cSSam Leffler tmp->user_data == user_data) 71939beb93cSSam Leffler return 1; 72039beb93cSSam Leffler } 72139beb93cSSam Leffler 72239beb93cSSam Leffler return 0; 72339beb93cSSam Leffler } 72439beb93cSSam Leffler 72539beb93cSSam Leffler 7265b9c547cSRui Paulo int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, 7275b9c547cSRui Paulo eloop_timeout_handler handler, void *eloop_data, 7285b9c547cSRui Paulo void *user_data) 7295b9c547cSRui Paulo { 7305b9c547cSRui Paulo struct os_reltime now, requested, remaining; 7315b9c547cSRui Paulo struct eloop_timeout *tmp; 7325b9c547cSRui Paulo 7335b9c547cSRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 7345b9c547cSRui Paulo if (tmp->handler == handler && 7355b9c547cSRui Paulo tmp->eloop_data == eloop_data && 7365b9c547cSRui Paulo tmp->user_data == user_data) { 7375b9c547cSRui Paulo requested.sec = req_secs; 7385b9c547cSRui Paulo requested.usec = req_usecs; 7395b9c547cSRui Paulo os_get_reltime(&now); 7405b9c547cSRui Paulo os_reltime_sub(&tmp->time, &now, &remaining); 7415b9c547cSRui Paulo if (os_reltime_before(&requested, &remaining)) { 7425b9c547cSRui Paulo eloop_cancel_timeout(handler, eloop_data, 7435b9c547cSRui Paulo user_data); 7445b9c547cSRui Paulo eloop_register_timeout(requested.sec, 7455b9c547cSRui Paulo requested.usec, 7465b9c547cSRui Paulo handler, eloop_data, 7475b9c547cSRui Paulo user_data); 7485b9c547cSRui Paulo return 1; 7495b9c547cSRui Paulo } 7505b9c547cSRui Paulo return 0; 7515b9c547cSRui Paulo } 7525b9c547cSRui Paulo } 7535b9c547cSRui Paulo 7545b9c547cSRui Paulo return -1; 7555b9c547cSRui Paulo } 7565b9c547cSRui Paulo 7575b9c547cSRui Paulo 7585b9c547cSRui Paulo int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, 7595b9c547cSRui Paulo eloop_timeout_handler handler, void *eloop_data, 7605b9c547cSRui Paulo void *user_data) 7615b9c547cSRui Paulo { 7625b9c547cSRui Paulo struct os_reltime now, requested, remaining; 7635b9c547cSRui Paulo struct eloop_timeout *tmp; 7645b9c547cSRui Paulo 7655b9c547cSRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 7665b9c547cSRui Paulo if (tmp->handler == handler && 7675b9c547cSRui Paulo tmp->eloop_data == eloop_data && 7685b9c547cSRui Paulo tmp->user_data == user_data) { 7695b9c547cSRui Paulo requested.sec = req_secs; 7705b9c547cSRui Paulo requested.usec = req_usecs; 7715b9c547cSRui Paulo os_get_reltime(&now); 7725b9c547cSRui Paulo os_reltime_sub(&tmp->time, &now, &remaining); 7735b9c547cSRui Paulo if (os_reltime_before(&remaining, &requested)) { 7745b9c547cSRui Paulo eloop_cancel_timeout(handler, eloop_data, 7755b9c547cSRui Paulo user_data); 7765b9c547cSRui Paulo eloop_register_timeout(requested.sec, 7775b9c547cSRui Paulo requested.usec, 7785b9c547cSRui Paulo handler, eloop_data, 7795b9c547cSRui Paulo user_data); 7805b9c547cSRui Paulo return 1; 7815b9c547cSRui Paulo } 7825b9c547cSRui Paulo return 0; 7835b9c547cSRui Paulo } 7845b9c547cSRui Paulo } 7855b9c547cSRui Paulo 7865b9c547cSRui Paulo return -1; 7875b9c547cSRui Paulo } 7885b9c547cSRui Paulo 7895b9c547cSRui Paulo 79039beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 79139beb93cSSam Leffler static void eloop_handle_alarm(int sig) 79239beb93cSSam Leffler { 793e28a4053SRui Paulo wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 794e28a4053SRui Paulo "two seconds. Looks like there\n" 79539beb93cSSam Leffler "is a bug that ends up in a busy loop that " 79639beb93cSSam Leffler "prevents clean shutdown.\n" 79739beb93cSSam Leffler "Killing program forcefully.\n"); 79839beb93cSSam Leffler exit(1); 79939beb93cSSam Leffler } 80039beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 80139beb93cSSam Leffler 80239beb93cSSam Leffler 80339beb93cSSam Leffler static void eloop_handle_signal(int sig) 80439beb93cSSam Leffler { 80539beb93cSSam Leffler int i; 80639beb93cSSam Leffler 80739beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 80839beb93cSSam Leffler if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 80939beb93cSSam Leffler /* Use SIGALRM to break out from potential busy loops that 81039beb93cSSam Leffler * would not allow the program to be killed. */ 81139beb93cSSam Leffler eloop.pending_terminate = 1; 81239beb93cSSam Leffler signal(SIGALRM, eloop_handle_alarm); 81339beb93cSSam Leffler alarm(2); 81439beb93cSSam Leffler } 81539beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 81639beb93cSSam Leffler 81739beb93cSSam Leffler eloop.signaled++; 81839beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) { 81939beb93cSSam Leffler if (eloop.signals[i].sig == sig) { 82039beb93cSSam Leffler eloop.signals[i].signaled++; 82139beb93cSSam Leffler break; 82239beb93cSSam Leffler } 82339beb93cSSam Leffler } 82439beb93cSSam Leffler } 82539beb93cSSam Leffler 82639beb93cSSam Leffler 82739beb93cSSam Leffler static void eloop_process_pending_signals(void) 82839beb93cSSam Leffler { 82939beb93cSSam Leffler int i; 83039beb93cSSam Leffler 83139beb93cSSam Leffler if (eloop.signaled == 0) 83239beb93cSSam Leffler return; 83339beb93cSSam Leffler eloop.signaled = 0; 83439beb93cSSam Leffler 83539beb93cSSam Leffler if (eloop.pending_terminate) { 83639beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 83739beb93cSSam Leffler alarm(0); 83839beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 83939beb93cSSam Leffler eloop.pending_terminate = 0; 84039beb93cSSam Leffler } 84139beb93cSSam Leffler 84239beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) { 84339beb93cSSam Leffler if (eloop.signals[i].signaled) { 84439beb93cSSam Leffler eloop.signals[i].signaled = 0; 84539beb93cSSam Leffler eloop.signals[i].handler(eloop.signals[i].sig, 84639beb93cSSam Leffler eloop.signals[i].user_data); 84739beb93cSSam Leffler } 84839beb93cSSam Leffler } 84939beb93cSSam Leffler } 85039beb93cSSam Leffler 85139beb93cSSam Leffler 85239beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler, 85339beb93cSSam Leffler void *user_data) 85439beb93cSSam Leffler { 85539beb93cSSam Leffler struct eloop_signal *tmp; 85639beb93cSSam Leffler 857f05cddf9SRui Paulo tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1, 85839beb93cSSam Leffler sizeof(struct eloop_signal)); 85939beb93cSSam Leffler if (tmp == NULL) 86039beb93cSSam Leffler return -1; 86139beb93cSSam Leffler 86239beb93cSSam Leffler tmp[eloop.signal_count].sig = sig; 86339beb93cSSam Leffler tmp[eloop.signal_count].user_data = user_data; 86439beb93cSSam Leffler tmp[eloop.signal_count].handler = handler; 86539beb93cSSam Leffler tmp[eloop.signal_count].signaled = 0; 86639beb93cSSam Leffler eloop.signal_count++; 86739beb93cSSam Leffler eloop.signals = tmp; 86839beb93cSSam Leffler signal(sig, eloop_handle_signal); 86939beb93cSSam Leffler 87039beb93cSSam Leffler return 0; 87139beb93cSSam Leffler } 87239beb93cSSam Leffler 87339beb93cSSam Leffler 87439beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler, 87539beb93cSSam Leffler void *user_data) 87639beb93cSSam Leffler { 87739beb93cSSam Leffler int ret = eloop_register_signal(SIGINT, handler, user_data); 87839beb93cSSam Leffler if (ret == 0) 87939beb93cSSam Leffler ret = eloop_register_signal(SIGTERM, handler, user_data); 88039beb93cSSam Leffler return ret; 88139beb93cSSam Leffler } 88239beb93cSSam Leffler 88339beb93cSSam Leffler 88439beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler, 88539beb93cSSam Leffler void *user_data) 88639beb93cSSam Leffler { 88739beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS 88839beb93cSSam Leffler return 0; 88939beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */ 89039beb93cSSam Leffler return eloop_register_signal(SIGHUP, handler, user_data); 89139beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 89239beb93cSSam Leffler } 89339beb93cSSam Leffler 89439beb93cSSam Leffler 89539beb93cSSam Leffler void eloop_run(void) 89639beb93cSSam Leffler { 897f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 898f05cddf9SRui Paulo int num_poll_fds; 899f05cddf9SRui Paulo int timeout_ms = 0; 9005b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 9015b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 90239beb93cSSam Leffler fd_set *rfds, *wfds, *efds; 90339beb93cSSam Leffler struct timeval _tv; 9045b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 9055b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 9065b9c547cSRui Paulo int timeout_ms = -1; 9075b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 908f05cddf9SRui Paulo int res; 9095b9c547cSRui Paulo struct os_reltime tv, now; 91039beb93cSSam Leffler 9115b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 91239beb93cSSam Leffler rfds = os_malloc(sizeof(*rfds)); 91339beb93cSSam Leffler wfds = os_malloc(sizeof(*wfds)); 91439beb93cSSam Leffler efds = os_malloc(sizeof(*efds)); 915e28a4053SRui Paulo if (rfds == NULL || wfds == NULL || efds == NULL) 91639beb93cSSam Leffler goto out; 9175b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 91839beb93cSSam Leffler 91939beb93cSSam Leffler while (!eloop.terminate && 920e28a4053SRui Paulo (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 92139beb93cSSam Leffler eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 922e28a4053SRui Paulo struct eloop_timeout *timeout; 923*325151a3SRui Paulo 924*325151a3SRui Paulo if (eloop.pending_terminate) { 925*325151a3SRui Paulo /* 926*325151a3SRui Paulo * This may happen in some corner cases where a signal 927*325151a3SRui Paulo * is received during a blocking operation. We need to 928*325151a3SRui Paulo * process the pending signals and exit if requested to 929*325151a3SRui Paulo * avoid hitting the SIGALRM limit if the blocking 930*325151a3SRui Paulo * operation took more than two seconds. 931*325151a3SRui Paulo */ 932*325151a3SRui Paulo eloop_process_pending_signals(); 933*325151a3SRui Paulo if (eloop.terminate) 934*325151a3SRui Paulo break; 935*325151a3SRui Paulo } 936*325151a3SRui Paulo 937e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 938e28a4053SRui Paulo list); 939e28a4053SRui Paulo if (timeout) { 9405b9c547cSRui Paulo os_get_reltime(&now); 9415b9c547cSRui Paulo if (os_reltime_before(&now, &timeout->time)) 9425b9c547cSRui Paulo os_reltime_sub(&timeout->time, &now, &tv); 94339beb93cSSam Leffler else 94439beb93cSSam Leffler tv.sec = tv.usec = 0; 9455b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) 946f05cddf9SRui Paulo timeout_ms = tv.sec * 1000 + tv.usec / 1000; 9475b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */ 9485b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 94939beb93cSSam Leffler _tv.tv_sec = tv.sec; 95039beb93cSSam Leffler _tv.tv_usec = tv.usec; 9515b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 95239beb93cSSam Leffler } 95339beb93cSSam Leffler 954f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 955f05cddf9SRui Paulo num_poll_fds = eloop_sock_table_set_fds( 956f05cddf9SRui Paulo &eloop.readers, &eloop.writers, &eloop.exceptions, 957f05cddf9SRui Paulo eloop.pollfds, eloop.pollfds_map, 958f05cddf9SRui Paulo eloop.max_pollfd_map); 959f05cddf9SRui Paulo res = poll(eloop.pollfds, num_poll_fds, 960f05cddf9SRui Paulo timeout ? timeout_ms : -1); 9615b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 9625b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 96339beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.readers, rfds); 96439beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.writers, wfds); 96539beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.exceptions, efds); 96639beb93cSSam Leffler res = select(eloop.max_sock + 1, rfds, wfds, efds, 967e28a4053SRui Paulo timeout ? &_tv : NULL); 9685b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 9695b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 9705b9c547cSRui Paulo if (eloop.count == 0) { 9715b9c547cSRui Paulo res = 0; 9725b9c547cSRui Paulo } else { 9735b9c547cSRui Paulo res = epoll_wait(eloop.epollfd, eloop.epoll_events, 9745b9c547cSRui Paulo eloop.count, timeout_ms); 9755b9c547cSRui Paulo } 9765b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 97739beb93cSSam Leffler if (res < 0 && errno != EINTR && errno != 0) { 9785b9c547cSRui Paulo wpa_printf(MSG_ERROR, "eloop: %s: %s", 9795b9c547cSRui Paulo #ifdef CONFIG_ELOOP_POLL 9805b9c547cSRui Paulo "poll" 9815b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 9825b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 9835b9c547cSRui Paulo "select" 9845b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 9855b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 9865b9c547cSRui Paulo "epoll" 9875b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 9885b9c547cSRui Paulo , strerror(errno)); 98939beb93cSSam Leffler goto out; 99039beb93cSSam Leffler } 991*325151a3SRui Paulo 992*325151a3SRui Paulo eloop.readers.changed = 0; 993*325151a3SRui Paulo eloop.writers.changed = 0; 994*325151a3SRui Paulo eloop.exceptions.changed = 0; 995*325151a3SRui Paulo 99639beb93cSSam Leffler eloop_process_pending_signals(); 99739beb93cSSam Leffler 99839beb93cSSam Leffler /* check if some registered timeouts have occurred */ 999e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 1000e28a4053SRui Paulo list); 1001e28a4053SRui Paulo if (timeout) { 10025b9c547cSRui Paulo os_get_reltime(&now); 10035b9c547cSRui Paulo if (!os_reltime_before(&now, &timeout->time)) { 1004e28a4053SRui Paulo void *eloop_data = timeout->eloop_data; 1005e28a4053SRui Paulo void *user_data = timeout->user_data; 1006e28a4053SRui Paulo eloop_timeout_handler handler = 1007e28a4053SRui Paulo timeout->handler; 1008e28a4053SRui Paulo eloop_remove_timeout(timeout); 1009e28a4053SRui Paulo handler(eloop_data, user_data); 101039beb93cSSam Leffler } 101139beb93cSSam Leffler 101239beb93cSSam Leffler } 101339beb93cSSam Leffler 101439beb93cSSam Leffler if (res <= 0) 101539beb93cSSam Leffler continue; 101639beb93cSSam Leffler 1017*325151a3SRui Paulo if (eloop.readers.changed || 1018*325151a3SRui Paulo eloop.writers.changed || 1019*325151a3SRui Paulo eloop.exceptions.changed) { 1020*325151a3SRui Paulo /* 1021*325151a3SRui Paulo * Sockets may have been closed and reopened with the 1022*325151a3SRui Paulo * same FD in the signal or timeout handlers, so we 1023*325151a3SRui Paulo * must skip the previous results and check again 1024*325151a3SRui Paulo * whether any of the currently registered sockets have 1025*325151a3SRui Paulo * events. 1026*325151a3SRui Paulo */ 1027*325151a3SRui Paulo continue; 1028*325151a3SRui Paulo } 1029*325151a3SRui Paulo 1030f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 1031f05cddf9SRui Paulo eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, 1032f05cddf9SRui Paulo &eloop.exceptions, eloop.pollfds_map, 1033f05cddf9SRui Paulo eloop.max_pollfd_map); 10345b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 10355b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 103639beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.readers, rfds); 103739beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.writers, wfds); 103839beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.exceptions, efds); 10395b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 10405b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 10415b9c547cSRui Paulo eloop_sock_table_dispatch(eloop.epoll_events, res); 10425b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 104339beb93cSSam Leffler } 104439beb93cSSam Leffler 10455b9c547cSRui Paulo eloop.terminate = 0; 104639beb93cSSam Leffler out: 10475b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 104839beb93cSSam Leffler os_free(rfds); 104939beb93cSSam Leffler os_free(wfds); 105039beb93cSSam Leffler os_free(efds); 10515b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 1052f05cddf9SRui Paulo return; 105339beb93cSSam Leffler } 105439beb93cSSam Leffler 105539beb93cSSam Leffler 105639beb93cSSam Leffler void eloop_terminate(void) 105739beb93cSSam Leffler { 105839beb93cSSam Leffler eloop.terminate = 1; 105939beb93cSSam Leffler } 106039beb93cSSam Leffler 106139beb93cSSam Leffler 106239beb93cSSam Leffler void eloop_destroy(void) 106339beb93cSSam Leffler { 106439beb93cSSam Leffler struct eloop_timeout *timeout, *prev; 10655b9c547cSRui Paulo struct os_reltime now; 106639beb93cSSam Leffler 10675b9c547cSRui Paulo os_get_reltime(&now); 1068e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 1069e28a4053SRui Paulo struct eloop_timeout, list) { 107039beb93cSSam Leffler int sec, usec; 1071e28a4053SRui Paulo sec = timeout->time.sec - now.sec; 1072e28a4053SRui Paulo usec = timeout->time.usec - now.usec; 1073e28a4053SRui Paulo if (timeout->time.usec < now.usec) { 107439beb93cSSam Leffler sec--; 107539beb93cSSam Leffler usec += 1000000; 107639beb93cSSam Leffler } 1077e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 1078e28a4053SRui Paulo "eloop_data=%p user_data=%p handler=%p", 1079e28a4053SRui Paulo sec, usec, timeout->eloop_data, timeout->user_data, 1080e28a4053SRui Paulo timeout->handler); 1081e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered timeout handler", 1082e28a4053SRui Paulo timeout->handler); 1083e28a4053SRui Paulo wpa_trace_dump("eloop timeout", timeout); 1084e28a4053SRui Paulo eloop_remove_timeout(timeout); 108539beb93cSSam Leffler } 108639beb93cSSam Leffler eloop_sock_table_destroy(&eloop.readers); 108739beb93cSSam Leffler eloop_sock_table_destroy(&eloop.writers); 108839beb93cSSam Leffler eloop_sock_table_destroy(&eloop.exceptions); 108939beb93cSSam Leffler os_free(eloop.signals); 1090f05cddf9SRui Paulo 1091f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 1092f05cddf9SRui Paulo os_free(eloop.pollfds); 1093f05cddf9SRui Paulo os_free(eloop.pollfds_map); 1094f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 10955b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 10965b9c547cSRui Paulo os_free(eloop.epoll_table); 10975b9c547cSRui Paulo os_free(eloop.epoll_events); 10985b9c547cSRui Paulo close(eloop.epollfd); 10995b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 110039beb93cSSam Leffler } 110139beb93cSSam Leffler 110239beb93cSSam Leffler 110339beb93cSSam Leffler int eloop_terminated(void) 110439beb93cSSam Leffler { 1105*325151a3SRui Paulo return eloop.terminate || eloop.pending_terminate; 110639beb93cSSam Leffler } 110739beb93cSSam Leffler 110839beb93cSSam Leffler 110939beb93cSSam Leffler void eloop_wait_for_read_sock(int sock) 111039beb93cSSam Leffler { 1111f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 1112f05cddf9SRui Paulo struct pollfd pfd; 1113f05cddf9SRui Paulo 1114f05cddf9SRui Paulo if (sock < 0) 1115f05cddf9SRui Paulo return; 1116f05cddf9SRui Paulo 1117f05cddf9SRui Paulo os_memset(&pfd, 0, sizeof(pfd)); 1118f05cddf9SRui Paulo pfd.fd = sock; 1119f05cddf9SRui Paulo pfd.events = POLLIN; 1120f05cddf9SRui Paulo 1121f05cddf9SRui Paulo poll(&pfd, 1, -1); 11225b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 11235b9c547cSRui Paulo #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) 11245b9c547cSRui Paulo /* 11255b9c547cSRui Paulo * We can use epoll() here. But epoll() requres 4 system calls. 11265b9c547cSRui Paulo * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for 11275b9c547cSRui Paulo * epoll fd. So select() is better for performance here. 11285b9c547cSRui Paulo */ 112939beb93cSSam Leffler fd_set rfds; 113039beb93cSSam Leffler 113139beb93cSSam Leffler if (sock < 0) 113239beb93cSSam Leffler return; 113339beb93cSSam Leffler 113439beb93cSSam Leffler FD_ZERO(&rfds); 113539beb93cSSam Leffler FD_SET(sock, &rfds); 113639beb93cSSam Leffler select(sock + 1, &rfds, NULL, NULL, NULL); 11375b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */ 113839beb93cSSam Leffler } 11395b9c547cSRui Paulo 11405b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 11415b9c547cSRui Paulo #undef CONFIG_ELOOP_SELECT 11425b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 1143