1/* 2 * Event loop - empty template (basic structure, but no OS specific operations) 3 * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15#include "includes.h" 16 17#include "common.h" 18#include "eloop.h" 19 20 21struct eloop_sock { 22 int sock; 23 void *eloop_data; 24 void *user_data; 25 void (*handler)(int sock, void *eloop_ctx, void *sock_ctx); 26}; 27 28struct eloop_timeout { 29 struct os_time time; 30 void *eloop_data; 31 void *user_data; 32 void (*handler)(void *eloop_ctx, void *sock_ctx); 33 struct eloop_timeout *next; 34}; 35 36struct eloop_signal { 37 int sig; 38 void *user_data; 39 void (*handler)(int sig, void *eloop_ctx, void *signal_ctx); 40 int signaled; 41}; 42 43struct eloop_data { 44 void *user_data; 45 46 int max_sock, reader_count; 47 struct eloop_sock *readers; 48 49 struct eloop_timeout *timeout; 50 51 int signal_count; 52 struct eloop_signal *signals; 53 int signaled; 54 int pending_terminate; 55 56 int terminate; 57 int reader_table_changed; 58}; 59 60static struct eloop_data eloop; 61 62 63int eloop_init(void *user_data) 64{ 65 memset(&eloop, 0, sizeof(eloop)); 66 eloop.user_data = user_data; 67 return 0; 68} 69 70 71int eloop_register_read_sock(int sock, 72 void (*handler)(int sock, void *eloop_ctx, 73 void *sock_ctx), 74 void *eloop_data, void *user_data) 75{ 76 struct eloop_sock *tmp; 77 78 tmp = (struct eloop_sock *) 79 realloc(eloop.readers, 80 (eloop.reader_count + 1) * sizeof(struct eloop_sock)); 81 if (tmp == NULL) 82 return -1; 83 84 tmp[eloop.reader_count].sock = sock; 85 tmp[eloop.reader_count].eloop_data = eloop_data; 86 tmp[eloop.reader_count].user_data = user_data; 87 tmp[eloop.reader_count].handler = handler; 88 eloop.reader_count++; 89 eloop.readers = tmp; 90 if (sock > eloop.max_sock) 91 eloop.max_sock = sock; 92 eloop.reader_table_changed = 1; 93 94 return 0; 95} 96 97 98void eloop_unregister_read_sock(int sock) 99{ 100 int i; 101 102 if (eloop.readers == NULL || eloop.reader_count == 0) 103 return; 104 105 for (i = 0; i < eloop.reader_count; i++) { 106 if (eloop.readers[i].sock == sock) 107 break; 108 } 109 if (i == eloop.reader_count) 110 return; 111 if (i != eloop.reader_count - 1) { 112 memmove(&eloop.readers[i], &eloop.readers[i + 1], 113 (eloop.reader_count - i - 1) * 114 sizeof(struct eloop_sock)); 115 } 116 eloop.reader_count--; 117 eloop.reader_table_changed = 1; 118} 119 120 121int eloop_register_timeout(unsigned int secs, unsigned int usecs, 122 void (*handler)(void *eloop_ctx, void *timeout_ctx), 123 void *eloop_data, void *user_data) 124{ 125 struct eloop_timeout *timeout, *tmp, *prev; 126 127 timeout = (struct eloop_timeout *) malloc(sizeof(*timeout)); 128 if (timeout == NULL) 129 return -1; 130 os_get_time(&timeout->time); 131 timeout->time.sec += secs; 132 timeout->time.usec += usecs; 133 while (timeout->time.usec >= 1000000) { 134 timeout->time.sec++; 135 timeout->time.usec -= 1000000; 136 } 137 timeout->eloop_data = eloop_data; 138 timeout->user_data = user_data; 139 timeout->handler = handler; 140 timeout->next = NULL; 141 142 if (eloop.timeout == NULL) { 143 eloop.timeout = timeout; 144 return 0; 145 } 146 147 prev = NULL; 148 tmp = eloop.timeout; 149 while (tmp != NULL) { 150 if (os_time_before(&timeout->time, &tmp->time)) 151 break; 152 prev = tmp; 153 tmp = tmp->next; 154 } 155 156 if (prev == NULL) { 157 timeout->next = eloop.timeout; 158 eloop.timeout = timeout; 159 } else { 160 timeout->next = prev->next; 161 prev->next = timeout; 162 } 163 164 return 0; 165} 166 167 168int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), 169 void *eloop_data, void *user_data) 170{ 171 struct eloop_timeout *timeout, *prev, *next; 172 int removed = 0; 173 174 prev = NULL; 175 timeout = eloop.timeout; 176 while (timeout != NULL) { 177 next = timeout->next; 178 179 if (timeout->handler == handler && 180 (timeout->eloop_data == eloop_data || 181 eloop_data == ELOOP_ALL_CTX) && 182 (timeout->user_data == user_data || 183 user_data == ELOOP_ALL_CTX)) { 184 if (prev == NULL) 185 eloop.timeout = next; 186 else 187 prev->next = next; 188 free(timeout); 189 removed++; 190 } else 191 prev = timeout; 192 193 timeout = next; 194 } 195 196 return removed; 197} 198 199 200int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx, 201 void *timeout_ctx), 202 void *eloop_data, void *user_data) 203{ 204 struct eloop_timeout *tmp; 205 206 tmp = eloop.timeout; 207 while (tmp != NULL) { 208 if (tmp->handler == handler && 209 tmp->eloop_data == eloop_data && 210 tmp->user_data == user_data) 211 return 1; 212 213 tmp = tmp->next; 214 } 215 216 return 0; 217} 218 219 220/* TODO: replace with suitable signal handler */ 221#if 0 222static void eloop_handle_signal(int sig) 223{ 224 int i; 225 226 eloop.signaled++; 227 for (i = 0; i < eloop.signal_count; i++) { 228 if (eloop.signals[i].sig == sig) { 229 eloop.signals[i].signaled++; 230 break; 231 } 232 } 233} 234#endif 235 236 237static void eloop_process_pending_signals(void) 238{ 239 int i; 240 241 if (eloop.signaled == 0) 242 return; 243 eloop.signaled = 0; 244 245 if (eloop.pending_terminate) { 246 eloop.pending_terminate = 0; 247 } 248 249 for (i = 0; i < eloop.signal_count; i++) { 250 if (eloop.signals[i].signaled) { 251 eloop.signals[i].signaled = 0; 252 eloop.signals[i].handler(eloop.signals[i].sig, 253 eloop.user_data, 254 eloop.signals[i].user_data); 255 } 256 } 257} 258 259 260int eloop_register_signal(int sig, 261 void (*handler)(int sig, void *eloop_ctx, 262 void *signal_ctx), 263 void *user_data) 264{ 265 struct eloop_signal *tmp; 266 267 tmp = (struct eloop_signal *) 268 realloc(eloop.signals, 269 (eloop.signal_count + 1) * 270 sizeof(struct eloop_signal)); 271 if (tmp == NULL) 272 return -1; 273 274 tmp[eloop.signal_count].sig = sig; 275 tmp[eloop.signal_count].user_data = user_data; 276 tmp[eloop.signal_count].handler = handler; 277 tmp[eloop.signal_count].signaled = 0; 278 eloop.signal_count++; 279 eloop.signals = tmp; 280 281 /* TODO: register signal handler */ 282 283 return 0; 284} 285 286 287int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx, 288 void *signal_ctx), 289 void *user_data) 290{ 291#if 0 292 /* TODO: for example */ 293 int ret = eloop_register_signal(SIGINT, handler, user_data); 294 if (ret == 0) 295 ret = eloop_register_signal(SIGTERM, handler, user_data); 296 return ret; 297#endif 298 return 0; 299} 300 301 302int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx, 303 void *signal_ctx), 304 void *user_data) 305{ 306#if 0 307 /* TODO: for example */ 308 return eloop_register_signal(SIGHUP, handler, user_data); 309#endif 310 return 0; 311} 312 313 314void eloop_run(void) 315{ 316 int i; 317 struct os_time tv, now; 318 319 while (!eloop.terminate && 320 (eloop.timeout || eloop.reader_count > 0)) { 321 if (eloop.timeout) { 322 os_get_time(&now); 323 if (os_time_before(&now, &eloop.timeout->time)) 324 os_time_sub(&eloop.timeout->time, &now, &tv); 325 else 326 tv.sec = tv.usec = 0; 327 } 328 329 /* 330 * TODO: wait for any event (read socket ready, timeout (tv), 331 * signal 332 */ 333 os_sleep(1, 0); /* just a dummy wait for testing */ 334 335 eloop_process_pending_signals(); 336 337 /* check if some registered timeouts have occurred */ 338 if (eloop.timeout) { 339 struct eloop_timeout *tmp; 340 341 os_get_time(&now); 342 if (!os_time_before(&now, &eloop.timeout->time)) { 343 tmp = eloop.timeout; 344 eloop.timeout = eloop.timeout->next; 345 tmp->handler(tmp->eloop_data, 346 tmp->user_data); 347 free(tmp); 348 } 349 350 } 351 352 eloop.reader_table_changed = 0; 353 for (i = 0; i < eloop.reader_count; i++) { 354 /* 355 * TODO: call each handler that has pending data to 356 * read 357 */ 358 if (0 /* TODO: eloop.readers[i].sock ready */) { 359 eloop.readers[i].handler( 360 eloop.readers[i].sock, 361 eloop.readers[i].eloop_data, 362 eloop.readers[i].user_data); 363 if (eloop.reader_table_changed) 364 break; 365 } 366 } 367 } 368} 369 370 371void eloop_terminate(void) 372{ 373 eloop.terminate = 1; 374} 375 376 377void eloop_destroy(void) 378{ 379 struct eloop_timeout *timeout, *prev; 380 381 timeout = eloop.timeout; 382 while (timeout != NULL) { 383 prev = timeout; 384 timeout = timeout->next; 385 free(prev); 386 } 387 free(eloop.readers); 388 free(eloop.signals); 389} 390 391 392int eloop_terminated(void) 393{ 394 return eloop.terminate; 395} 396 397 398void eloop_wait_for_read_sock(int sock) 399{ 400 /* 401 * TODO: wait for the file descriptor to have something available for 402 * reading 403 */ 404} 405 406 407void * eloop_get_user_data(void) 408{ 409 return eloop.user_data; 410} 411