18dbcf02cSchristos /* 28dbcf02cSchristos * Event loop based on select() loop 38dbcf02cSchristos * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 48dbcf02cSchristos * 5316ee512Schristos * This software may be distributed under the terms of the BSD license. 6316ee512Schristos * See README for more details. 78dbcf02cSchristos */ 88dbcf02cSchristos 98dbcf02cSchristos #include "includes.h" 103c5783d3Schristos #include <assert.h> 118dbcf02cSchristos 128dbcf02cSchristos #include "common.h" 138dbcf02cSchristos #include "trace.h" 148dbcf02cSchristos #include "list.h" 158dbcf02cSchristos #include "eloop.h" 168dbcf02cSchristos 173c5783d3Schristos #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL) 183c5783d3Schristos #error Do not define both of poll and epoll 193c5783d3Schristos #endif 203c5783d3Schristos 216da92e7fSroy #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE) 226da92e7fSroy #error Do not define both of poll and kqueue 236da92e7fSroy #endif 246da92e7fSroy 256da92e7fSroy #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \ 266da92e7fSroy !defined(CONFIG_ELOOP_KQUEUE) 273c5783d3Schristos #define CONFIG_ELOOP_SELECT 283c5783d3Schristos #endif 293c5783d3Schristos 30316ee512Schristos #ifdef CONFIG_ELOOP_POLL 31316ee512Schristos #include <poll.h> 32316ee512Schristos #endif /* CONFIG_ELOOP_POLL */ 33316ee512Schristos 343c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 353c5783d3Schristos #include <sys/epoll.h> 363c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 378dbcf02cSchristos 386da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 396da92e7fSroy #include <sys/event.h> 406da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 416da92e7fSroy 428dbcf02cSchristos struct eloop_sock { 438dbcf02cSchristos int sock; 448dbcf02cSchristos void *eloop_data; 458dbcf02cSchristos void *user_data; 468dbcf02cSchristos eloop_sock_handler handler; 47042b6b47Sroy WPA_TRACE_REF(eloop); 48042b6b47Sroy WPA_TRACE_REF(user); 498dbcf02cSchristos WPA_TRACE_INFO 508dbcf02cSchristos }; 518dbcf02cSchristos 528dbcf02cSchristos struct eloop_timeout { 538dbcf02cSchristos struct dl_list list; 543c5783d3Schristos struct os_reltime time; 558dbcf02cSchristos void *eloop_data; 568dbcf02cSchristos void *user_data; 578dbcf02cSchristos eloop_timeout_handler handler; 58042b6b47Sroy WPA_TRACE_REF(eloop); 59042b6b47Sroy WPA_TRACE_REF(user); 608dbcf02cSchristos WPA_TRACE_INFO 618dbcf02cSchristos }; 628dbcf02cSchristos 638dbcf02cSchristos struct eloop_signal { 648dbcf02cSchristos int sig; 658dbcf02cSchristos void *user_data; 668dbcf02cSchristos eloop_signal_handler handler; 678dbcf02cSchristos int signaled; 688dbcf02cSchristos }; 698dbcf02cSchristos 708dbcf02cSchristos struct eloop_sock_table { 71*45d3cc13Schristos size_t count; 728dbcf02cSchristos struct eloop_sock *table; 733c5783d3Schristos eloop_event_type type; 748dbcf02cSchristos int changed; 758dbcf02cSchristos }; 768dbcf02cSchristos 778dbcf02cSchristos struct eloop_data { 788dbcf02cSchristos int max_sock; 798dbcf02cSchristos 80*45d3cc13Schristos size_t count; /* sum of all table counts */ 81316ee512Schristos #ifdef CONFIG_ELOOP_POLL 82*45d3cc13Schristos size_t max_pollfd_map; /* number of pollfds_map currently allocated */ 83*45d3cc13Schristos size_t max_poll_fds; /* number of pollfds currently allocated */ 84316ee512Schristos struct pollfd *pollfds; 85316ee512Schristos struct pollfd **pollfds_map; 86316ee512Schristos #endif /* CONFIG_ELOOP_POLL */ 876da92e7fSroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) 886da92e7fSroy int max_fd; 896da92e7fSroy struct eloop_sock *fd_table; 90ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ 913c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 923c5783d3Schristos int epollfd; 93*45d3cc13Schristos size_t epoll_max_event_num; 943c5783d3Schristos struct epoll_event *epoll_events; 953c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 966da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 976da92e7fSroy int kqueuefd; 98*45d3cc13Schristos size_t kqueue_nevents; 996da92e7fSroy struct kevent *kqueue_events; 1006da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 1018dbcf02cSchristos struct eloop_sock_table readers; 1028dbcf02cSchristos struct eloop_sock_table writers; 1038dbcf02cSchristos struct eloop_sock_table exceptions; 1048dbcf02cSchristos 1058dbcf02cSchristos struct dl_list timeout; 1068dbcf02cSchristos 107*45d3cc13Schristos size_t signal_count; 1088dbcf02cSchristos struct eloop_signal *signals; 1098dbcf02cSchristos int signaled; 1108dbcf02cSchristos int pending_terminate; 1118dbcf02cSchristos 1128dbcf02cSchristos int terminate; 1138dbcf02cSchristos }; 1148dbcf02cSchristos 1158dbcf02cSchristos static struct eloop_data eloop; 1168dbcf02cSchristos 1178dbcf02cSchristos 1188dbcf02cSchristos #ifdef WPA_TRACE 1198dbcf02cSchristos 1208dbcf02cSchristos static void eloop_sigsegv_handler(int sig) 1218dbcf02cSchristos { 1228dbcf02cSchristos wpa_trace_show("eloop SIGSEGV"); 1238dbcf02cSchristos abort(); 1248dbcf02cSchristos } 1258dbcf02cSchristos 1268dbcf02cSchristos static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 1278dbcf02cSchristos { 128*45d3cc13Schristos size_t i; 129*45d3cc13Schristos 1308dbcf02cSchristos if (table == NULL || table->table == NULL) 1318dbcf02cSchristos return; 1328dbcf02cSchristos for (i = 0; i < table->count; i++) { 1338dbcf02cSchristos wpa_trace_add_ref(&table->table[i], eloop, 1348dbcf02cSchristos table->table[i].eloop_data); 1358dbcf02cSchristos wpa_trace_add_ref(&table->table[i], user, 1368dbcf02cSchristos table->table[i].user_data); 1378dbcf02cSchristos } 1388dbcf02cSchristos } 1398dbcf02cSchristos 1408dbcf02cSchristos 1418dbcf02cSchristos static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 1428dbcf02cSchristos { 143*45d3cc13Schristos size_t i; 144*45d3cc13Schristos 1458dbcf02cSchristos if (table == NULL || table->table == NULL) 1468dbcf02cSchristos return; 1478dbcf02cSchristos for (i = 0; i < table->count; i++) { 1488dbcf02cSchristos wpa_trace_remove_ref(&table->table[i], eloop, 1498dbcf02cSchristos table->table[i].eloop_data); 1508dbcf02cSchristos wpa_trace_remove_ref(&table->table[i], user, 1518dbcf02cSchristos table->table[i].user_data); 1528dbcf02cSchristos } 1538dbcf02cSchristos } 1548dbcf02cSchristos 1558dbcf02cSchristos #else /* WPA_TRACE */ 1568dbcf02cSchristos 1578dbcf02cSchristos #define eloop_trace_sock_add_ref(table) do { } while (0) 1588dbcf02cSchristos #define eloop_trace_sock_remove_ref(table) do { } while (0) 1598dbcf02cSchristos 1608dbcf02cSchristos #endif /* WPA_TRACE */ 1618dbcf02cSchristos 1628dbcf02cSchristos 1638dbcf02cSchristos int eloop_init(void) 1648dbcf02cSchristos { 1658dbcf02cSchristos os_memset(&eloop, 0, sizeof(eloop)); 1668dbcf02cSchristos dl_list_init(&eloop.timeout); 1673c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 1683c5783d3Schristos eloop.epollfd = epoll_create1(0); 1693c5783d3Schristos if (eloop.epollfd < 0) { 170ecc36642Schristos wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s", 1713c5783d3Schristos __func__, strerror(errno)); 1723c5783d3Schristos return -1; 1733c5783d3Schristos } 1743c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 1756da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 1766da92e7fSroy eloop.kqueuefd = kqueue(); 1776da92e7fSroy if (eloop.kqueuefd < 0) { 178ecc36642Schristos wpa_printf(MSG_ERROR, "%s: kqueue failed: %s", 1796da92e7fSroy __func__, strerror(errno)); 1806da92e7fSroy return -1; 1816da92e7fSroy } 1826da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 183d2b81c07Sroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) 184d2b81c07Sroy eloop.readers.type = EVENT_TYPE_READ; 185d2b81c07Sroy eloop.writers.type = EVENT_TYPE_WRITE; 186d2b81c07Sroy eloop.exceptions.type = EVENT_TYPE_EXCEPTION; 187ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ 1888dbcf02cSchristos #ifdef WPA_TRACE 1898dbcf02cSchristos signal(SIGSEGV, eloop_sigsegv_handler); 1908dbcf02cSchristos #endif /* WPA_TRACE */ 1918dbcf02cSchristos return 0; 1928dbcf02cSchristos } 1938dbcf02cSchristos 194ecc36642Schristos 195d2b81c07Sroy #ifdef CONFIG_ELOOP_EPOLL 196d2b81c07Sroy static int eloop_sock_queue(int sock, eloop_event_type type) 197d2b81c07Sroy { 198d2b81c07Sroy struct epoll_event ev; 199d2b81c07Sroy 200d2b81c07Sroy os_memset(&ev, 0, sizeof(ev)); 201d2b81c07Sroy switch (type) { 202d2b81c07Sroy case EVENT_TYPE_READ: 203d2b81c07Sroy ev.events = EPOLLIN; 204d2b81c07Sroy break; 205d2b81c07Sroy case EVENT_TYPE_WRITE: 206d2b81c07Sroy ev.events = EPOLLOUT; 207d2b81c07Sroy break; 208d2b81c07Sroy /* 209d2b81c07Sroy * Exceptions are always checked when using epoll, but I suppose it's 210d2b81c07Sroy * possible that someone registered a socket *only* for exception 211d2b81c07Sroy * handling. 212d2b81c07Sroy */ 213d2b81c07Sroy case EVENT_TYPE_EXCEPTION: 214d2b81c07Sroy ev.events = EPOLLERR | EPOLLHUP; 215d2b81c07Sroy break; 216d2b81c07Sroy } 217d2b81c07Sroy ev.data.fd = sock; 218d2b81c07Sroy if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { 219ecc36642Schristos wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s", 220ecc36642Schristos __func__, sock, strerror(errno)); 221d2b81c07Sroy return -1; 222d2b81c07Sroy } 223d2b81c07Sroy return 0; 224d2b81c07Sroy } 225d2b81c07Sroy #endif /* CONFIG_ELOOP_EPOLL */ 226d2b81c07Sroy 227ecc36642Schristos 228d2b81c07Sroy #ifdef CONFIG_ELOOP_KQUEUE 229d2b81c07Sroy 230460bb4fcSchristos static short event_type_kevent_filter(eloop_event_type type) 231460bb4fcSchristos { 232d2b81c07Sroy switch (type) { 233d2b81c07Sroy case EVENT_TYPE_READ: 234460bb4fcSchristos return EVFILT_READ; 235d2b81c07Sroy case EVENT_TYPE_WRITE: 236460bb4fcSchristos return EVFILT_WRITE; 237d2b81c07Sroy default: 238460bb4fcSchristos return 0; 239d2b81c07Sroy } 240460bb4fcSchristos } 241460bb4fcSchristos 242460bb4fcSchristos 243460bb4fcSchristos static int eloop_sock_queue(int sock, eloop_event_type type) 244460bb4fcSchristos { 245460bb4fcSchristos struct kevent ke; 246460bb4fcSchristos 247460bb4fcSchristos EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0); 248d2b81c07Sroy if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) { 249ecc36642Schristos wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s", 250ecc36642Schristos __func__, sock, strerror(errno)); 251d2b81c07Sroy return -1; 252d2b81c07Sroy } 253d2b81c07Sroy return 0; 254d2b81c07Sroy } 255460bb4fcSchristos 256d2b81c07Sroy #endif /* CONFIG_ELOOP_KQUEUE */ 2578dbcf02cSchristos 258ecc36642Schristos 2598dbcf02cSchristos static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 2608dbcf02cSchristos int sock, eloop_sock_handler handler, 2618dbcf02cSchristos void *eloop_data, void *user_data) 2628dbcf02cSchristos { 2633c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 264d2b81c07Sroy struct epoll_event *temp_events; 2653c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 266fbb8252eSroy #ifdef CONFIG_ELOOP_KQUEUE 267fbb8252eSroy struct kevent *temp_events; 268fbb8252eSroy #endif /* CONFIG_ELOOP_EPOLL */ 269d2b81c07Sroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) 2706da92e7fSroy struct eloop_sock *temp_table; 271*45d3cc13Schristos size_t next; 272ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ 2738dbcf02cSchristos struct eloop_sock *tmp; 274316ee512Schristos int new_max_sock; 275316ee512Schristos 276316ee512Schristos if (sock > eloop.max_sock) 277316ee512Schristos new_max_sock = sock; 278316ee512Schristos else 279316ee512Schristos new_max_sock = eloop.max_sock; 2808dbcf02cSchristos 2818dbcf02cSchristos if (table == NULL) 2828dbcf02cSchristos return -1; 2838dbcf02cSchristos 284316ee512Schristos #ifdef CONFIG_ELOOP_POLL 285*45d3cc13Schristos if ((size_t) new_max_sock >= eloop.max_pollfd_map) { 286316ee512Schristos struct pollfd **nmap; 287316ee512Schristos nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50, 288316ee512Schristos sizeof(struct pollfd *)); 289316ee512Schristos if (nmap == NULL) 290316ee512Schristos return -1; 291316ee512Schristos 292316ee512Schristos eloop.max_pollfd_map = new_max_sock + 50; 293316ee512Schristos eloop.pollfds_map = nmap; 294316ee512Schristos } 295316ee512Schristos 296316ee512Schristos if (eloop.count + 1 > eloop.max_poll_fds) { 297316ee512Schristos struct pollfd *n; 298*45d3cc13Schristos size_t nmax = eloop.count + 1 + 50; 299*45d3cc13Schristos 300316ee512Schristos n = os_realloc_array(eloop.pollfds, nmax, 301316ee512Schristos sizeof(struct pollfd)); 302316ee512Schristos if (n == NULL) 303316ee512Schristos return -1; 304316ee512Schristos 305316ee512Schristos eloop.max_poll_fds = nmax; 306316ee512Schristos eloop.pollfds = n; 307316ee512Schristos } 308316ee512Schristos #endif /* CONFIG_ELOOP_POLL */ 3096da92e7fSroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) 3106da92e7fSroy if (new_max_sock >= eloop.max_fd) { 311460bb4fcSchristos next = new_max_sock + 16; 3126da92e7fSroy temp_table = os_realloc_array(eloop.fd_table, next, 3133c5783d3Schristos sizeof(struct eloop_sock)); 3143c5783d3Schristos if (temp_table == NULL) 3153c5783d3Schristos return -1; 3163c5783d3Schristos 3176da92e7fSroy eloop.max_fd = next; 3186da92e7fSroy eloop.fd_table = temp_table; 3193c5783d3Schristos } 320ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ 3213c5783d3Schristos 3226da92e7fSroy #ifdef CONFIG_ELOOP_EPOLL 3233c5783d3Schristos if (eloop.count + 1 > eloop.epoll_max_event_num) { 3243c5783d3Schristos next = eloop.epoll_max_event_num == 0 ? 8 : 3253c5783d3Schristos eloop.epoll_max_event_num * 2; 3263c5783d3Schristos temp_events = os_realloc_array(eloop.epoll_events, next, 3273c5783d3Schristos sizeof(struct epoll_event)); 3283c5783d3Schristos if (temp_events == NULL) { 329ecc36642Schristos wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s", 330ecc36642Schristos __func__, strerror(errno)); 3313c5783d3Schristos return -1; 3323c5783d3Schristos } 3333c5783d3Schristos 3343c5783d3Schristos eloop.epoll_max_event_num = next; 3353c5783d3Schristos eloop.epoll_events = temp_events; 3363c5783d3Schristos } 3373c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 3386da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 3396da92e7fSroy if (eloop.count + 1 > eloop.kqueue_nevents) { 3406da92e7fSroy next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2; 341fbb8252eSroy temp_events = os_malloc(next * sizeof(*temp_events)); 342ecc36642Schristos if (!temp_events) { 343ecc36642Schristos wpa_printf(MSG_ERROR, 344ecc36642Schristos "%s: malloc for kqueue failed: %s", 345ecc36642Schristos __func__, strerror(errno)); 3466da92e7fSroy return -1; 3476da92e7fSroy } 3486da92e7fSroy 349fbb8252eSroy os_free(eloop.kqueue_events); 350fbb8252eSroy eloop.kqueue_events = temp_events; 3516da92e7fSroy eloop.kqueue_nevents = next; 3526da92e7fSroy } 3536da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 354316ee512Schristos 3558dbcf02cSchristos eloop_trace_sock_remove_ref(table); 356316ee512Schristos tmp = os_realloc_array(table->table, table->count + 1, 357316ee512Schristos sizeof(struct eloop_sock)); 358299bbf24Schristos if (tmp == NULL) { 359299bbf24Schristos eloop_trace_sock_add_ref(table); 3608dbcf02cSchristos return -1; 361299bbf24Schristos } 3628dbcf02cSchristos 3638dbcf02cSchristos tmp[table->count].sock = sock; 3648dbcf02cSchristos tmp[table->count].eloop_data = eloop_data; 3658dbcf02cSchristos tmp[table->count].user_data = user_data; 3668dbcf02cSchristos tmp[table->count].handler = handler; 3678dbcf02cSchristos wpa_trace_record(&tmp[table->count]); 3688dbcf02cSchristos table->count++; 3698dbcf02cSchristos table->table = tmp; 370316ee512Schristos eloop.max_sock = new_max_sock; 371316ee512Schristos eloop.count++; 3728dbcf02cSchristos table->changed = 1; 3738dbcf02cSchristos eloop_trace_sock_add_ref(table); 3748dbcf02cSchristos 375d2b81c07Sroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) 376ecc36642Schristos if (eloop_sock_queue(sock, table->type) < 0) 3773c5783d3Schristos return -1; 3786da92e7fSroy os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1], 3793c5783d3Schristos sizeof(struct eloop_sock)); 380ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ 3818dbcf02cSchristos return 0; 3828dbcf02cSchristos } 3838dbcf02cSchristos 3848dbcf02cSchristos 3858dbcf02cSchristos static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 3868dbcf02cSchristos int sock) 3878dbcf02cSchristos { 3886da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 3896da92e7fSroy struct kevent ke; 390ecc36642Schristos #endif /* CONFIG_ELOOP_KQUEUE */ 391*45d3cc13Schristos size_t i; 3928dbcf02cSchristos 3938dbcf02cSchristos if (table == NULL || table->table == NULL || table->count == 0) 3948dbcf02cSchristos return; 3958dbcf02cSchristos 3968dbcf02cSchristos for (i = 0; i < table->count; i++) { 3978dbcf02cSchristos if (table->table[i].sock == sock) 3988dbcf02cSchristos break; 3998dbcf02cSchristos } 4008dbcf02cSchristos if (i == table->count) 4018dbcf02cSchristos return; 4028dbcf02cSchristos eloop_trace_sock_remove_ref(table); 4038dbcf02cSchristos if (i != table->count - 1) { 4048dbcf02cSchristos os_memmove(&table->table[i], &table->table[i + 1], 4058dbcf02cSchristos (table->count - i - 1) * 4068dbcf02cSchristos sizeof(struct eloop_sock)); 4078dbcf02cSchristos } 4088dbcf02cSchristos table->count--; 409316ee512Schristos eloop.count--; 4108dbcf02cSchristos table->changed = 1; 4118dbcf02cSchristos eloop_trace_sock_add_ref(table); 4123c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 4133c5783d3Schristos if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) { 414ecc36642Schristos wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s", 415ecc36642Schristos __func__, sock, strerror(errno)); 4163c5783d3Schristos return; 4173c5783d3Schristos } 4186da92e7fSroy os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock)); 4193c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 4206da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 421460bb4fcSchristos EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0, 422460bb4fcSchristos 0, 0); 423ecc36642Schristos if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) { 424ecc36642Schristos wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s", 425ecc36642Schristos __func__, sock, strerror(errno)); 4266da92e7fSroy return; 4276da92e7fSroy } 4286da92e7fSroy os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock)); 4296da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 4308dbcf02cSchristos } 4318dbcf02cSchristos 4328dbcf02cSchristos 433316ee512Schristos #ifdef CONFIG_ELOOP_POLL 434316ee512Schristos 435316ee512Schristos static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx) 436316ee512Schristos { 437316ee512Schristos if (fd < mx && fd >= 0) 438316ee512Schristos return pollfds_map[fd]; 439316ee512Schristos return NULL; 440316ee512Schristos } 441316ee512Schristos 442316ee512Schristos 443316ee512Schristos static int eloop_sock_table_set_fds(struct eloop_sock_table *readers, 444316ee512Schristos struct eloop_sock_table *writers, 445316ee512Schristos struct eloop_sock_table *exceptions, 446316ee512Schristos struct pollfd *pollfds, 447316ee512Schristos struct pollfd **pollfds_map, 448316ee512Schristos int max_pollfd_map) 449316ee512Schristos { 450*45d3cc13Schristos size_t i; 451316ee512Schristos int nxt = 0; 452316ee512Schristos int fd; 453316ee512Schristos struct pollfd *pfd; 454316ee512Schristos 455316ee512Schristos /* Clear pollfd lookup map. It will be re-populated below. */ 456316ee512Schristos os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map); 457316ee512Schristos 458316ee512Schristos if (readers && readers->table) { 459316ee512Schristos for (i = 0; i < readers->count; i++) { 460316ee512Schristos fd = readers->table[i].sock; 461316ee512Schristos assert(fd >= 0 && fd < max_pollfd_map); 462316ee512Schristos pollfds[nxt].fd = fd; 463316ee512Schristos pollfds[nxt].events = POLLIN; 464316ee512Schristos pollfds[nxt].revents = 0; 465316ee512Schristos pollfds_map[fd] = &(pollfds[nxt]); 466316ee512Schristos nxt++; 467316ee512Schristos } 468316ee512Schristos } 469316ee512Schristos 470316ee512Schristos if (writers && writers->table) { 471316ee512Schristos for (i = 0; i < writers->count; i++) { 472316ee512Schristos /* 473316ee512Schristos * See if we already added this descriptor, update it 474316ee512Schristos * if so. 475316ee512Schristos */ 476316ee512Schristos fd = writers->table[i].sock; 477316ee512Schristos assert(fd >= 0 && fd < max_pollfd_map); 478316ee512Schristos pfd = pollfds_map[fd]; 479316ee512Schristos if (!pfd) { 480316ee512Schristos pfd = &(pollfds[nxt]); 481316ee512Schristos pfd->events = 0; 482316ee512Schristos pfd->fd = fd; 483316ee512Schristos pollfds[i].revents = 0; 484316ee512Schristos pollfds_map[fd] = pfd; 485316ee512Schristos nxt++; 486316ee512Schristos } 487316ee512Schristos pfd->events |= POLLOUT; 488316ee512Schristos } 489316ee512Schristos } 490316ee512Schristos 491316ee512Schristos /* 492316ee512Schristos * Exceptions are always checked when using poll, but I suppose it's 493316ee512Schristos * possible that someone registered a socket *only* for exception 494316ee512Schristos * handling. Set the POLLIN bit in this case. 495316ee512Schristos */ 496316ee512Schristos if (exceptions && exceptions->table) { 497316ee512Schristos for (i = 0; i < exceptions->count; i++) { 498316ee512Schristos /* 499316ee512Schristos * See if we already added this descriptor, just use it 500316ee512Schristos * if so. 501316ee512Schristos */ 502316ee512Schristos fd = exceptions->table[i].sock; 503316ee512Schristos assert(fd >= 0 && fd < max_pollfd_map); 504316ee512Schristos pfd = pollfds_map[fd]; 505316ee512Schristos if (!pfd) { 506316ee512Schristos pfd = &(pollfds[nxt]); 507316ee512Schristos pfd->events = POLLIN; 508316ee512Schristos pfd->fd = fd; 509316ee512Schristos pollfds[i].revents = 0; 510316ee512Schristos pollfds_map[fd] = pfd; 511316ee512Schristos nxt++; 512316ee512Schristos } 513316ee512Schristos } 514316ee512Schristos } 515316ee512Schristos 516316ee512Schristos return nxt; 517316ee512Schristos } 518316ee512Schristos 519316ee512Schristos 520316ee512Schristos static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table, 521316ee512Schristos struct pollfd **pollfds_map, 522316ee512Schristos int max_pollfd_map, 523316ee512Schristos short int revents) 524316ee512Schristos { 525*45d3cc13Schristos size_t i; 526316ee512Schristos struct pollfd *pfd; 527316ee512Schristos 528316ee512Schristos if (!table || !table->table) 529316ee512Schristos return 0; 530316ee512Schristos 531316ee512Schristos table->changed = 0; 532316ee512Schristos for (i = 0; i < table->count; i++) { 533316ee512Schristos pfd = find_pollfd(pollfds_map, table->table[i].sock, 534316ee512Schristos max_pollfd_map); 535316ee512Schristos if (!pfd) 536316ee512Schristos continue; 537316ee512Schristos 538316ee512Schristos if (!(pfd->revents & revents)) 539316ee512Schristos continue; 540316ee512Schristos 541316ee512Schristos table->table[i].handler(table->table[i].sock, 542316ee512Schristos table->table[i].eloop_data, 543316ee512Schristos table->table[i].user_data); 544316ee512Schristos if (table->changed) 545316ee512Schristos return 1; 546316ee512Schristos } 547316ee512Schristos 548316ee512Schristos return 0; 549316ee512Schristos } 550316ee512Schristos 551316ee512Schristos 552316ee512Schristos static void eloop_sock_table_dispatch(struct eloop_sock_table *readers, 553316ee512Schristos struct eloop_sock_table *writers, 554316ee512Schristos struct eloop_sock_table *exceptions, 555316ee512Schristos struct pollfd **pollfds_map, 556316ee512Schristos int max_pollfd_map) 557316ee512Schristos { 558316ee512Schristos if (eloop_sock_table_dispatch_table(readers, pollfds_map, 559316ee512Schristos max_pollfd_map, POLLIN | POLLERR | 560316ee512Schristos POLLHUP)) 561316ee512Schristos return; /* pollfds may be invalid at this point */ 562316ee512Schristos 563316ee512Schristos if (eloop_sock_table_dispatch_table(writers, pollfds_map, 564316ee512Schristos max_pollfd_map, POLLOUT)) 565316ee512Schristos return; /* pollfds may be invalid at this point */ 566316ee512Schristos 567316ee512Schristos eloop_sock_table_dispatch_table(exceptions, pollfds_map, 568316ee512Schristos max_pollfd_map, POLLERR | POLLHUP); 569316ee512Schristos } 570316ee512Schristos 5713c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */ 5723c5783d3Schristos 5733c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 574316ee512Schristos 5758dbcf02cSchristos static void eloop_sock_table_set_fds(struct eloop_sock_table *table, 5768dbcf02cSchristos fd_set *fds) 5778dbcf02cSchristos { 578*45d3cc13Schristos size_t i; 5798dbcf02cSchristos 5808dbcf02cSchristos FD_ZERO(fds); 5818dbcf02cSchristos 5828dbcf02cSchristos if (table->table == NULL) 5838dbcf02cSchristos return; 5848dbcf02cSchristos 5853c5783d3Schristos for (i = 0; i < table->count; i++) { 5863c5783d3Schristos assert(table->table[i].sock >= 0); 5878dbcf02cSchristos FD_SET(table->table[i].sock, fds); 5888dbcf02cSchristos } 5893c5783d3Schristos } 5908dbcf02cSchristos 5918dbcf02cSchristos 5928dbcf02cSchristos static void eloop_sock_table_dispatch(struct eloop_sock_table *table, 5938dbcf02cSchristos fd_set *fds) 5948dbcf02cSchristos { 595*45d3cc13Schristos size_t i; 5968dbcf02cSchristos 5978dbcf02cSchristos if (table == NULL || table->table == NULL) 5988dbcf02cSchristos return; 5998dbcf02cSchristos 6008dbcf02cSchristos table->changed = 0; 6018dbcf02cSchristos for (i = 0; i < table->count; i++) { 6028dbcf02cSchristos if (FD_ISSET(table->table[i].sock, fds)) { 6038dbcf02cSchristos table->table[i].handler(table->table[i].sock, 6048dbcf02cSchristos table->table[i].eloop_data, 6058dbcf02cSchristos table->table[i].user_data); 6068dbcf02cSchristos if (table->changed) 6078dbcf02cSchristos break; 6088dbcf02cSchristos } 6098dbcf02cSchristos } 6108dbcf02cSchristos } 6118dbcf02cSchristos 6123c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 6133c5783d3Schristos 6143c5783d3Schristos 6153c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 6163c5783d3Schristos static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) 6173c5783d3Schristos { 6183c5783d3Schristos struct eloop_sock *table; 6193c5783d3Schristos int i; 6203c5783d3Schristos 6213c5783d3Schristos for (i = 0; i < nfds; i++) { 6226da92e7fSroy table = &eloop.fd_table[events[i].data.fd]; 6233c5783d3Schristos if (table->handler == NULL) 6243c5783d3Schristos continue; 6253c5783d3Schristos table->handler(table->sock, table->eloop_data, 6263c5783d3Schristos table->user_data); 627042b6b47Sroy if (eloop.readers.changed || 628042b6b47Sroy eloop.writers.changed || 629042b6b47Sroy eloop.exceptions.changed) 630042b6b47Sroy break; 6313c5783d3Schristos } 6323c5783d3Schristos } 6333c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 634316ee512Schristos 6358dbcf02cSchristos 6366da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 637ecc36642Schristos 6386da92e7fSroy static void eloop_sock_table_dispatch(struct kevent *events, int nfds) 6396da92e7fSroy { 6406da92e7fSroy struct eloop_sock *table; 6416da92e7fSroy int i; 6426da92e7fSroy 6436da92e7fSroy for (i = 0; i < nfds; i++) { 6446da92e7fSroy table = &eloop.fd_table[events[i].ident]; 6456da92e7fSroy if (table->handler == NULL) 6466da92e7fSroy continue; 6476da92e7fSroy table->handler(table->sock, table->eloop_data, 6486da92e7fSroy table->user_data); 649042b6b47Sroy if (eloop.readers.changed || 650042b6b47Sroy eloop.writers.changed || 651042b6b47Sroy eloop.exceptions.changed) 652042b6b47Sroy break; 6536da92e7fSroy } 6546da92e7fSroy } 655d2b81c07Sroy 656ecc36642Schristos 657d2b81c07Sroy static int eloop_sock_table_requeue(struct eloop_sock_table *table) 658d2b81c07Sroy { 659*45d3cc13Schristos size_t i; 660*45d3cc13Schristos int r; 661d2b81c07Sroy 662d2b81c07Sroy r = 0; 663d2b81c07Sroy for (i = 0; i < table->count && table->table; i++) { 664d2b81c07Sroy if (eloop_sock_queue(table->table[i].sock, table->type) == -1) 665d2b81c07Sroy r = -1; 666d2b81c07Sroy } 667d2b81c07Sroy return r; 668d2b81c07Sroy } 669d2b81c07Sroy 670ecc36642Schristos #endif /* CONFIG_ELOOP_KQUEUE */ 671ecc36642Schristos 672ecc36642Schristos 673d2b81c07Sroy int eloop_sock_requeue(void) 674d2b81c07Sroy { 675d2b81c07Sroy int r = 0; 676d2b81c07Sroy 677ecc36642Schristos #ifdef CONFIG_ELOOP_KQUEUE 678d2b81c07Sroy close(eloop.kqueuefd); 679d2b81c07Sroy eloop.kqueuefd = kqueue(); 680d2b81c07Sroy if (eloop.kqueuefd < 0) { 681ecc36642Schristos wpa_printf(MSG_ERROR, "%s: kqueue failed: %s", 682d2b81c07Sroy __func__, strerror(errno)); 683d2b81c07Sroy return -1; 684d2b81c07Sroy } 685d2b81c07Sroy 686ecc36642Schristos if (eloop_sock_table_requeue(&eloop.readers) < 0) 687d2b81c07Sroy r = -1; 688ecc36642Schristos if (eloop_sock_table_requeue(&eloop.writers) < 0) 689d2b81c07Sroy r = -1; 690ecc36642Schristos if (eloop_sock_table_requeue(&eloop.exceptions) < 0) 691d2b81c07Sroy r = -1; 692ecc36642Schristos #endif /* CONFIG_ELOOP_KQUEUE */ 693d2b81c07Sroy 694d2b81c07Sroy return r; 695d2b81c07Sroy } 696d2b81c07Sroy 6976da92e7fSroy 6988dbcf02cSchristos static void eloop_sock_table_destroy(struct eloop_sock_table *table) 6998dbcf02cSchristos { 7008dbcf02cSchristos if (table) { 701*45d3cc13Schristos size_t i; 702*45d3cc13Schristos 7038dbcf02cSchristos for (i = 0; i < table->count && table->table; i++) { 7048dbcf02cSchristos wpa_printf(MSG_INFO, "ELOOP: remaining socket: " 7058dbcf02cSchristos "sock=%d eloop_data=%p user_data=%p " 7068dbcf02cSchristos "handler=%p", 7078dbcf02cSchristos table->table[i].sock, 7088dbcf02cSchristos table->table[i].eloop_data, 7098dbcf02cSchristos table->table[i].user_data, 7108dbcf02cSchristos table->table[i].handler); 7118dbcf02cSchristos wpa_trace_dump_funcname("eloop unregistered socket " 7128dbcf02cSchristos "handler", 7138dbcf02cSchristos table->table[i].handler); 7148dbcf02cSchristos wpa_trace_dump("eloop sock", &table->table[i]); 7158dbcf02cSchristos } 7168dbcf02cSchristos os_free(table->table); 7178dbcf02cSchristos } 7188dbcf02cSchristos } 7198dbcf02cSchristos 7208dbcf02cSchristos 7218dbcf02cSchristos int eloop_register_read_sock(int sock, eloop_sock_handler handler, 7228dbcf02cSchristos void *eloop_data, void *user_data) 7238dbcf02cSchristos { 7248dbcf02cSchristos return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 7258dbcf02cSchristos eloop_data, user_data); 7268dbcf02cSchristos } 7278dbcf02cSchristos 7288dbcf02cSchristos 7298dbcf02cSchristos void eloop_unregister_read_sock(int sock) 7308dbcf02cSchristos { 7318dbcf02cSchristos eloop_unregister_sock(sock, EVENT_TYPE_READ); 7328dbcf02cSchristos } 7338dbcf02cSchristos 7348dbcf02cSchristos 7358dbcf02cSchristos static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 7368dbcf02cSchristos { 7378dbcf02cSchristos switch (type) { 7388dbcf02cSchristos case EVENT_TYPE_READ: 7398dbcf02cSchristos return &eloop.readers; 7408dbcf02cSchristos case EVENT_TYPE_WRITE: 7418dbcf02cSchristos return &eloop.writers; 7428dbcf02cSchristos case EVENT_TYPE_EXCEPTION: 7438dbcf02cSchristos return &eloop.exceptions; 7448dbcf02cSchristos } 7458dbcf02cSchristos 7468dbcf02cSchristos return NULL; 7478dbcf02cSchristos } 7488dbcf02cSchristos 7498dbcf02cSchristos 7508dbcf02cSchristos int eloop_register_sock(int sock, eloop_event_type type, 7518dbcf02cSchristos eloop_sock_handler handler, 7528dbcf02cSchristos void *eloop_data, void *user_data) 7538dbcf02cSchristos { 7548dbcf02cSchristos struct eloop_sock_table *table; 7558dbcf02cSchristos 7563c5783d3Schristos assert(sock >= 0); 7578dbcf02cSchristos table = eloop_get_sock_table(type); 7588dbcf02cSchristos return eloop_sock_table_add_sock(table, sock, handler, 7598dbcf02cSchristos eloop_data, user_data); 7608dbcf02cSchristos } 7618dbcf02cSchristos 7628dbcf02cSchristos 7638dbcf02cSchristos void eloop_unregister_sock(int sock, eloop_event_type type) 7648dbcf02cSchristos { 7658dbcf02cSchristos struct eloop_sock_table *table; 7668dbcf02cSchristos 7678dbcf02cSchristos table = eloop_get_sock_table(type); 7688dbcf02cSchristos eloop_sock_table_remove_sock(table, sock); 7698dbcf02cSchristos } 7708dbcf02cSchristos 7718dbcf02cSchristos 7728dbcf02cSchristos int eloop_register_timeout(unsigned int secs, unsigned int usecs, 7738dbcf02cSchristos eloop_timeout_handler handler, 7748dbcf02cSchristos void *eloop_data, void *user_data) 7758dbcf02cSchristos { 7768dbcf02cSchristos struct eloop_timeout *timeout, *tmp; 777b8fa3219Schristos os_time_t now_sec; 7788dbcf02cSchristos 7798dbcf02cSchristos timeout = os_zalloc(sizeof(*timeout)); 7808dbcf02cSchristos if (timeout == NULL) 7818dbcf02cSchristos return -1; 7823c5783d3Schristos if (os_get_reltime(&timeout->time) < 0) { 7838dbcf02cSchristos os_free(timeout); 7848dbcf02cSchristos return -1; 7858dbcf02cSchristos } 786b8fa3219Schristos now_sec = timeout->time.sec; 7878dbcf02cSchristos timeout->time.sec += secs; 788*45d3cc13Schristos if (timeout->time.sec < now_sec) 789*45d3cc13Schristos goto overflow; 7908dbcf02cSchristos timeout->time.usec += usecs; 7918dbcf02cSchristos while (timeout->time.usec >= 1000000) { 7928dbcf02cSchristos timeout->time.sec++; 7938dbcf02cSchristos timeout->time.usec -= 1000000; 7948dbcf02cSchristos } 795*45d3cc13Schristos if (timeout->time.sec < now_sec) 796*45d3cc13Schristos goto overflow; 7978dbcf02cSchristos timeout->eloop_data = eloop_data; 7988dbcf02cSchristos timeout->user_data = user_data; 7998dbcf02cSchristos timeout->handler = handler; 8008dbcf02cSchristos wpa_trace_add_ref(timeout, eloop, eloop_data); 8018dbcf02cSchristos wpa_trace_add_ref(timeout, user, user_data); 8028dbcf02cSchristos wpa_trace_record(timeout); 8038dbcf02cSchristos 8048dbcf02cSchristos /* Maintain timeouts in order of increasing time */ 8058dbcf02cSchristos dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 8063c5783d3Schristos if (os_reltime_before(&timeout->time, &tmp->time)) { 8078dbcf02cSchristos dl_list_add(tmp->list.prev, &timeout->list); 8088dbcf02cSchristos return 0; 8098dbcf02cSchristos } 8108dbcf02cSchristos } 8118dbcf02cSchristos dl_list_add_tail(&eloop.timeout, &timeout->list); 8128dbcf02cSchristos 8138dbcf02cSchristos return 0; 814*45d3cc13Schristos 815*45d3cc13Schristos overflow: 816*45d3cc13Schristos /* 817*45d3cc13Schristos * Integer overflow - assume long enough timeout to be assumed 818*45d3cc13Schristos * to be infinite, i.e., the timeout would never happen. 819*45d3cc13Schristos */ 820*45d3cc13Schristos wpa_printf(MSG_DEBUG, 821*45d3cc13Schristos "ELOOP: Too long timeout (secs=%u usecs=%u) to ever happen - ignore it", 822*45d3cc13Schristos secs,usecs); 823*45d3cc13Schristos os_free(timeout); 824*45d3cc13Schristos return 0; 8258dbcf02cSchristos } 8268dbcf02cSchristos 8278dbcf02cSchristos 8288dbcf02cSchristos static void eloop_remove_timeout(struct eloop_timeout *timeout) 8298dbcf02cSchristos { 8308dbcf02cSchristos dl_list_del(&timeout->list); 8318dbcf02cSchristos wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 8328dbcf02cSchristos wpa_trace_remove_ref(timeout, user, timeout->user_data); 8338dbcf02cSchristos os_free(timeout); 8348dbcf02cSchristos } 8358dbcf02cSchristos 8368dbcf02cSchristos 8378dbcf02cSchristos int eloop_cancel_timeout(eloop_timeout_handler handler, 8388dbcf02cSchristos void *eloop_data, void *user_data) 8398dbcf02cSchristos { 8408dbcf02cSchristos struct eloop_timeout *timeout, *prev; 8418dbcf02cSchristos int removed = 0; 8428dbcf02cSchristos 8438dbcf02cSchristos dl_list_for_each_safe(timeout, prev, &eloop.timeout, 8448dbcf02cSchristos struct eloop_timeout, list) { 8458dbcf02cSchristos if (timeout->handler == handler && 8468dbcf02cSchristos (timeout->eloop_data == eloop_data || 8478dbcf02cSchristos eloop_data == ELOOP_ALL_CTX) && 8488dbcf02cSchristos (timeout->user_data == user_data || 8498dbcf02cSchristos user_data == ELOOP_ALL_CTX)) { 8508dbcf02cSchristos eloop_remove_timeout(timeout); 8518dbcf02cSchristos removed++; 8528dbcf02cSchristos } 8538dbcf02cSchristos } 8548dbcf02cSchristos 8558dbcf02cSchristos return removed; 8568dbcf02cSchristos } 8578dbcf02cSchristos 8588dbcf02cSchristos 8593c5783d3Schristos int eloop_cancel_timeout_one(eloop_timeout_handler handler, 8603c5783d3Schristos void *eloop_data, void *user_data, 8613c5783d3Schristos struct os_reltime *remaining) 8623c5783d3Schristos { 8633c5783d3Schristos struct eloop_timeout *timeout, *prev; 8643c5783d3Schristos int removed = 0; 8653c5783d3Schristos struct os_reltime now; 8663c5783d3Schristos 8673c5783d3Schristos os_get_reltime(&now); 8683c5783d3Schristos remaining->sec = remaining->usec = 0; 8693c5783d3Schristos 8703c5783d3Schristos dl_list_for_each_safe(timeout, prev, &eloop.timeout, 8713c5783d3Schristos struct eloop_timeout, list) { 8723c5783d3Schristos if (timeout->handler == handler && 8733c5783d3Schristos (timeout->eloop_data == eloop_data) && 8743c5783d3Schristos (timeout->user_data == user_data)) { 8753c5783d3Schristos removed = 1; 8763c5783d3Schristos if (os_reltime_before(&now, &timeout->time)) 8773c5783d3Schristos os_reltime_sub(&timeout->time, &now, remaining); 8783c5783d3Schristos eloop_remove_timeout(timeout); 8793c5783d3Schristos break; 8803c5783d3Schristos } 8813c5783d3Schristos } 8823c5783d3Schristos return removed; 8833c5783d3Schristos } 8843c5783d3Schristos 8853c5783d3Schristos 8868dbcf02cSchristos int eloop_is_timeout_registered(eloop_timeout_handler handler, 8878dbcf02cSchristos void *eloop_data, void *user_data) 8888dbcf02cSchristos { 8898dbcf02cSchristos struct eloop_timeout *tmp; 8908dbcf02cSchristos 8918dbcf02cSchristos dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 8928dbcf02cSchristos if (tmp->handler == handler && 8938dbcf02cSchristos tmp->eloop_data == eloop_data && 8948dbcf02cSchristos tmp->user_data == user_data) 8958dbcf02cSchristos return 1; 8968dbcf02cSchristos } 8978dbcf02cSchristos 8988dbcf02cSchristos return 0; 8998dbcf02cSchristos } 9008dbcf02cSchristos 9018dbcf02cSchristos 9023c5783d3Schristos int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, 9033c5783d3Schristos eloop_timeout_handler handler, void *eloop_data, 9043c5783d3Schristos void *user_data) 9053c5783d3Schristos { 9063c5783d3Schristos struct os_reltime now, requested, remaining; 9073c5783d3Schristos struct eloop_timeout *tmp; 9083c5783d3Schristos 9093c5783d3Schristos dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 9103c5783d3Schristos if (tmp->handler == handler && 9113c5783d3Schristos tmp->eloop_data == eloop_data && 9123c5783d3Schristos tmp->user_data == user_data) { 9133c5783d3Schristos requested.sec = req_secs; 9143c5783d3Schristos requested.usec = req_usecs; 9153c5783d3Schristos os_get_reltime(&now); 9163c5783d3Schristos os_reltime_sub(&tmp->time, &now, &remaining); 9173c5783d3Schristos if (os_reltime_before(&requested, &remaining)) { 9183c5783d3Schristos eloop_cancel_timeout(handler, eloop_data, 9193c5783d3Schristos user_data); 9203c5783d3Schristos eloop_register_timeout(requested.sec, 9213c5783d3Schristos requested.usec, 9223c5783d3Schristos handler, eloop_data, 9233c5783d3Schristos user_data); 9243c5783d3Schristos return 1; 9253c5783d3Schristos } 9263c5783d3Schristos return 0; 9273c5783d3Schristos } 9283c5783d3Schristos } 9293c5783d3Schristos 9303c5783d3Schristos return -1; 9313c5783d3Schristos } 9323c5783d3Schristos 9333c5783d3Schristos 9343c5783d3Schristos int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, 9353c5783d3Schristos eloop_timeout_handler handler, void *eloop_data, 9363c5783d3Schristos void *user_data) 9373c5783d3Schristos { 9383c5783d3Schristos struct os_reltime now, requested, remaining; 9393c5783d3Schristos struct eloop_timeout *tmp; 9403c5783d3Schristos 9413c5783d3Schristos dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 9423c5783d3Schristos if (tmp->handler == handler && 9433c5783d3Schristos tmp->eloop_data == eloop_data && 9443c5783d3Schristos tmp->user_data == user_data) { 9453c5783d3Schristos requested.sec = req_secs; 9463c5783d3Schristos requested.usec = req_usecs; 9473c5783d3Schristos os_get_reltime(&now); 9483c5783d3Schristos os_reltime_sub(&tmp->time, &now, &remaining); 9493c5783d3Schristos if (os_reltime_before(&remaining, &requested)) { 9503c5783d3Schristos eloop_cancel_timeout(handler, eloop_data, 9513c5783d3Schristos user_data); 9523c5783d3Schristos eloop_register_timeout(requested.sec, 9533c5783d3Schristos requested.usec, 9543c5783d3Schristos handler, eloop_data, 9553c5783d3Schristos user_data); 9563c5783d3Schristos return 1; 9573c5783d3Schristos } 9583c5783d3Schristos return 0; 9593c5783d3Schristos } 9603c5783d3Schristos } 9613c5783d3Schristos 9623c5783d3Schristos return -1; 9633c5783d3Schristos } 9643c5783d3Schristos 9653c5783d3Schristos 9668dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 9678dbcf02cSchristos static void eloop_handle_alarm(int sig) 9688dbcf02cSchristos { 9698dbcf02cSchristos wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 9708dbcf02cSchristos "two seconds. Looks like there\n" 9718dbcf02cSchristos "is a bug that ends up in a busy loop that " 9728dbcf02cSchristos "prevents clean shutdown.\n" 9738dbcf02cSchristos "Killing program forcefully.\n"); 9748dbcf02cSchristos exit(1); 9758dbcf02cSchristos } 9768dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 9778dbcf02cSchristos 9788dbcf02cSchristos 9798dbcf02cSchristos static void eloop_handle_signal(int sig) 9808dbcf02cSchristos { 981*45d3cc13Schristos size_t i; 9828dbcf02cSchristos 9838dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 9848dbcf02cSchristos if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 9858dbcf02cSchristos /* Use SIGALRM to break out from potential busy loops that 9868dbcf02cSchristos * would not allow the program to be killed. */ 9878dbcf02cSchristos eloop.pending_terminate = 1; 9888dbcf02cSchristos signal(SIGALRM, eloop_handle_alarm); 9898dbcf02cSchristos alarm(2); 9908dbcf02cSchristos } 9918dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 9928dbcf02cSchristos 9938dbcf02cSchristos eloop.signaled++; 9948dbcf02cSchristos for (i = 0; i < eloop.signal_count; i++) { 9958dbcf02cSchristos if (eloop.signals[i].sig == sig) { 9968dbcf02cSchristos eloop.signals[i].signaled++; 9978dbcf02cSchristos break; 9988dbcf02cSchristos } 9998dbcf02cSchristos } 10008dbcf02cSchristos } 10018dbcf02cSchristos 10028dbcf02cSchristos 10038dbcf02cSchristos static void eloop_process_pending_signals(void) 10048dbcf02cSchristos { 1005*45d3cc13Schristos size_t i; 10068dbcf02cSchristos 10078dbcf02cSchristos if (eloop.signaled == 0) 10088dbcf02cSchristos return; 10098dbcf02cSchristos eloop.signaled = 0; 10108dbcf02cSchristos 10118dbcf02cSchristos if (eloop.pending_terminate) { 10128dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 10138dbcf02cSchristos alarm(0); 10148dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 10158dbcf02cSchristos eloop.pending_terminate = 0; 10168dbcf02cSchristos } 10178dbcf02cSchristos 10188dbcf02cSchristos for (i = 0; i < eloop.signal_count; i++) { 10198dbcf02cSchristos if (eloop.signals[i].signaled) { 10208dbcf02cSchristos eloop.signals[i].signaled = 0; 10218dbcf02cSchristos eloop.signals[i].handler(eloop.signals[i].sig, 10228dbcf02cSchristos eloop.signals[i].user_data); 10238dbcf02cSchristos } 10248dbcf02cSchristos } 10258dbcf02cSchristos } 10268dbcf02cSchristos 10278dbcf02cSchristos 10288dbcf02cSchristos int eloop_register_signal(int sig, eloop_signal_handler handler, 10298dbcf02cSchristos void *user_data) 10308dbcf02cSchristos { 10318dbcf02cSchristos struct eloop_signal *tmp; 10328dbcf02cSchristos 1033316ee512Schristos tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1, 10348dbcf02cSchristos sizeof(struct eloop_signal)); 10358dbcf02cSchristos if (tmp == NULL) 10368dbcf02cSchristos return -1; 10378dbcf02cSchristos 10388dbcf02cSchristos tmp[eloop.signal_count].sig = sig; 10398dbcf02cSchristos tmp[eloop.signal_count].user_data = user_data; 10408dbcf02cSchristos tmp[eloop.signal_count].handler = handler; 10418dbcf02cSchristos tmp[eloop.signal_count].signaled = 0; 10428dbcf02cSchristos eloop.signal_count++; 10438dbcf02cSchristos eloop.signals = tmp; 10448dbcf02cSchristos signal(sig, eloop_handle_signal); 10458dbcf02cSchristos 10468dbcf02cSchristos return 0; 10478dbcf02cSchristos } 10488dbcf02cSchristos 10498dbcf02cSchristos 10508dbcf02cSchristos int eloop_register_signal_terminate(eloop_signal_handler handler, 10518dbcf02cSchristos void *user_data) 10528dbcf02cSchristos { 10538dbcf02cSchristos int ret = eloop_register_signal(SIGINT, handler, user_data); 10548dbcf02cSchristos if (ret == 0) 10558dbcf02cSchristos ret = eloop_register_signal(SIGTERM, handler, user_data); 10568dbcf02cSchristos return ret; 10578dbcf02cSchristos } 10588dbcf02cSchristos 10598dbcf02cSchristos 10608dbcf02cSchristos int eloop_register_signal_reconfig(eloop_signal_handler handler, 10618dbcf02cSchristos void *user_data) 10628dbcf02cSchristos { 10638dbcf02cSchristos #ifdef CONFIG_NATIVE_WINDOWS 10648dbcf02cSchristos return 0; 10658dbcf02cSchristos #else /* CONFIG_NATIVE_WINDOWS */ 10668dbcf02cSchristos return eloop_register_signal(SIGHUP, handler, user_data); 10678dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 10688dbcf02cSchristos } 10698dbcf02cSchristos 10708dbcf02cSchristos 10718dbcf02cSchristos void eloop_run(void) 10728dbcf02cSchristos { 1073316ee512Schristos #ifdef CONFIG_ELOOP_POLL 1074316ee512Schristos int num_poll_fds; 1075316ee512Schristos int timeout_ms = 0; 10763c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */ 10773c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 10788dbcf02cSchristos fd_set *rfds, *wfds, *efds; 10798dbcf02cSchristos struct timeval _tv; 10803c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 10813c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 10823c5783d3Schristos int timeout_ms = -1; 10833c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 10846da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 10856da92e7fSroy struct timespec ts; 10866da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 1087316ee512Schristos int res; 10883c5783d3Schristos struct os_reltime tv, now; 10898dbcf02cSchristos 10903c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 10918dbcf02cSchristos rfds = os_malloc(sizeof(*rfds)); 10928dbcf02cSchristos wfds = os_malloc(sizeof(*wfds)); 10938dbcf02cSchristos efds = os_malloc(sizeof(*efds)); 10948dbcf02cSchristos if (rfds == NULL || wfds == NULL || efds == NULL) 10958dbcf02cSchristos goto out; 10963c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 10978dbcf02cSchristos 10988dbcf02cSchristos while (!eloop.terminate && 10998dbcf02cSchristos (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 11008dbcf02cSchristos eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 11018dbcf02cSchristos struct eloop_timeout *timeout; 1102042b6b47Sroy 1103042b6b47Sroy if (eloop.pending_terminate) { 1104042b6b47Sroy /* 1105042b6b47Sroy * This may happen in some corner cases where a signal 1106042b6b47Sroy * is received during a blocking operation. We need to 1107042b6b47Sroy * process the pending signals and exit if requested to 1108042b6b47Sroy * avoid hitting the SIGALRM limit if the blocking 1109042b6b47Sroy * operation took more than two seconds. 1110042b6b47Sroy */ 1111042b6b47Sroy eloop_process_pending_signals(); 1112042b6b47Sroy if (eloop.terminate) 1113042b6b47Sroy break; 1114042b6b47Sroy } 1115042b6b47Sroy 11168dbcf02cSchristos timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 11178dbcf02cSchristos list); 11188dbcf02cSchristos if (timeout) { 11193c5783d3Schristos os_get_reltime(&now); 11203c5783d3Schristos if (os_reltime_before(&now, &timeout->time)) 11213c5783d3Schristos os_reltime_sub(&timeout->time, &now, &tv); 11228dbcf02cSchristos else 11238dbcf02cSchristos tv.sec = tv.usec = 0; 11243c5783d3Schristos #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) 1125316ee512Schristos timeout_ms = tv.sec * 1000 + tv.usec / 1000; 11263c5783d3Schristos #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */ 11273c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 11288dbcf02cSchristos _tv.tv_sec = tv.sec; 11298dbcf02cSchristos _tv.tv_usec = tv.usec; 11303c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 11316da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 11326da92e7fSroy ts.tv_sec = tv.sec; 11336da92e7fSroy ts.tv_nsec = tv.usec * 1000L; 11346da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 11358dbcf02cSchristos } 11368dbcf02cSchristos 1137316ee512Schristos #ifdef CONFIG_ELOOP_POLL 1138316ee512Schristos num_poll_fds = eloop_sock_table_set_fds( 1139316ee512Schristos &eloop.readers, &eloop.writers, &eloop.exceptions, 1140316ee512Schristos eloop.pollfds, eloop.pollfds_map, 1141316ee512Schristos eloop.max_pollfd_map); 1142316ee512Schristos res = poll(eloop.pollfds, num_poll_fds, 1143316ee512Schristos timeout ? timeout_ms : -1); 11443c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */ 11453c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 11468dbcf02cSchristos eloop_sock_table_set_fds(&eloop.readers, rfds); 11478dbcf02cSchristos eloop_sock_table_set_fds(&eloop.writers, wfds); 11488dbcf02cSchristos eloop_sock_table_set_fds(&eloop.exceptions, efds); 11498dbcf02cSchristos res = select(eloop.max_sock + 1, rfds, wfds, efds, 11508dbcf02cSchristos timeout ? &_tv : NULL); 11513c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 11523c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 11533c5783d3Schristos if (eloop.count == 0) { 11543c5783d3Schristos res = 0; 11553c5783d3Schristos } else { 11563c5783d3Schristos res = epoll_wait(eloop.epollfd, eloop.epoll_events, 11573c5783d3Schristos eloop.count, timeout_ms); 11583c5783d3Schristos } 11593c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 11606da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 11616da92e7fSroy if (eloop.count == 0) { 11626da92e7fSroy res = 0; 11636da92e7fSroy } else { 11646da92e7fSroy res = kevent(eloop.kqueuefd, NULL, 0, 11656da92e7fSroy eloop.kqueue_events, eloop.kqueue_nevents, 11666da92e7fSroy timeout ? &ts : NULL); 11676da92e7fSroy } 11686da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 11698dbcf02cSchristos if (res < 0 && errno != EINTR && errno != 0) { 11703c5783d3Schristos wpa_printf(MSG_ERROR, "eloop: %s: %s", 11713c5783d3Schristos #ifdef CONFIG_ELOOP_POLL 11723c5783d3Schristos "poll" 11733c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */ 11743c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 11753c5783d3Schristos "select" 11763c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 11773c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 11783c5783d3Schristos "epoll" 11793c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 11806da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 11816da92e7fSroy "kqueue" 11826da92e7fSroy #endif /* CONFIG_ELOOP_EKQUEUE */ 11836da92e7fSroy 11843c5783d3Schristos , strerror(errno)); 11858dbcf02cSchristos goto out; 11868dbcf02cSchristos } 1187042b6b47Sroy 1188042b6b47Sroy eloop.readers.changed = 0; 1189042b6b47Sroy eloop.writers.changed = 0; 1190042b6b47Sroy eloop.exceptions.changed = 0; 1191042b6b47Sroy 11928dbcf02cSchristos eloop_process_pending_signals(); 11938dbcf02cSchristos 1194042b6b47Sroy 11958dbcf02cSchristos /* check if some registered timeouts have occurred */ 1196e6e4448bSchristos timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 1197e6e4448bSchristos list); 11988dbcf02cSchristos if (timeout) { 11993c5783d3Schristos os_get_reltime(&now); 12003c5783d3Schristos if (!os_reltime_before(&now, &timeout->time)) { 12018dbcf02cSchristos void *eloop_data = timeout->eloop_data; 12028dbcf02cSchristos void *user_data = timeout->user_data; 12038dbcf02cSchristos eloop_timeout_handler handler = 12048dbcf02cSchristos timeout->handler; 12058dbcf02cSchristos eloop_remove_timeout(timeout); 12068dbcf02cSchristos handler(eloop_data, user_data); 12078dbcf02cSchristos } 12088dbcf02cSchristos 12098dbcf02cSchristos } 12108dbcf02cSchristos 12118dbcf02cSchristos if (res <= 0) 12128dbcf02cSchristos continue; 12138dbcf02cSchristos 1214042b6b47Sroy if (eloop.readers.changed || 1215042b6b47Sroy eloop.writers.changed || 1216042b6b47Sroy eloop.exceptions.changed) { 1217042b6b47Sroy /* 1218042b6b47Sroy * Sockets may have been closed and reopened with the 1219042b6b47Sroy * same FD in the signal or timeout handlers, so we 1220042b6b47Sroy * must skip the previous results and check again 1221042b6b47Sroy * whether any of the currently registered sockets have 1222042b6b47Sroy * events. 1223042b6b47Sroy */ 1224042b6b47Sroy continue; 1225042b6b47Sroy } 1226042b6b47Sroy 1227316ee512Schristos #ifdef CONFIG_ELOOP_POLL 1228316ee512Schristos eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, 1229316ee512Schristos &eloop.exceptions, eloop.pollfds_map, 1230316ee512Schristos eloop.max_pollfd_map); 12313c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */ 12323c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 12338dbcf02cSchristos eloop_sock_table_dispatch(&eloop.readers, rfds); 12348dbcf02cSchristos eloop_sock_table_dispatch(&eloop.writers, wfds); 12358dbcf02cSchristos eloop_sock_table_dispatch(&eloop.exceptions, efds); 12363c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 12373c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 12383c5783d3Schristos eloop_sock_table_dispatch(eloop.epoll_events, res); 12393c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 12406da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 12416da92e7fSroy eloop_sock_table_dispatch(eloop.kqueue_events, res); 12426da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 12438dbcf02cSchristos } 12448dbcf02cSchristos 12453c5783d3Schristos eloop.terminate = 0; 12468dbcf02cSchristos out: 12473c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 12488dbcf02cSchristos os_free(rfds); 12498dbcf02cSchristos os_free(wfds); 12508dbcf02cSchristos os_free(efds); 12513c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 1252316ee512Schristos return; 12538dbcf02cSchristos } 12548dbcf02cSchristos 12558dbcf02cSchristos 12568dbcf02cSchristos void eloop_terminate(void) 12578dbcf02cSchristos { 12588dbcf02cSchristos eloop.terminate = 1; 12598dbcf02cSchristos } 12608dbcf02cSchristos 12618dbcf02cSchristos 12628dbcf02cSchristos void eloop_destroy(void) 12638dbcf02cSchristos { 12648dbcf02cSchristos struct eloop_timeout *timeout, *prev; 12653c5783d3Schristos struct os_reltime now; 12668dbcf02cSchristos 12673c5783d3Schristos os_get_reltime(&now); 12688dbcf02cSchristos dl_list_for_each_safe(timeout, prev, &eloop.timeout, 12698dbcf02cSchristos struct eloop_timeout, list) { 12708dbcf02cSchristos int sec, usec; 12718dbcf02cSchristos sec = timeout->time.sec - now.sec; 12728dbcf02cSchristos usec = timeout->time.usec - now.usec; 12738dbcf02cSchristos if (timeout->time.usec < now.usec) { 12748dbcf02cSchristos sec--; 12758dbcf02cSchristos usec += 1000000; 12768dbcf02cSchristos } 12778dbcf02cSchristos wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 12788dbcf02cSchristos "eloop_data=%p user_data=%p handler=%p", 12798dbcf02cSchristos sec, usec, timeout->eloop_data, timeout->user_data, 12808dbcf02cSchristos timeout->handler); 12818dbcf02cSchristos wpa_trace_dump_funcname("eloop unregistered timeout handler", 12828dbcf02cSchristos timeout->handler); 12838dbcf02cSchristos wpa_trace_dump("eloop timeout", timeout); 12848dbcf02cSchristos eloop_remove_timeout(timeout); 12858dbcf02cSchristos } 12868dbcf02cSchristos eloop_sock_table_destroy(&eloop.readers); 12878dbcf02cSchristos eloop_sock_table_destroy(&eloop.writers); 12888dbcf02cSchristos eloop_sock_table_destroy(&eloop.exceptions); 12898dbcf02cSchristos os_free(eloop.signals); 1290316ee512Schristos 1291316ee512Schristos #ifdef CONFIG_ELOOP_POLL 1292316ee512Schristos os_free(eloop.pollfds); 1293316ee512Schristos os_free(eloop.pollfds_map); 1294316ee512Schristos #endif /* CONFIG_ELOOP_POLL */ 12956da92e7fSroy #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) 12966da92e7fSroy os_free(eloop.fd_table); 1297ecc36642Schristos #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ 12983c5783d3Schristos #ifdef CONFIG_ELOOP_EPOLL 12993c5783d3Schristos os_free(eloop.epoll_events); 13003c5783d3Schristos close(eloop.epollfd); 13013c5783d3Schristos #endif /* CONFIG_ELOOP_EPOLL */ 13026da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 13036da92e7fSroy os_free(eloop.kqueue_events); 13046da92e7fSroy close(eloop.kqueuefd); 13056da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 13068dbcf02cSchristos } 13078dbcf02cSchristos 13088dbcf02cSchristos 13098dbcf02cSchristos int eloop_terminated(void) 13108dbcf02cSchristos { 1311042b6b47Sroy return eloop.terminate || eloop.pending_terminate; 13128dbcf02cSchristos } 13138dbcf02cSchristos 13148dbcf02cSchristos 13158dbcf02cSchristos void eloop_wait_for_read_sock(int sock) 13168dbcf02cSchristos { 1317316ee512Schristos #ifdef CONFIG_ELOOP_POLL 1318316ee512Schristos struct pollfd pfd; 1319316ee512Schristos 1320316ee512Schristos if (sock < 0) 1321316ee512Schristos return; 1322316ee512Schristos 1323316ee512Schristos os_memset(&pfd, 0, sizeof(pfd)); 1324316ee512Schristos pfd.fd = sock; 1325316ee512Schristos pfd.events = POLLIN; 1326316ee512Schristos 1327316ee512Schristos poll(&pfd, 1, -1); 13283c5783d3Schristos #endif /* CONFIG_ELOOP_POLL */ 13293c5783d3Schristos #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) 13303c5783d3Schristos /* 13313c5783d3Schristos * We can use epoll() here. But epoll() requres 4 system calls. 13323c5783d3Schristos * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for 13333c5783d3Schristos * epoll fd. So select() is better for performance here. 13343c5783d3Schristos */ 13358dbcf02cSchristos fd_set rfds; 13368dbcf02cSchristos 13378dbcf02cSchristos if (sock < 0) 13388dbcf02cSchristos return; 13398dbcf02cSchristos 13408dbcf02cSchristos FD_ZERO(&rfds); 13418dbcf02cSchristos FD_SET(sock, &rfds); 13428dbcf02cSchristos select(sock + 1, &rfds, NULL, NULL, NULL); 13433c5783d3Schristos #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */ 13446da92e7fSroy #ifdef CONFIG_ELOOP_KQUEUE 13456da92e7fSroy int kfd; 13466da92e7fSroy struct kevent ke1, ke2; 13476da92e7fSroy 13486da92e7fSroy kfd = kqueue(); 13496da92e7fSroy if (kfd == -1) 13506da92e7fSroy return; 1351b06fa2e7Schristos EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); 13526da92e7fSroy kevent(kfd, &ke1, 1, &ke2, 1, NULL); 13536da92e7fSroy close(kfd); 13546da92e7fSroy #endif /* CONFIG_ELOOP_KQUEUE */ 13558dbcf02cSchristos } 13563c5783d3Schristos 13573c5783d3Schristos #ifdef CONFIG_ELOOP_SELECT 13583c5783d3Schristos #undef CONFIG_ELOOP_SELECT 13593c5783d3Schristos #endif /* CONFIG_ELOOP_SELECT */ 1360