📄 eloop.c
字号:
/* * Event loop based on select() loop * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "eloop.h"struct eloop_sock { int sock; void *eloop_data; void *user_data; eloop_sock_handler handler;};struct eloop_timeout { struct os_time time; void *eloop_data; void *user_data; eloop_timeout_handler handler; struct eloop_timeout *next;};struct eloop_signal { int sig; void *user_data; eloop_signal_handler handler; int signaled;};struct eloop_sock_table { int count; struct eloop_sock *table; int changed;};struct eloop_data { void *user_data; int max_sock; struct eloop_sock_table readers; struct eloop_sock_table writers; struct eloop_sock_table exceptions; struct eloop_timeout *timeout; int signal_count; struct eloop_signal *signals; int signaled; int pending_terminate; int terminate; int reader_table_changed;};static struct eloop_data eloop;int eloop_init(void *user_data){ os_memset(&eloop, 0, sizeof(eloop)); eloop.user_data = user_data; return 0;}static int eloop_sock_table_add_sock(struct eloop_sock_table *table, int sock, eloop_sock_handler handler, void *eloop_data, void *user_data){ struct eloop_sock *tmp; if (table == NULL) return -1; tmp = (struct eloop_sock *) os_realloc(table->table, (table->count + 1) * sizeof(struct eloop_sock)); if (tmp == NULL) return -1; tmp[table->count].sock = sock; tmp[table->count].eloop_data = eloop_data; tmp[table->count].user_data = user_data; tmp[table->count].handler = handler; table->count++; table->table = tmp; if (sock > eloop.max_sock) eloop.max_sock = sock; table->changed = 1; return 0;}static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, int sock){ int i; if (table == NULL || table->table == NULL || table->count == 0) return; for (i = 0; i < table->count; i++) { if (table->table[i].sock == sock) break; } if (i == table->count) return; if (i != table->count - 1) { os_memmove(&table->table[i], &table->table[i + 1], (table->count - i - 1) * sizeof(struct eloop_sock)); } table->count--; table->changed = 1;}static void eloop_sock_table_set_fds(struct eloop_sock_table *table, fd_set *fds){ int i; FD_ZERO(fds); if (table->table == NULL) return; for (i = 0; i < table->count; i++) FD_SET(table->table[i].sock, fds);}static void eloop_sock_table_dispatch(struct eloop_sock_table *table, fd_set *fds){ int i; if (table == NULL || table->table == NULL) return; table->changed = 0; for (i = 0; i < table->count; i++) { if (FD_ISSET(table->table[i].sock, fds)) { table->table[i].handler(table->table[i].sock, table->table[i].eloop_data, table->table[i].user_data); if (table->changed) break; } }}static void eloop_sock_table_destroy(struct eloop_sock_table *table){ if (table) os_free(table->table);}int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data){ return eloop_register_sock(sock, EVENT_TYPE_READ, handler, eloop_data, user_data);}void eloop_unregister_read_sock(int sock){ eloop_unregister_sock(sock, EVENT_TYPE_READ);}static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type){ switch (type) { case EVENT_TYPE_READ: return &eloop.readers; case EVENT_TYPE_WRITE: return &eloop.writers; case EVENT_TYPE_EXCEPTION: return &eloop.exceptions; } return NULL;}int eloop_register_sock(int sock, eloop_event_type type, eloop_sock_handler handler, void *eloop_data, void *user_data){ struct eloop_sock_table *table; table = eloop_get_sock_table(type); return eloop_sock_table_add_sock(table, sock, handler, eloop_data, user_data);}void eloop_unregister_sock(int sock, eloop_event_type type){ struct eloop_sock_table *table; table = eloop_get_sock_table(type); eloop_sock_table_remove_sock(table, sock);}int eloop_register_timeout(unsigned int secs, unsigned int usecs, eloop_timeout_handler handler, void *eloop_data, void *user_data){ struct eloop_timeout *timeout, *tmp, *prev; timeout = os_malloc(sizeof(*timeout)); if (timeout == NULL) return -1; os_get_time(&timeout->time); timeout->time.sec += secs; timeout->time.usec += usecs; while (timeout->time.usec >= 1000000) { timeout->time.sec++; timeout->time.usec -= 1000000; } timeout->eloop_data = eloop_data; timeout->user_data = user_data; timeout->handler = handler; timeout->next = NULL; if (eloop.timeout == NULL) { eloop.timeout = timeout; return 0; } prev = NULL; tmp = eloop.timeout; while (tmp != NULL) { if (os_time_before(&timeout->time, &tmp->time)) break; prev = tmp; tmp = tmp->next; } if (prev == NULL) { timeout->next = eloop.timeout; eloop.timeout = timeout; } else { timeout->next = prev->next; prev->next = timeout; } return 0;}int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data){ struct eloop_timeout *timeout, *prev, *next; int removed = 0; prev = NULL; timeout = eloop.timeout; while (timeout != NULL) { next = timeout->next; if (timeout->handler == handler && (timeout->eloop_data == eloop_data || eloop_data == ELOOP_ALL_CTX) && (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX)) { if (prev == NULL) eloop.timeout = next; else prev->next = next; os_free(timeout); removed++; } else prev = timeout; timeout = next; } return removed;}#ifndef CONFIG_NATIVE_WINDOWSstatic void eloop_handle_alarm(int sig){ fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two " "seconds. Looks like there\n" "is a bug that ends up in a busy loop that " "prevents clean shutdown.\n" "Killing program forcefully.\n"); exit(1);}#endif /* CONFIG_NATIVE_WINDOWS */static void eloop_handle_signal(int sig){ int i;#ifndef CONFIG_NATIVE_WINDOWS if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { /* Use SIGALRM to break out from potential busy loops that * would not allow the program to be killed. */ eloop.pending_terminate = 1; signal(SIGALRM, eloop_handle_alarm); alarm(2); }#endif /* CONFIG_NATIVE_WINDOWS */ eloop.signaled++; for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].sig == sig) { eloop.signals[i].signaled++; break; } }}static void eloop_process_pending_signals(void){ int i; if (eloop.signaled == 0) return; eloop.signaled = 0; if (eloop.pending_terminate) {#ifndef CONFIG_NATIVE_WINDOWS alarm(0);#endif /* CONFIG_NATIVE_WINDOWS */ eloop.pending_terminate = 0; } for (i = 0; i < eloop.signal_count; i++) { if (eloop.signals[i].signaled) { eloop.signals[i].signaled = 0; eloop.signals[i].handler(eloop.signals[i].sig, eloop.user_data, eloop.signals[i].user_data); } }}int eloop_register_signal(int sig, eloop_signal_handler handler, void *user_data){ struct eloop_signal *tmp; tmp = (struct eloop_signal *) os_realloc(eloop.signals, (eloop.signal_count + 1) * sizeof(struct eloop_signal)); if (tmp == NULL) return -1; tmp[eloop.signal_count].sig = sig; tmp[eloop.signal_count].user_data = user_data; tmp[eloop.signal_count].handler = handler; tmp[eloop.signal_count].signaled = 0; eloop.signal_count++; eloop.signals = tmp; signal(sig, eloop_handle_signal); return 0;}int eloop_register_signal_terminate(eloop_signal_handler handler, void *user_data){ int ret = eloop_register_signal(SIGINT, handler, user_data); if (ret == 0) ret = eloop_register_signal(SIGTERM, handler, user_data); return ret;}int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data){#ifdef CONFIG_NATIVE_WINDOWS return 0;#else /* CONFIG_NATIVE_WINDOWS */ return eloop_register_signal(SIGHUP, handler, user_data);#endif /* CONFIG_NATIVE_WINDOWS */}void eloop_run(void){ fd_set *rfds, *wfds, *efds; int res; struct timeval _tv; struct os_time tv, now; rfds = os_malloc(sizeof(*rfds)); wfds = os_malloc(sizeof(*wfds)); efds = os_malloc(sizeof(*efds)); if (rfds == NULL || wfds == NULL || efds == NULL) { printf("eloop_run - malloc failed\n"); goto out; } while (!eloop.terminate && (eloop.timeout || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0)) { if (eloop.timeout) { os_get_time(&now); if (os_time_before(&now, &eloop.timeout->time)) os_time_sub(&eloop.timeout->time, &now, &tv); else tv.sec = tv.usec = 0;#if 0 printf("next timeout in %lu.%06lu sec\n", tv.sec, tv.usec);#endif _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; } eloop_sock_table_set_fds(&eloop.readers, rfds); eloop_sock_table_set_fds(&eloop.writers, wfds); eloop_sock_table_set_fds(&eloop.exceptions, efds); res = select(eloop.max_sock + 1, rfds, wfds, efds, eloop.timeout ? &_tv : NULL); if (res < 0 && errno != EINTR && errno != 0) { perror("select"); goto out; } eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ if (eloop.timeout) { struct eloop_timeout *tmp; os_get_time(&now); if (!os_time_before(&now, &eloop.timeout->time)) { tmp = eloop.timeout; eloop.timeout = eloop.timeout->next; tmp->handler(tmp->eloop_data, tmp->user_data); os_free(tmp); } } if (res <= 0) continue; eloop_sock_table_dispatch(&eloop.readers, rfds); eloop_sock_table_dispatch(&eloop.writers, wfds); eloop_sock_table_dispatch(&eloop.exceptions, efds); }out: os_free(rfds); os_free(wfds); os_free(efds);}void eloop_terminate(void){ eloop.terminate = 1;}void eloop_destroy(void){ struct eloop_timeout *timeout, *prev; timeout = eloop.timeout; while (timeout != NULL) { prev = timeout; timeout = timeout->next; os_free(prev); } eloop_sock_table_destroy(&eloop.readers); eloop_sock_table_destroy(&eloop.writers); eloop_sock_table_destroy(&eloop.exceptions); os_free(eloop.signals);}int eloop_terminated(void){ return eloop.terminate;}void eloop_wait_for_read_sock(int sock){ fd_set rfds; if (sock < 0) return; FD_ZERO(&rfds); FD_SET(sock, &rfds); select(sock + 1, &rfds, NULL, NULL, NULL);}void * eloop_get_user_data(void){ return eloop.user_data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -