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" 10*5b9c547cSRui 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 17*5b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_EPOLL) 18*5b9c547cSRui Paulo #error Do not define both of poll and epoll 19*5b9c547cSRui Paulo #endif 20*5b9c547cSRui Paulo 21*5b9c547cSRui Paulo #if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) 22*5b9c547cSRui Paulo #define CONFIG_ELOOP_SELECT 23*5b9c547cSRui Paulo #endif 24*5b9c547cSRui Paulo 25f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 26f05cddf9SRui Paulo #include <poll.h> 27f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 28f05cddf9SRui Paulo 29*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 30*5b9c547cSRui Paulo #include <sys/epoll.h> 31*5b9c547cSRui 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; 45*5b9c547cSRui 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; 64*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 65*5b9c547cSRui Paulo eloop_event_type type; 66*5b9c547cSRui Paulo #else /* CONFIG_ELOOP_EPOLL */ 6739beb93cSSam Leffler int changed; 68*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 6939beb93cSSam Leffler }; 7039beb93cSSam Leffler 7139beb93cSSam Leffler struct eloop_data { 7239beb93cSSam Leffler int max_sock; 7339beb93cSSam Leffler 74f05cddf9SRui Paulo int count; /* sum of all table counts */ 75f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 76f05cddf9SRui Paulo int max_pollfd_map; /* number of pollfds_map currently allocated */ 77f05cddf9SRui Paulo int max_poll_fds; /* number of pollfds currently allocated */ 78f05cddf9SRui Paulo struct pollfd *pollfds; 79f05cddf9SRui Paulo struct pollfd **pollfds_map; 80f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 81*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 82*5b9c547cSRui Paulo int epollfd; 83*5b9c547cSRui Paulo int epoll_max_event_num; 84*5b9c547cSRui Paulo int epoll_max_fd; 85*5b9c547cSRui Paulo struct eloop_sock *epoll_table; 86*5b9c547cSRui Paulo struct epoll_event *epoll_events; 87*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 8839beb93cSSam Leffler struct eloop_sock_table readers; 8939beb93cSSam Leffler struct eloop_sock_table writers; 9039beb93cSSam Leffler struct eloop_sock_table exceptions; 9139beb93cSSam Leffler 92e28a4053SRui Paulo struct dl_list timeout; 9339beb93cSSam Leffler 9439beb93cSSam Leffler int signal_count; 9539beb93cSSam Leffler struct eloop_signal *signals; 9639beb93cSSam Leffler int signaled; 9739beb93cSSam Leffler int pending_terminate; 9839beb93cSSam Leffler 9939beb93cSSam Leffler int terminate; 10039beb93cSSam Leffler }; 10139beb93cSSam Leffler 10239beb93cSSam Leffler static struct eloop_data eloop; 10339beb93cSSam Leffler 10439beb93cSSam Leffler 105e28a4053SRui Paulo #ifdef WPA_TRACE 106e28a4053SRui Paulo 107e28a4053SRui Paulo static void eloop_sigsegv_handler(int sig) 108e28a4053SRui Paulo { 109e28a4053SRui Paulo wpa_trace_show("eloop SIGSEGV"); 110e28a4053SRui Paulo abort(); 111e28a4053SRui Paulo } 112e28a4053SRui Paulo 113e28a4053SRui Paulo static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) 114e28a4053SRui Paulo { 115e28a4053SRui Paulo int i; 116e28a4053SRui Paulo if (table == NULL || table->table == NULL) 117e28a4053SRui Paulo return; 118e28a4053SRui Paulo for (i = 0; i < table->count; i++) { 119e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], eloop, 120e28a4053SRui Paulo table->table[i].eloop_data); 121e28a4053SRui Paulo wpa_trace_add_ref(&table->table[i], user, 122e28a4053SRui Paulo table->table[i].user_data); 123e28a4053SRui Paulo } 124e28a4053SRui Paulo } 125e28a4053SRui Paulo 126e28a4053SRui Paulo 127e28a4053SRui Paulo static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) 128e28a4053SRui Paulo { 129e28a4053SRui Paulo int i; 130e28a4053SRui Paulo if (table == NULL || table->table == NULL) 131e28a4053SRui Paulo return; 132e28a4053SRui Paulo for (i = 0; i < table->count; i++) { 133e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], eloop, 134e28a4053SRui Paulo table->table[i].eloop_data); 135e28a4053SRui Paulo wpa_trace_remove_ref(&table->table[i], user, 136e28a4053SRui Paulo table->table[i].user_data); 137e28a4053SRui Paulo } 138e28a4053SRui Paulo } 139e28a4053SRui Paulo 140e28a4053SRui Paulo #else /* WPA_TRACE */ 141e28a4053SRui Paulo 142e28a4053SRui Paulo #define eloop_trace_sock_add_ref(table) do { } while (0) 143e28a4053SRui Paulo #define eloop_trace_sock_remove_ref(table) do { } while (0) 144e28a4053SRui Paulo 145e28a4053SRui Paulo #endif /* WPA_TRACE */ 146e28a4053SRui Paulo 147e28a4053SRui Paulo 148e28a4053SRui Paulo int eloop_init(void) 14939beb93cSSam Leffler { 15039beb93cSSam Leffler os_memset(&eloop, 0, sizeof(eloop)); 151e28a4053SRui Paulo dl_list_init(&eloop.timeout); 152*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 153*5b9c547cSRui Paulo eloop.epollfd = epoll_create1(0); 154*5b9c547cSRui Paulo if (eloop.epollfd < 0) { 155*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n", 156*5b9c547cSRui Paulo __func__, strerror(errno)); 157*5b9c547cSRui Paulo return -1; 158*5b9c547cSRui Paulo } 159*5b9c547cSRui Paulo eloop.readers.type = EVENT_TYPE_READ; 160*5b9c547cSRui Paulo eloop.writers.type = EVENT_TYPE_WRITE; 161*5b9c547cSRui Paulo eloop.exceptions.type = EVENT_TYPE_EXCEPTION; 162*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 163e28a4053SRui Paulo #ifdef WPA_TRACE 164e28a4053SRui Paulo signal(SIGSEGV, eloop_sigsegv_handler); 165e28a4053SRui Paulo #endif /* WPA_TRACE */ 16639beb93cSSam Leffler return 0; 16739beb93cSSam Leffler } 16839beb93cSSam Leffler 16939beb93cSSam Leffler 17039beb93cSSam Leffler static int eloop_sock_table_add_sock(struct eloop_sock_table *table, 17139beb93cSSam Leffler int sock, eloop_sock_handler handler, 17239beb93cSSam Leffler void *eloop_data, void *user_data) 17339beb93cSSam Leffler { 174*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 175*5b9c547cSRui Paulo struct eloop_sock *temp_table; 176*5b9c547cSRui Paulo struct epoll_event ev, *temp_events; 177*5b9c547cSRui Paulo int next; 178*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 17939beb93cSSam Leffler struct eloop_sock *tmp; 180f05cddf9SRui Paulo int new_max_sock; 181f05cddf9SRui Paulo 182f05cddf9SRui Paulo if (sock > eloop.max_sock) 183f05cddf9SRui Paulo new_max_sock = sock; 184f05cddf9SRui Paulo else 185f05cddf9SRui Paulo new_max_sock = eloop.max_sock; 18639beb93cSSam Leffler 18739beb93cSSam Leffler if (table == NULL) 18839beb93cSSam Leffler return -1; 18939beb93cSSam Leffler 190f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 191f05cddf9SRui Paulo if (new_max_sock >= eloop.max_pollfd_map) { 192f05cddf9SRui Paulo struct pollfd **nmap; 193f05cddf9SRui Paulo nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50, 194f05cddf9SRui Paulo sizeof(struct pollfd *)); 195f05cddf9SRui Paulo if (nmap == NULL) 196f05cddf9SRui Paulo return -1; 197f05cddf9SRui Paulo 198f05cddf9SRui Paulo eloop.max_pollfd_map = new_max_sock + 50; 199f05cddf9SRui Paulo eloop.pollfds_map = nmap; 200f05cddf9SRui Paulo } 201f05cddf9SRui Paulo 202f05cddf9SRui Paulo if (eloop.count + 1 > eloop.max_poll_fds) { 203f05cddf9SRui Paulo struct pollfd *n; 204f05cddf9SRui Paulo int nmax = eloop.count + 1 + 50; 205f05cddf9SRui Paulo n = os_realloc_array(eloop.pollfds, nmax, 206f05cddf9SRui Paulo sizeof(struct pollfd)); 207f05cddf9SRui Paulo if (n == NULL) 208f05cddf9SRui Paulo return -1; 209f05cddf9SRui Paulo 210f05cddf9SRui Paulo eloop.max_poll_fds = nmax; 211f05cddf9SRui Paulo eloop.pollfds = n; 212f05cddf9SRui Paulo } 213f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 214*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 215*5b9c547cSRui Paulo if (new_max_sock >= eloop.epoll_max_fd) { 216*5b9c547cSRui Paulo next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2; 217*5b9c547cSRui Paulo temp_table = os_realloc_array(eloop.epoll_table, next, 218*5b9c547cSRui Paulo sizeof(struct eloop_sock)); 219*5b9c547cSRui Paulo if (temp_table == NULL) 220*5b9c547cSRui Paulo return -1; 221*5b9c547cSRui Paulo 222*5b9c547cSRui Paulo eloop.epoll_max_fd = next; 223*5b9c547cSRui Paulo eloop.epoll_table = temp_table; 224*5b9c547cSRui Paulo } 225*5b9c547cSRui Paulo 226*5b9c547cSRui Paulo if (eloop.count + 1 > eloop.epoll_max_event_num) { 227*5b9c547cSRui Paulo next = eloop.epoll_max_event_num == 0 ? 8 : 228*5b9c547cSRui Paulo eloop.epoll_max_event_num * 2; 229*5b9c547cSRui Paulo temp_events = os_realloc_array(eloop.epoll_events, next, 230*5b9c547cSRui Paulo sizeof(struct epoll_event)); 231*5b9c547cSRui Paulo if (temp_events == NULL) { 232*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. " 233*5b9c547cSRui Paulo "%s\n", __func__, strerror(errno)); 234*5b9c547cSRui Paulo return -1; 235*5b9c547cSRui Paulo } 236*5b9c547cSRui Paulo 237*5b9c547cSRui Paulo eloop.epoll_max_event_num = next; 238*5b9c547cSRui Paulo eloop.epoll_events = temp_events; 239*5b9c547cSRui Paulo } 240*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 241f05cddf9SRui Paulo 242e28a4053SRui Paulo eloop_trace_sock_remove_ref(table); 243f05cddf9SRui Paulo tmp = os_realloc_array(table->table, table->count + 1, 244f05cddf9SRui Paulo sizeof(struct eloop_sock)); 245*5b9c547cSRui Paulo if (tmp == NULL) { 246*5b9c547cSRui Paulo eloop_trace_sock_add_ref(table); 24739beb93cSSam Leffler return -1; 248*5b9c547cSRui Paulo } 24939beb93cSSam Leffler 25039beb93cSSam Leffler tmp[table->count].sock = sock; 25139beb93cSSam Leffler tmp[table->count].eloop_data = eloop_data; 25239beb93cSSam Leffler tmp[table->count].user_data = user_data; 25339beb93cSSam Leffler tmp[table->count].handler = handler; 254e28a4053SRui Paulo wpa_trace_record(&tmp[table->count]); 25539beb93cSSam Leffler table->count++; 25639beb93cSSam Leffler table->table = tmp; 257f05cddf9SRui Paulo eloop.max_sock = new_max_sock; 258f05cddf9SRui Paulo eloop.count++; 259*5b9c547cSRui Paulo #ifndef CONFIG_ELOOP_EPOLL 26039beb93cSSam Leffler table->changed = 1; 261*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 262e28a4053SRui Paulo eloop_trace_sock_add_ref(table); 26339beb93cSSam Leffler 264*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 265*5b9c547cSRui Paulo os_memset(&ev, 0, sizeof(ev)); 266*5b9c547cSRui Paulo switch (table->type) { 267*5b9c547cSRui Paulo case EVENT_TYPE_READ: 268*5b9c547cSRui Paulo ev.events = EPOLLIN; 269*5b9c547cSRui Paulo break; 270*5b9c547cSRui Paulo case EVENT_TYPE_WRITE: 271*5b9c547cSRui Paulo ev.events = EPOLLOUT; 272*5b9c547cSRui Paulo break; 273*5b9c547cSRui Paulo /* 274*5b9c547cSRui Paulo * Exceptions are always checked when using epoll, but I suppose it's 275*5b9c547cSRui Paulo * possible that someone registered a socket *only* for exception 276*5b9c547cSRui Paulo * handling. 277*5b9c547cSRui Paulo */ 278*5b9c547cSRui Paulo case EVENT_TYPE_EXCEPTION: 279*5b9c547cSRui Paulo ev.events = EPOLLERR | EPOLLHUP; 280*5b9c547cSRui Paulo break; 281*5b9c547cSRui Paulo } 282*5b9c547cSRui Paulo ev.data.fd = sock; 283*5b9c547cSRui Paulo if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { 284*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d " 285*5b9c547cSRui Paulo "failed. %s\n", __func__, sock, strerror(errno)); 286*5b9c547cSRui Paulo return -1; 287*5b9c547cSRui Paulo } 288*5b9c547cSRui Paulo os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1], 289*5b9c547cSRui Paulo sizeof(struct eloop_sock)); 290*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 29139beb93cSSam Leffler return 0; 29239beb93cSSam Leffler } 29339beb93cSSam Leffler 29439beb93cSSam Leffler 29539beb93cSSam Leffler static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, 29639beb93cSSam Leffler int sock) 29739beb93cSSam Leffler { 29839beb93cSSam Leffler int i; 29939beb93cSSam Leffler 30039beb93cSSam Leffler if (table == NULL || table->table == NULL || table->count == 0) 30139beb93cSSam Leffler return; 30239beb93cSSam Leffler 30339beb93cSSam Leffler for (i = 0; i < table->count; i++) { 30439beb93cSSam Leffler if (table->table[i].sock == sock) 30539beb93cSSam Leffler break; 30639beb93cSSam Leffler } 30739beb93cSSam Leffler if (i == table->count) 30839beb93cSSam Leffler return; 309e28a4053SRui Paulo eloop_trace_sock_remove_ref(table); 31039beb93cSSam Leffler if (i != table->count - 1) { 31139beb93cSSam Leffler os_memmove(&table->table[i], &table->table[i + 1], 31239beb93cSSam Leffler (table->count - i - 1) * 31339beb93cSSam Leffler sizeof(struct eloop_sock)); 31439beb93cSSam Leffler } 31539beb93cSSam Leffler table->count--; 316f05cddf9SRui Paulo eloop.count--; 317*5b9c547cSRui Paulo #ifndef CONFIG_ELOOP_EPOLL 31839beb93cSSam Leffler table->changed = 1; 319*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 320e28a4053SRui Paulo eloop_trace_sock_add_ref(table); 321*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 322*5b9c547cSRui Paulo if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) { 323*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d " 324*5b9c547cSRui Paulo "failed. %s\n", __func__, sock, strerror(errno)); 325*5b9c547cSRui Paulo return; 326*5b9c547cSRui Paulo } 327*5b9c547cSRui Paulo os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock)); 328*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 32939beb93cSSam Leffler } 33039beb93cSSam Leffler 33139beb93cSSam Leffler 332f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 333f05cddf9SRui Paulo 334f05cddf9SRui Paulo static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx) 335f05cddf9SRui Paulo { 336f05cddf9SRui Paulo if (fd < mx && fd >= 0) 337f05cddf9SRui Paulo return pollfds_map[fd]; 338f05cddf9SRui Paulo return NULL; 339f05cddf9SRui Paulo } 340f05cddf9SRui Paulo 341f05cddf9SRui Paulo 342f05cddf9SRui Paulo static int eloop_sock_table_set_fds(struct eloop_sock_table *readers, 343f05cddf9SRui Paulo struct eloop_sock_table *writers, 344f05cddf9SRui Paulo struct eloop_sock_table *exceptions, 345f05cddf9SRui Paulo struct pollfd *pollfds, 346f05cddf9SRui Paulo struct pollfd **pollfds_map, 347f05cddf9SRui Paulo int max_pollfd_map) 348f05cddf9SRui Paulo { 349f05cddf9SRui Paulo int i; 350f05cddf9SRui Paulo int nxt = 0; 351f05cddf9SRui Paulo int fd; 352f05cddf9SRui Paulo struct pollfd *pfd; 353f05cddf9SRui Paulo 354f05cddf9SRui Paulo /* Clear pollfd lookup map. It will be re-populated below. */ 355f05cddf9SRui Paulo os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map); 356f05cddf9SRui Paulo 357f05cddf9SRui Paulo if (readers && readers->table) { 358f05cddf9SRui Paulo for (i = 0; i < readers->count; i++) { 359f05cddf9SRui Paulo fd = readers->table[i].sock; 360f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map); 361f05cddf9SRui Paulo pollfds[nxt].fd = fd; 362f05cddf9SRui Paulo pollfds[nxt].events = POLLIN; 363f05cddf9SRui Paulo pollfds[nxt].revents = 0; 364f05cddf9SRui Paulo pollfds_map[fd] = &(pollfds[nxt]); 365f05cddf9SRui Paulo nxt++; 366f05cddf9SRui Paulo } 367f05cddf9SRui Paulo } 368f05cddf9SRui Paulo 369f05cddf9SRui Paulo if (writers && writers->table) { 370f05cddf9SRui Paulo for (i = 0; i < writers->count; i++) { 371f05cddf9SRui Paulo /* 372f05cddf9SRui Paulo * See if we already added this descriptor, update it 373f05cddf9SRui Paulo * if so. 374f05cddf9SRui Paulo */ 375f05cddf9SRui Paulo fd = writers->table[i].sock; 376f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map); 377f05cddf9SRui Paulo pfd = pollfds_map[fd]; 378f05cddf9SRui Paulo if (!pfd) { 379f05cddf9SRui Paulo pfd = &(pollfds[nxt]); 380f05cddf9SRui Paulo pfd->events = 0; 381f05cddf9SRui Paulo pfd->fd = fd; 382f05cddf9SRui Paulo pollfds[i].revents = 0; 383f05cddf9SRui Paulo pollfds_map[fd] = pfd; 384f05cddf9SRui Paulo nxt++; 385f05cddf9SRui Paulo } 386f05cddf9SRui Paulo pfd->events |= POLLOUT; 387f05cddf9SRui Paulo } 388f05cddf9SRui Paulo } 389f05cddf9SRui Paulo 390f05cddf9SRui Paulo /* 391f05cddf9SRui Paulo * Exceptions are always checked when using poll, but I suppose it's 392f05cddf9SRui Paulo * possible that someone registered a socket *only* for exception 393f05cddf9SRui Paulo * handling. Set the POLLIN bit in this case. 394f05cddf9SRui Paulo */ 395f05cddf9SRui Paulo if (exceptions && exceptions->table) { 396f05cddf9SRui Paulo for (i = 0; i < exceptions->count; i++) { 397f05cddf9SRui Paulo /* 398f05cddf9SRui Paulo * See if we already added this descriptor, just use it 399f05cddf9SRui Paulo * if so. 400f05cddf9SRui Paulo */ 401f05cddf9SRui Paulo fd = exceptions->table[i].sock; 402f05cddf9SRui Paulo assert(fd >= 0 && fd < max_pollfd_map); 403f05cddf9SRui Paulo pfd = pollfds_map[fd]; 404f05cddf9SRui Paulo if (!pfd) { 405f05cddf9SRui Paulo pfd = &(pollfds[nxt]); 406f05cddf9SRui Paulo pfd->events = POLLIN; 407f05cddf9SRui Paulo pfd->fd = fd; 408f05cddf9SRui Paulo pollfds[i].revents = 0; 409f05cddf9SRui Paulo pollfds_map[fd] = pfd; 410f05cddf9SRui Paulo nxt++; 411f05cddf9SRui Paulo } 412f05cddf9SRui Paulo } 413f05cddf9SRui Paulo } 414f05cddf9SRui Paulo 415f05cddf9SRui Paulo return nxt; 416f05cddf9SRui Paulo } 417f05cddf9SRui Paulo 418f05cddf9SRui Paulo 419f05cddf9SRui Paulo static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table, 420f05cddf9SRui Paulo struct pollfd **pollfds_map, 421f05cddf9SRui Paulo int max_pollfd_map, 422f05cddf9SRui Paulo short int revents) 423f05cddf9SRui Paulo { 424f05cddf9SRui Paulo int i; 425f05cddf9SRui Paulo struct pollfd *pfd; 426f05cddf9SRui Paulo 427f05cddf9SRui Paulo if (!table || !table->table) 428f05cddf9SRui Paulo return 0; 429f05cddf9SRui Paulo 430f05cddf9SRui Paulo table->changed = 0; 431f05cddf9SRui Paulo for (i = 0; i < table->count; i++) { 432f05cddf9SRui Paulo pfd = find_pollfd(pollfds_map, table->table[i].sock, 433f05cddf9SRui Paulo max_pollfd_map); 434f05cddf9SRui Paulo if (!pfd) 435f05cddf9SRui Paulo continue; 436f05cddf9SRui Paulo 437f05cddf9SRui Paulo if (!(pfd->revents & revents)) 438f05cddf9SRui Paulo continue; 439f05cddf9SRui Paulo 440f05cddf9SRui Paulo table->table[i].handler(table->table[i].sock, 441f05cddf9SRui Paulo table->table[i].eloop_data, 442f05cddf9SRui Paulo table->table[i].user_data); 443f05cddf9SRui Paulo if (table->changed) 444f05cddf9SRui Paulo return 1; 445f05cddf9SRui Paulo } 446f05cddf9SRui Paulo 447f05cddf9SRui Paulo return 0; 448f05cddf9SRui Paulo } 449f05cddf9SRui Paulo 450f05cddf9SRui Paulo 451f05cddf9SRui Paulo static void eloop_sock_table_dispatch(struct eloop_sock_table *readers, 452f05cddf9SRui Paulo struct eloop_sock_table *writers, 453f05cddf9SRui Paulo struct eloop_sock_table *exceptions, 454f05cddf9SRui Paulo struct pollfd **pollfds_map, 455f05cddf9SRui Paulo int max_pollfd_map) 456f05cddf9SRui Paulo { 457f05cddf9SRui Paulo if (eloop_sock_table_dispatch_table(readers, pollfds_map, 458f05cddf9SRui Paulo max_pollfd_map, POLLIN | POLLERR | 459f05cddf9SRui Paulo POLLHUP)) 460f05cddf9SRui Paulo return; /* pollfds may be invalid at this point */ 461f05cddf9SRui Paulo 462f05cddf9SRui Paulo if (eloop_sock_table_dispatch_table(writers, pollfds_map, 463f05cddf9SRui Paulo max_pollfd_map, POLLOUT)) 464f05cddf9SRui Paulo return; /* pollfds may be invalid at this point */ 465f05cddf9SRui Paulo 466f05cddf9SRui Paulo eloop_sock_table_dispatch_table(exceptions, pollfds_map, 467f05cddf9SRui Paulo max_pollfd_map, POLLERR | POLLHUP); 468f05cddf9SRui Paulo } 469f05cddf9SRui Paulo 470*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 471*5b9c547cSRui Paulo 472*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 473f05cddf9SRui Paulo 47439beb93cSSam Leffler static void eloop_sock_table_set_fds(struct eloop_sock_table *table, 47539beb93cSSam Leffler fd_set *fds) 47639beb93cSSam Leffler { 47739beb93cSSam Leffler int i; 47839beb93cSSam Leffler 47939beb93cSSam Leffler FD_ZERO(fds); 48039beb93cSSam Leffler 48139beb93cSSam Leffler if (table->table == NULL) 48239beb93cSSam Leffler return; 48339beb93cSSam Leffler 484*5b9c547cSRui Paulo for (i = 0; i < table->count; i++) { 485*5b9c547cSRui Paulo assert(table->table[i].sock >= 0); 48639beb93cSSam Leffler FD_SET(table->table[i].sock, fds); 48739beb93cSSam Leffler } 488*5b9c547cSRui Paulo } 48939beb93cSSam Leffler 49039beb93cSSam Leffler 49139beb93cSSam Leffler static void eloop_sock_table_dispatch(struct eloop_sock_table *table, 49239beb93cSSam Leffler fd_set *fds) 49339beb93cSSam Leffler { 49439beb93cSSam Leffler int i; 49539beb93cSSam Leffler 49639beb93cSSam Leffler if (table == NULL || table->table == NULL) 49739beb93cSSam Leffler return; 49839beb93cSSam Leffler 49939beb93cSSam Leffler table->changed = 0; 50039beb93cSSam Leffler for (i = 0; i < table->count; i++) { 50139beb93cSSam Leffler if (FD_ISSET(table->table[i].sock, fds)) { 50239beb93cSSam Leffler table->table[i].handler(table->table[i].sock, 50339beb93cSSam Leffler table->table[i].eloop_data, 50439beb93cSSam Leffler table->table[i].user_data); 50539beb93cSSam Leffler if (table->changed) 50639beb93cSSam Leffler break; 50739beb93cSSam Leffler } 50839beb93cSSam Leffler } 50939beb93cSSam Leffler } 51039beb93cSSam Leffler 511*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 512*5b9c547cSRui Paulo 513*5b9c547cSRui Paulo 514*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 515*5b9c547cSRui Paulo static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) 516*5b9c547cSRui Paulo { 517*5b9c547cSRui Paulo struct eloop_sock *table; 518*5b9c547cSRui Paulo int i; 519*5b9c547cSRui Paulo 520*5b9c547cSRui Paulo for (i = 0; i < nfds; i++) { 521*5b9c547cSRui Paulo table = &eloop.epoll_table[events[i].data.fd]; 522*5b9c547cSRui Paulo if (table->handler == NULL) 523*5b9c547cSRui Paulo continue; 524*5b9c547cSRui Paulo table->handler(table->sock, table->eloop_data, 525*5b9c547cSRui Paulo table->user_data); 526*5b9c547cSRui Paulo } 527*5b9c547cSRui Paulo } 528*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 529f05cddf9SRui Paulo 53039beb93cSSam Leffler 53139beb93cSSam Leffler static void eloop_sock_table_destroy(struct eloop_sock_table *table) 53239beb93cSSam Leffler { 53339beb93cSSam Leffler if (table) { 53439beb93cSSam Leffler int i; 53539beb93cSSam Leffler for (i = 0; i < table->count && table->table; i++) { 536e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining socket: " 537e28a4053SRui Paulo "sock=%d eloop_data=%p user_data=%p " 538e28a4053SRui Paulo "handler=%p", 53939beb93cSSam Leffler table->table[i].sock, 54039beb93cSSam Leffler table->table[i].eloop_data, 54139beb93cSSam Leffler table->table[i].user_data, 54239beb93cSSam Leffler table->table[i].handler); 543e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered socket " 544e28a4053SRui Paulo "handler", 545e28a4053SRui Paulo table->table[i].handler); 546e28a4053SRui Paulo wpa_trace_dump("eloop sock", &table->table[i]); 54739beb93cSSam Leffler } 54839beb93cSSam Leffler os_free(table->table); 54939beb93cSSam Leffler } 55039beb93cSSam Leffler } 55139beb93cSSam Leffler 55239beb93cSSam Leffler 55339beb93cSSam Leffler int eloop_register_read_sock(int sock, eloop_sock_handler handler, 55439beb93cSSam Leffler void *eloop_data, void *user_data) 55539beb93cSSam Leffler { 55639beb93cSSam Leffler return eloop_register_sock(sock, EVENT_TYPE_READ, handler, 55739beb93cSSam Leffler eloop_data, user_data); 55839beb93cSSam Leffler } 55939beb93cSSam Leffler 56039beb93cSSam Leffler 56139beb93cSSam Leffler void eloop_unregister_read_sock(int sock) 56239beb93cSSam Leffler { 56339beb93cSSam Leffler eloop_unregister_sock(sock, EVENT_TYPE_READ); 56439beb93cSSam Leffler } 56539beb93cSSam Leffler 56639beb93cSSam Leffler 56739beb93cSSam Leffler static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) 56839beb93cSSam Leffler { 56939beb93cSSam Leffler switch (type) { 57039beb93cSSam Leffler case EVENT_TYPE_READ: 57139beb93cSSam Leffler return &eloop.readers; 57239beb93cSSam Leffler case EVENT_TYPE_WRITE: 57339beb93cSSam Leffler return &eloop.writers; 57439beb93cSSam Leffler case EVENT_TYPE_EXCEPTION: 57539beb93cSSam Leffler return &eloop.exceptions; 57639beb93cSSam Leffler } 57739beb93cSSam Leffler 57839beb93cSSam Leffler return NULL; 57939beb93cSSam Leffler } 58039beb93cSSam Leffler 58139beb93cSSam Leffler 58239beb93cSSam Leffler int eloop_register_sock(int sock, eloop_event_type type, 58339beb93cSSam Leffler eloop_sock_handler handler, 58439beb93cSSam Leffler void *eloop_data, void *user_data) 58539beb93cSSam Leffler { 58639beb93cSSam Leffler struct eloop_sock_table *table; 58739beb93cSSam Leffler 588*5b9c547cSRui Paulo assert(sock >= 0); 58939beb93cSSam Leffler table = eloop_get_sock_table(type); 59039beb93cSSam Leffler return eloop_sock_table_add_sock(table, sock, handler, 59139beb93cSSam Leffler eloop_data, user_data); 59239beb93cSSam Leffler } 59339beb93cSSam Leffler 59439beb93cSSam Leffler 59539beb93cSSam Leffler void eloop_unregister_sock(int sock, eloop_event_type type) 59639beb93cSSam Leffler { 59739beb93cSSam Leffler struct eloop_sock_table *table; 59839beb93cSSam Leffler 59939beb93cSSam Leffler table = eloop_get_sock_table(type); 60039beb93cSSam Leffler eloop_sock_table_remove_sock(table, sock); 60139beb93cSSam Leffler } 60239beb93cSSam Leffler 60339beb93cSSam Leffler 60439beb93cSSam Leffler int eloop_register_timeout(unsigned int secs, unsigned int usecs, 60539beb93cSSam Leffler eloop_timeout_handler handler, 60639beb93cSSam Leffler void *eloop_data, void *user_data) 60739beb93cSSam Leffler { 608e28a4053SRui Paulo struct eloop_timeout *timeout, *tmp; 609f05cddf9SRui Paulo os_time_t now_sec; 61039beb93cSSam Leffler 611e28a4053SRui Paulo timeout = os_zalloc(sizeof(*timeout)); 61239beb93cSSam Leffler if (timeout == NULL) 61339beb93cSSam Leffler return -1; 614*5b9c547cSRui Paulo if (os_get_reltime(&timeout->time) < 0) { 61539beb93cSSam Leffler os_free(timeout); 61639beb93cSSam Leffler return -1; 61739beb93cSSam Leffler } 618f05cddf9SRui Paulo now_sec = timeout->time.sec; 61939beb93cSSam Leffler timeout->time.sec += secs; 620f05cddf9SRui Paulo if (timeout->time.sec < now_sec) { 621f05cddf9SRui Paulo /* 622f05cddf9SRui Paulo * Integer overflow - assume long enough timeout to be assumed 623f05cddf9SRui Paulo * to be infinite, i.e., the timeout would never happen. 624f05cddf9SRui Paulo */ 625f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " 626f05cddf9SRui Paulo "ever happen - ignore it", secs); 627f05cddf9SRui Paulo os_free(timeout); 628f05cddf9SRui Paulo return 0; 629f05cddf9SRui Paulo } 63039beb93cSSam Leffler timeout->time.usec += usecs; 63139beb93cSSam Leffler while (timeout->time.usec >= 1000000) { 63239beb93cSSam Leffler timeout->time.sec++; 63339beb93cSSam Leffler timeout->time.usec -= 1000000; 63439beb93cSSam Leffler } 63539beb93cSSam Leffler timeout->eloop_data = eloop_data; 63639beb93cSSam Leffler timeout->user_data = user_data; 63739beb93cSSam Leffler timeout->handler = handler; 638e28a4053SRui Paulo wpa_trace_add_ref(timeout, eloop, eloop_data); 639e28a4053SRui Paulo wpa_trace_add_ref(timeout, user, user_data); 640e28a4053SRui Paulo wpa_trace_record(timeout); 64139beb93cSSam Leffler 642e28a4053SRui Paulo /* Maintain timeouts in order of increasing time */ 643e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 644*5b9c547cSRui Paulo if (os_reltime_before(&timeout->time, &tmp->time)) { 645e28a4053SRui Paulo dl_list_add(tmp->list.prev, &timeout->list); 646e28a4053SRui Paulo return 0; 647e28a4053SRui Paulo } 648e28a4053SRui Paulo } 649e28a4053SRui Paulo dl_list_add_tail(&eloop.timeout, &timeout->list); 650e28a4053SRui Paulo 65139beb93cSSam Leffler return 0; 65239beb93cSSam Leffler } 65339beb93cSSam Leffler 65439beb93cSSam Leffler 655e28a4053SRui Paulo static void eloop_remove_timeout(struct eloop_timeout *timeout) 656e28a4053SRui Paulo { 657e28a4053SRui Paulo dl_list_del(&timeout->list); 658e28a4053SRui Paulo wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); 659e28a4053SRui Paulo wpa_trace_remove_ref(timeout, user, timeout->user_data); 660e28a4053SRui Paulo os_free(timeout); 66139beb93cSSam Leffler } 66239beb93cSSam Leffler 66339beb93cSSam Leffler 66439beb93cSSam Leffler int eloop_cancel_timeout(eloop_timeout_handler handler, 66539beb93cSSam Leffler void *eloop_data, void *user_data) 66639beb93cSSam Leffler { 667e28a4053SRui Paulo struct eloop_timeout *timeout, *prev; 66839beb93cSSam Leffler int removed = 0; 66939beb93cSSam Leffler 670e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 671e28a4053SRui Paulo struct eloop_timeout, list) { 67239beb93cSSam Leffler if (timeout->handler == handler && 67339beb93cSSam Leffler (timeout->eloop_data == eloop_data || 67439beb93cSSam Leffler eloop_data == ELOOP_ALL_CTX) && 67539beb93cSSam Leffler (timeout->user_data == user_data || 67639beb93cSSam Leffler user_data == ELOOP_ALL_CTX)) { 677e28a4053SRui Paulo eloop_remove_timeout(timeout); 67839beb93cSSam Leffler removed++; 679e28a4053SRui Paulo } 68039beb93cSSam Leffler } 68139beb93cSSam Leffler 68239beb93cSSam Leffler return removed; 68339beb93cSSam Leffler } 68439beb93cSSam Leffler 68539beb93cSSam Leffler 686*5b9c547cSRui Paulo int eloop_cancel_timeout_one(eloop_timeout_handler handler, 687*5b9c547cSRui Paulo void *eloop_data, void *user_data, 688*5b9c547cSRui Paulo struct os_reltime *remaining) 689*5b9c547cSRui Paulo { 690*5b9c547cSRui Paulo struct eloop_timeout *timeout, *prev; 691*5b9c547cSRui Paulo int removed = 0; 692*5b9c547cSRui Paulo struct os_reltime now; 693*5b9c547cSRui Paulo 694*5b9c547cSRui Paulo os_get_reltime(&now); 695*5b9c547cSRui Paulo remaining->sec = remaining->usec = 0; 696*5b9c547cSRui Paulo 697*5b9c547cSRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 698*5b9c547cSRui Paulo struct eloop_timeout, list) { 699*5b9c547cSRui Paulo if (timeout->handler == handler && 700*5b9c547cSRui Paulo (timeout->eloop_data == eloop_data) && 701*5b9c547cSRui Paulo (timeout->user_data == user_data)) { 702*5b9c547cSRui Paulo removed = 1; 703*5b9c547cSRui Paulo if (os_reltime_before(&now, &timeout->time)) 704*5b9c547cSRui Paulo os_reltime_sub(&timeout->time, &now, remaining); 705*5b9c547cSRui Paulo eloop_remove_timeout(timeout); 706*5b9c547cSRui Paulo break; 707*5b9c547cSRui Paulo } 708*5b9c547cSRui Paulo } 709*5b9c547cSRui Paulo return removed; 710*5b9c547cSRui Paulo } 711*5b9c547cSRui Paulo 712*5b9c547cSRui Paulo 71339beb93cSSam Leffler int eloop_is_timeout_registered(eloop_timeout_handler handler, 71439beb93cSSam Leffler void *eloop_data, void *user_data) 71539beb93cSSam Leffler { 71639beb93cSSam Leffler struct eloop_timeout *tmp; 71739beb93cSSam Leffler 718e28a4053SRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 71939beb93cSSam Leffler if (tmp->handler == handler && 72039beb93cSSam Leffler tmp->eloop_data == eloop_data && 72139beb93cSSam Leffler tmp->user_data == user_data) 72239beb93cSSam Leffler return 1; 72339beb93cSSam Leffler } 72439beb93cSSam Leffler 72539beb93cSSam Leffler return 0; 72639beb93cSSam Leffler } 72739beb93cSSam Leffler 72839beb93cSSam Leffler 729*5b9c547cSRui Paulo int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs, 730*5b9c547cSRui Paulo eloop_timeout_handler handler, void *eloop_data, 731*5b9c547cSRui Paulo void *user_data) 732*5b9c547cSRui Paulo { 733*5b9c547cSRui Paulo struct os_reltime now, requested, remaining; 734*5b9c547cSRui Paulo struct eloop_timeout *tmp; 735*5b9c547cSRui Paulo 736*5b9c547cSRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 737*5b9c547cSRui Paulo if (tmp->handler == handler && 738*5b9c547cSRui Paulo tmp->eloop_data == eloop_data && 739*5b9c547cSRui Paulo tmp->user_data == user_data) { 740*5b9c547cSRui Paulo requested.sec = req_secs; 741*5b9c547cSRui Paulo requested.usec = req_usecs; 742*5b9c547cSRui Paulo os_get_reltime(&now); 743*5b9c547cSRui Paulo os_reltime_sub(&tmp->time, &now, &remaining); 744*5b9c547cSRui Paulo if (os_reltime_before(&requested, &remaining)) { 745*5b9c547cSRui Paulo eloop_cancel_timeout(handler, eloop_data, 746*5b9c547cSRui Paulo user_data); 747*5b9c547cSRui Paulo eloop_register_timeout(requested.sec, 748*5b9c547cSRui Paulo requested.usec, 749*5b9c547cSRui Paulo handler, eloop_data, 750*5b9c547cSRui Paulo user_data); 751*5b9c547cSRui Paulo return 1; 752*5b9c547cSRui Paulo } 753*5b9c547cSRui Paulo return 0; 754*5b9c547cSRui Paulo } 755*5b9c547cSRui Paulo } 756*5b9c547cSRui Paulo 757*5b9c547cSRui Paulo return -1; 758*5b9c547cSRui Paulo } 759*5b9c547cSRui Paulo 760*5b9c547cSRui Paulo 761*5b9c547cSRui Paulo int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, 762*5b9c547cSRui Paulo eloop_timeout_handler handler, void *eloop_data, 763*5b9c547cSRui Paulo void *user_data) 764*5b9c547cSRui Paulo { 765*5b9c547cSRui Paulo struct os_reltime now, requested, remaining; 766*5b9c547cSRui Paulo struct eloop_timeout *tmp; 767*5b9c547cSRui Paulo 768*5b9c547cSRui Paulo dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { 769*5b9c547cSRui Paulo if (tmp->handler == handler && 770*5b9c547cSRui Paulo tmp->eloop_data == eloop_data && 771*5b9c547cSRui Paulo tmp->user_data == user_data) { 772*5b9c547cSRui Paulo requested.sec = req_secs; 773*5b9c547cSRui Paulo requested.usec = req_usecs; 774*5b9c547cSRui Paulo os_get_reltime(&now); 775*5b9c547cSRui Paulo os_reltime_sub(&tmp->time, &now, &remaining); 776*5b9c547cSRui Paulo if (os_reltime_before(&remaining, &requested)) { 777*5b9c547cSRui Paulo eloop_cancel_timeout(handler, eloop_data, 778*5b9c547cSRui Paulo user_data); 779*5b9c547cSRui Paulo eloop_register_timeout(requested.sec, 780*5b9c547cSRui Paulo requested.usec, 781*5b9c547cSRui Paulo handler, eloop_data, 782*5b9c547cSRui Paulo user_data); 783*5b9c547cSRui Paulo return 1; 784*5b9c547cSRui Paulo } 785*5b9c547cSRui Paulo return 0; 786*5b9c547cSRui Paulo } 787*5b9c547cSRui Paulo } 788*5b9c547cSRui Paulo 789*5b9c547cSRui Paulo return -1; 790*5b9c547cSRui Paulo } 791*5b9c547cSRui Paulo 792*5b9c547cSRui Paulo 79339beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 79439beb93cSSam Leffler static void eloop_handle_alarm(int sig) 79539beb93cSSam Leffler { 796e28a4053SRui Paulo wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " 797e28a4053SRui Paulo "two seconds. Looks like there\n" 79839beb93cSSam Leffler "is a bug that ends up in a busy loop that " 79939beb93cSSam Leffler "prevents clean shutdown.\n" 80039beb93cSSam Leffler "Killing program forcefully.\n"); 80139beb93cSSam Leffler exit(1); 80239beb93cSSam Leffler } 80339beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 80439beb93cSSam Leffler 80539beb93cSSam Leffler 80639beb93cSSam Leffler static void eloop_handle_signal(int sig) 80739beb93cSSam Leffler { 80839beb93cSSam Leffler int i; 80939beb93cSSam Leffler 81039beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 81139beb93cSSam Leffler if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { 81239beb93cSSam Leffler /* Use SIGALRM to break out from potential busy loops that 81339beb93cSSam Leffler * would not allow the program to be killed. */ 81439beb93cSSam Leffler eloop.pending_terminate = 1; 81539beb93cSSam Leffler signal(SIGALRM, eloop_handle_alarm); 81639beb93cSSam Leffler alarm(2); 81739beb93cSSam Leffler } 81839beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 81939beb93cSSam Leffler 82039beb93cSSam Leffler eloop.signaled++; 82139beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) { 82239beb93cSSam Leffler if (eloop.signals[i].sig == sig) { 82339beb93cSSam Leffler eloop.signals[i].signaled++; 82439beb93cSSam Leffler break; 82539beb93cSSam Leffler } 82639beb93cSSam Leffler } 82739beb93cSSam Leffler } 82839beb93cSSam Leffler 82939beb93cSSam Leffler 83039beb93cSSam Leffler static void eloop_process_pending_signals(void) 83139beb93cSSam Leffler { 83239beb93cSSam Leffler int i; 83339beb93cSSam Leffler 83439beb93cSSam Leffler if (eloop.signaled == 0) 83539beb93cSSam Leffler return; 83639beb93cSSam Leffler eloop.signaled = 0; 83739beb93cSSam Leffler 83839beb93cSSam Leffler if (eloop.pending_terminate) { 83939beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS 84039beb93cSSam Leffler alarm(0); 84139beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 84239beb93cSSam Leffler eloop.pending_terminate = 0; 84339beb93cSSam Leffler } 84439beb93cSSam Leffler 84539beb93cSSam Leffler for (i = 0; i < eloop.signal_count; i++) { 84639beb93cSSam Leffler if (eloop.signals[i].signaled) { 84739beb93cSSam Leffler eloop.signals[i].signaled = 0; 84839beb93cSSam Leffler eloop.signals[i].handler(eloop.signals[i].sig, 84939beb93cSSam Leffler eloop.signals[i].user_data); 85039beb93cSSam Leffler } 85139beb93cSSam Leffler } 85239beb93cSSam Leffler } 85339beb93cSSam Leffler 85439beb93cSSam Leffler 85539beb93cSSam Leffler int eloop_register_signal(int sig, eloop_signal_handler handler, 85639beb93cSSam Leffler void *user_data) 85739beb93cSSam Leffler { 85839beb93cSSam Leffler struct eloop_signal *tmp; 85939beb93cSSam Leffler 860f05cddf9SRui Paulo tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1, 86139beb93cSSam Leffler sizeof(struct eloop_signal)); 86239beb93cSSam Leffler if (tmp == NULL) 86339beb93cSSam Leffler return -1; 86439beb93cSSam Leffler 86539beb93cSSam Leffler tmp[eloop.signal_count].sig = sig; 86639beb93cSSam Leffler tmp[eloop.signal_count].user_data = user_data; 86739beb93cSSam Leffler tmp[eloop.signal_count].handler = handler; 86839beb93cSSam Leffler tmp[eloop.signal_count].signaled = 0; 86939beb93cSSam Leffler eloop.signal_count++; 87039beb93cSSam Leffler eloop.signals = tmp; 87139beb93cSSam Leffler signal(sig, eloop_handle_signal); 87239beb93cSSam Leffler 87339beb93cSSam Leffler return 0; 87439beb93cSSam Leffler } 87539beb93cSSam Leffler 87639beb93cSSam Leffler 87739beb93cSSam Leffler int eloop_register_signal_terminate(eloop_signal_handler handler, 87839beb93cSSam Leffler void *user_data) 87939beb93cSSam Leffler { 88039beb93cSSam Leffler int ret = eloop_register_signal(SIGINT, handler, user_data); 88139beb93cSSam Leffler if (ret == 0) 88239beb93cSSam Leffler ret = eloop_register_signal(SIGTERM, handler, user_data); 88339beb93cSSam Leffler return ret; 88439beb93cSSam Leffler } 88539beb93cSSam Leffler 88639beb93cSSam Leffler 88739beb93cSSam Leffler int eloop_register_signal_reconfig(eloop_signal_handler handler, 88839beb93cSSam Leffler void *user_data) 88939beb93cSSam Leffler { 89039beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS 89139beb93cSSam Leffler return 0; 89239beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */ 89339beb93cSSam Leffler return eloop_register_signal(SIGHUP, handler, user_data); 89439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */ 89539beb93cSSam Leffler } 89639beb93cSSam Leffler 89739beb93cSSam Leffler 89839beb93cSSam Leffler void eloop_run(void) 89939beb93cSSam Leffler { 900f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 901f05cddf9SRui Paulo int num_poll_fds; 902f05cddf9SRui Paulo int timeout_ms = 0; 903*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 904*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 90539beb93cSSam Leffler fd_set *rfds, *wfds, *efds; 90639beb93cSSam Leffler struct timeval _tv; 907*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 908*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 909*5b9c547cSRui Paulo int timeout_ms = -1; 910*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 911f05cddf9SRui Paulo int res; 912*5b9c547cSRui Paulo struct os_reltime tv, now; 91339beb93cSSam Leffler 914*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 91539beb93cSSam Leffler rfds = os_malloc(sizeof(*rfds)); 91639beb93cSSam Leffler wfds = os_malloc(sizeof(*wfds)); 91739beb93cSSam Leffler efds = os_malloc(sizeof(*efds)); 918e28a4053SRui Paulo if (rfds == NULL || wfds == NULL || efds == NULL) 91939beb93cSSam Leffler goto out; 920*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 92139beb93cSSam Leffler 92239beb93cSSam Leffler while (!eloop.terminate && 923e28a4053SRui Paulo (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || 92439beb93cSSam Leffler eloop.writers.count > 0 || eloop.exceptions.count > 0)) { 925e28a4053SRui Paulo struct eloop_timeout *timeout; 926e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 927e28a4053SRui Paulo list); 928e28a4053SRui Paulo if (timeout) { 929*5b9c547cSRui Paulo os_get_reltime(&now); 930*5b9c547cSRui Paulo if (os_reltime_before(&now, &timeout->time)) 931*5b9c547cSRui Paulo os_reltime_sub(&timeout->time, &now, &tv); 93239beb93cSSam Leffler else 93339beb93cSSam Leffler tv.sec = tv.usec = 0; 934*5b9c547cSRui Paulo #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) 935f05cddf9SRui Paulo timeout_ms = tv.sec * 1000 + tv.usec / 1000; 936*5b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */ 937*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 93839beb93cSSam Leffler _tv.tv_sec = tv.sec; 93939beb93cSSam Leffler _tv.tv_usec = tv.usec; 940*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 94139beb93cSSam Leffler } 94239beb93cSSam Leffler 943f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 944f05cddf9SRui Paulo num_poll_fds = eloop_sock_table_set_fds( 945f05cddf9SRui Paulo &eloop.readers, &eloop.writers, &eloop.exceptions, 946f05cddf9SRui Paulo eloop.pollfds, eloop.pollfds_map, 947f05cddf9SRui Paulo eloop.max_pollfd_map); 948f05cddf9SRui Paulo res = poll(eloop.pollfds, num_poll_fds, 949f05cddf9SRui Paulo timeout ? timeout_ms : -1); 950*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 951*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 95239beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.readers, rfds); 95339beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.writers, wfds); 95439beb93cSSam Leffler eloop_sock_table_set_fds(&eloop.exceptions, efds); 95539beb93cSSam Leffler res = select(eloop.max_sock + 1, rfds, wfds, efds, 956e28a4053SRui Paulo timeout ? &_tv : NULL); 957*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 958*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 959*5b9c547cSRui Paulo if (eloop.count == 0) { 960*5b9c547cSRui Paulo res = 0; 961*5b9c547cSRui Paulo } else { 962*5b9c547cSRui Paulo res = epoll_wait(eloop.epollfd, eloop.epoll_events, 963*5b9c547cSRui Paulo eloop.count, timeout_ms); 964*5b9c547cSRui Paulo } 965*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 96639beb93cSSam Leffler if (res < 0 && errno != EINTR && errno != 0) { 967*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "eloop: %s: %s", 968*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_POLL 969*5b9c547cSRui Paulo "poll" 970*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 971*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 972*5b9c547cSRui Paulo "select" 973*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 974*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 975*5b9c547cSRui Paulo "epoll" 976*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 977*5b9c547cSRui Paulo , strerror(errno)); 97839beb93cSSam Leffler goto out; 97939beb93cSSam Leffler } 98039beb93cSSam Leffler eloop_process_pending_signals(); 98139beb93cSSam Leffler 98239beb93cSSam Leffler /* check if some registered timeouts have occurred */ 983e28a4053SRui Paulo timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, 984e28a4053SRui Paulo list); 985e28a4053SRui Paulo if (timeout) { 986*5b9c547cSRui Paulo os_get_reltime(&now); 987*5b9c547cSRui Paulo if (!os_reltime_before(&now, &timeout->time)) { 988e28a4053SRui Paulo void *eloop_data = timeout->eloop_data; 989e28a4053SRui Paulo void *user_data = timeout->user_data; 990e28a4053SRui Paulo eloop_timeout_handler handler = 991e28a4053SRui Paulo timeout->handler; 992e28a4053SRui Paulo eloop_remove_timeout(timeout); 993e28a4053SRui Paulo handler(eloop_data, user_data); 99439beb93cSSam Leffler } 99539beb93cSSam Leffler 99639beb93cSSam Leffler } 99739beb93cSSam Leffler 99839beb93cSSam Leffler if (res <= 0) 99939beb93cSSam Leffler continue; 100039beb93cSSam Leffler 1001f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 1002f05cddf9SRui Paulo eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, 1003f05cddf9SRui Paulo &eloop.exceptions, eloop.pollfds_map, 1004f05cddf9SRui Paulo eloop.max_pollfd_map); 1005*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 1006*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 100739beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.readers, rfds); 100839beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.writers, wfds); 100939beb93cSSam Leffler eloop_sock_table_dispatch(&eloop.exceptions, efds); 1010*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 1011*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 1012*5b9c547cSRui Paulo eloop_sock_table_dispatch(eloop.epoll_events, res); 1013*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 101439beb93cSSam Leffler } 101539beb93cSSam Leffler 1016*5b9c547cSRui Paulo eloop.terminate = 0; 101739beb93cSSam Leffler out: 1018*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 101939beb93cSSam Leffler os_free(rfds); 102039beb93cSSam Leffler os_free(wfds); 102139beb93cSSam Leffler os_free(efds); 1022*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 1023f05cddf9SRui Paulo return; 102439beb93cSSam Leffler } 102539beb93cSSam Leffler 102639beb93cSSam Leffler 102739beb93cSSam Leffler void eloop_terminate(void) 102839beb93cSSam Leffler { 102939beb93cSSam Leffler eloop.terminate = 1; 103039beb93cSSam Leffler } 103139beb93cSSam Leffler 103239beb93cSSam Leffler 103339beb93cSSam Leffler void eloop_destroy(void) 103439beb93cSSam Leffler { 103539beb93cSSam Leffler struct eloop_timeout *timeout, *prev; 1036*5b9c547cSRui Paulo struct os_reltime now; 103739beb93cSSam Leffler 1038*5b9c547cSRui Paulo os_get_reltime(&now); 1039e28a4053SRui Paulo dl_list_for_each_safe(timeout, prev, &eloop.timeout, 1040e28a4053SRui Paulo struct eloop_timeout, list) { 104139beb93cSSam Leffler int sec, usec; 1042e28a4053SRui Paulo sec = timeout->time.sec - now.sec; 1043e28a4053SRui Paulo usec = timeout->time.usec - now.usec; 1044e28a4053SRui Paulo if (timeout->time.usec < now.usec) { 104539beb93cSSam Leffler sec--; 104639beb93cSSam Leffler usec += 1000000; 104739beb93cSSam Leffler } 1048e28a4053SRui Paulo wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " 1049e28a4053SRui Paulo "eloop_data=%p user_data=%p handler=%p", 1050e28a4053SRui Paulo sec, usec, timeout->eloop_data, timeout->user_data, 1051e28a4053SRui Paulo timeout->handler); 1052e28a4053SRui Paulo wpa_trace_dump_funcname("eloop unregistered timeout handler", 1053e28a4053SRui Paulo timeout->handler); 1054e28a4053SRui Paulo wpa_trace_dump("eloop timeout", timeout); 1055e28a4053SRui Paulo eloop_remove_timeout(timeout); 105639beb93cSSam Leffler } 105739beb93cSSam Leffler eloop_sock_table_destroy(&eloop.readers); 105839beb93cSSam Leffler eloop_sock_table_destroy(&eloop.writers); 105939beb93cSSam Leffler eloop_sock_table_destroy(&eloop.exceptions); 106039beb93cSSam Leffler os_free(eloop.signals); 1061f05cddf9SRui Paulo 1062f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 1063f05cddf9SRui Paulo os_free(eloop.pollfds); 1064f05cddf9SRui Paulo os_free(eloop.pollfds_map); 1065f05cddf9SRui Paulo #endif /* CONFIG_ELOOP_POLL */ 1066*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_EPOLL 1067*5b9c547cSRui Paulo os_free(eloop.epoll_table); 1068*5b9c547cSRui Paulo os_free(eloop.epoll_events); 1069*5b9c547cSRui Paulo close(eloop.epollfd); 1070*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_EPOLL */ 107139beb93cSSam Leffler } 107239beb93cSSam Leffler 107339beb93cSSam Leffler 107439beb93cSSam Leffler int eloop_terminated(void) 107539beb93cSSam Leffler { 107639beb93cSSam Leffler return eloop.terminate; 107739beb93cSSam Leffler } 107839beb93cSSam Leffler 107939beb93cSSam Leffler 108039beb93cSSam Leffler void eloop_wait_for_read_sock(int sock) 108139beb93cSSam Leffler { 1082f05cddf9SRui Paulo #ifdef CONFIG_ELOOP_POLL 1083f05cddf9SRui Paulo struct pollfd pfd; 1084f05cddf9SRui Paulo 1085f05cddf9SRui Paulo if (sock < 0) 1086f05cddf9SRui Paulo return; 1087f05cddf9SRui Paulo 1088f05cddf9SRui Paulo os_memset(&pfd, 0, sizeof(pfd)); 1089f05cddf9SRui Paulo pfd.fd = sock; 1090f05cddf9SRui Paulo pfd.events = POLLIN; 1091f05cddf9SRui Paulo 1092f05cddf9SRui Paulo poll(&pfd, 1, -1); 1093*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_POLL */ 1094*5b9c547cSRui Paulo #if defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) 1095*5b9c547cSRui Paulo /* 1096*5b9c547cSRui Paulo * We can use epoll() here. But epoll() requres 4 system calls. 1097*5b9c547cSRui Paulo * epoll_create1(), epoll_ctl() for ADD, epoll_wait, and close() for 1098*5b9c547cSRui Paulo * epoll fd. So select() is better for performance here. 1099*5b9c547cSRui Paulo */ 110039beb93cSSam Leffler fd_set rfds; 110139beb93cSSam Leffler 110239beb93cSSam Leffler if (sock < 0) 110339beb93cSSam Leffler return; 110439beb93cSSam Leffler 110539beb93cSSam Leffler FD_ZERO(&rfds); 110639beb93cSSam Leffler FD_SET(sock, &rfds); 110739beb93cSSam Leffler select(sock + 1, &rfds, NULL, NULL, NULL); 1108*5b9c547cSRui Paulo #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */ 110939beb93cSSam Leffler } 1110*5b9c547cSRui Paulo 1111*5b9c547cSRui Paulo #ifdef CONFIG_ELOOP_SELECT 1112*5b9c547cSRui Paulo #undef CONFIG_ELOOP_SELECT 1113*5b9c547cSRui Paulo #endif /* CONFIG_ELOOP_SELECT */ 1114