1 /* $NetBSD: events.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* events 3 6 /* SUMMARY 7 /* event manager 8 /* SYNOPSIS 9 /* #include <events.h> 10 /* 11 /* time_t event_time() 12 /* 13 /* void event_loop(delay) 14 /* int delay; 15 /* 16 /* time_t event_request_timer(callback, context, delay) 17 /* void (*callback)(int event, void *context); 18 /* void *context; 19 /* int delay; 20 /* 21 /* int event_cancel_timer(callback, context) 22 /* void (*callback)(int event, void *context); 23 /* void *context; 24 /* 25 /* void event_enable_read(fd, callback, context) 26 /* int fd; 27 /* void (*callback)(int event, void *context); 28 /* void *context; 29 /* 30 /* void event_enable_write(fd, callback, context) 31 /* int fd; 32 /* void (*callback)(int event, void *context); 33 /* void *context; 34 /* 35 /* void event_disable_readwrite(fd) 36 /* int fd; 37 /* 38 /* void event_drain(time_limit) 39 /* int time_limit; 40 /* 41 /* void event_fork(void) 42 /* DESCRIPTION 43 /* This module delivers I/O and timer events. 44 /* Multiple I/O streams and timers can be monitored simultaneously. 45 /* Events are delivered via callback routines provided by the 46 /* application. When requesting an event, the application can provide 47 /* private context that is passed back when the callback routine is 48 /* executed. 49 /* 50 /* event_time() returns a cached value of the current time. 51 /* 52 /* event_loop() monitors all I/O channels for which the application has 53 /* expressed interest, and monitors the timer request queue. 54 /* It notifies the application whenever events of interest happen. 55 /* A negative delay value causes the function to pause until something 56 /* happens; a positive delay value causes event_loop() to return when 57 /* the next event happens or when the delay time in seconds is over, 58 /* whatever happens first. A zero delay effectuates a poll. 59 /* 60 /* Note: in order to avoid race conditions, event_loop() cannot 61 /* not be called recursively. 62 /* 63 /* event_request_timer() causes the specified callback function to 64 /* be called with the specified context argument after \fIdelay\fR 65 /* seconds, or as soon as possible thereafter. The delay should 66 /* not be negative (the manifest EVENT_NULL_DELAY provides for 67 /* convenient zero-delay notification). 68 /* The event argument is equal to EVENT_TIME. 69 /* Only one timer request can be active per (callback, context) pair. 70 /* Calling event_request_timer() with an existing (callback, context) 71 /* pair does not schedule a new event, but updates the time of event 72 /* delivery. The result is the absolute time at which the timer is 73 /* scheduled to go off. 74 /* 75 /* event_cancel_timer() cancels the specified (callback, context) request. 76 /* The application is allowed to cancel non-existing requests. The result 77 /* value is the amount of time left before the timer would have gone off, 78 /* or -1 in case of no pending timer. 79 /* 80 /* event_enable_read() (event_enable_write()) enables read (write) events 81 /* on the named I/O channel. It is up to the application to assemble 82 /* partial reads or writes. 83 /* An I/O channel cannot handle more than one request at the 84 /* same time. The application is allowed to enable an event that 85 /* is already enabled (same channel, same read or write operation, 86 /* but perhaps a different callback or context). On systems with 87 /* kernel-based event filters this is preferred usage, because 88 /* each disable and enable request would cost a system call. 89 /* 90 /* The manifest constants EVENT_NULL_CONTEXT and EVENT_NULL_TYPE 91 /* provide convenient null values. 92 /* 93 /* The callback routine has the following arguments: 94 /* .IP fd 95 /* The stream on which the event happened. 96 /* .IP event 97 /* An indication of the event type: 98 /* .RS 99 /* .IP EVENT_READ 100 /* read event, 101 /* .IP EVENT_WRITE 102 /* write event, 103 /* .IP EVENT_XCPT 104 /* exception (actually, any event other than read or write). 105 /* .RE 106 /* .IP context 107 /* Application context given to event_enable_read() (event_enable_write()). 108 /* .PP 109 /* event_disable_readwrite() disables further I/O events on the specified 110 /* I/O channel. The application is allowed to cancel non-existing 111 /* I/O event requests. 112 /* 113 /* event_drain() repeatedly calls event_loop() until no more timer 114 /* events or I/O events are pending or until the time limit is reached. 115 /* This routine must not be called from an event_whatever() callback 116 /* routine. Note: this function assumes that no new I/O events 117 /* will be registered. 118 /* 119 /* event_fork() must be called by a child process after it is 120 /* created with fork(), to re-initialize event processing. 121 /* DIAGNOSTICS 122 /* Panics: interface violations. Fatal errors: out of memory, 123 /* system call failure. Warnings: the number of available 124 /* file descriptors is much less than FD_SETSIZE. 125 /* BUGS 126 /* This module is based on event selection. It assumes that the 127 /* event_loop() routine is called frequently. This approach is 128 /* not suitable for applications with compute-bound loops that 129 /* take a significant amount of time. 130 /* LICENSE 131 /* .ad 132 /* .fi 133 /* The Secure Mailer license must be distributed with this software. 134 /* AUTHOR(S) 135 /* Wietse Venema 136 /* IBM T.J. Watson Research 137 /* P.O. Box 704 138 /* Yorktown Heights, NY 10598, USA 139 /*--*/ 140 141 /* System libraries. */ 142 143 #include "sys_defs.h" 144 #include <sys/time.h> /* XXX: 44BSD uses bzero() */ 145 #include <time.h> 146 #include <errno.h> 147 #include <unistd.h> 148 #include <stddef.h> /* offsetof() */ 149 #include <string.h> /* bzero() prototype for 44BSD */ 150 #include <limits.h> /* INT_MAX */ 151 152 #ifdef USE_SYS_SELECT_H 153 #include <sys/select.h> 154 #endif 155 156 /* Application-specific. */ 157 158 #include "mymalloc.h" 159 #include "msg.h" 160 #include "iostuff.h" 161 #include "ring.h" 162 #include "events.h" 163 164 #if !defined(EVENTS_STYLE) 165 #error "must define EVENTS_STYLE" 166 #endif 167 168 /* 169 * Traditional BSD-style select(2). Works everywhere, but has a built-in 170 * upper bound on the number of file descriptors, and that limit is hard to 171 * change on Linux. Is sometimes emulated with SYSV-style poll(2) which 172 * doesn't have the file descriptor limit, but unfortunately does not help 173 * to improve the performance of servers with lots of connections. 174 */ 175 #define EVENT_ALLOC_INCR 10 176 177 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 178 typedef fd_set EVENT_MASK; 179 180 #define EVENT_MASK_BYTE_COUNT(mask) sizeof(*(mask)) 181 #define EVENT_MASK_ZERO(mask) FD_ZERO(mask) 182 #define EVENT_MASK_SET(fd, mask) FD_SET((fd), (mask)) 183 #define EVENT_MASK_ISSET(fd, mask) FD_ISSET((fd), (mask)) 184 #define EVENT_MASK_CLR(fd, mask) FD_CLR((fd), (mask)) 185 #define EVENT_MASK_CMP(m1, m2) memcmp((m1), (m2), EVENT_MASK_BYTE_COUNT(m1)) 186 #else 187 188 /* 189 * Kernel-based event filters (kqueue, /dev/poll, epoll). We use the 190 * following file descriptor mask structure which is expanded on the fly. 191 */ 192 typedef struct { 193 char *data; /* bit mask */ 194 size_t data_len; /* data byte count */ 195 } EVENT_MASK; 196 197 /* Bits per byte, byte in vector, bit offset in byte, bytes per set. */ 198 #define EVENT_MASK_NBBY (8) 199 #define EVENT_MASK_FD_BYTE(fd, mask) \ 200 (((unsigned char *) (mask)->data)[(fd) / EVENT_MASK_NBBY]) 201 #define EVENT_MASK_FD_BIT(fd) (1 << ((fd) % EVENT_MASK_NBBY)) 202 #define EVENT_MASK_BYTES_NEEDED(len) \ 203 (((len) + (EVENT_MASK_NBBY -1)) / EVENT_MASK_NBBY) 204 #define EVENT_MASK_BYTE_COUNT(mask) ((mask)->data_len) 205 206 /* Memory management. */ 207 #define EVENT_MASK_ALLOC(mask, bit_len) do { \ 208 size_t _byte_len = EVENT_MASK_BYTES_NEEDED(bit_len); \ 209 (mask)->data = mymalloc(_byte_len); \ 210 memset((mask)->data, 0, _byte_len); \ 211 (mask)->data_len = _byte_len; \ 212 } while (0) 213 #define EVENT_MASK_REALLOC(mask, bit_len) do { \ 214 size_t _byte_len = EVENT_MASK_BYTES_NEEDED(bit_len); \ 215 size_t _old_len = (mask)->data_len; \ 216 (mask)->data = myrealloc((mask)->data, _byte_len); \ 217 if (_byte_len > _old_len) \ 218 memset((mask)->data + _old_len, 0, _byte_len - _old_len); \ 219 (mask)->data_len = _byte_len; \ 220 } while (0) 221 #define EVENT_MASK_FREE(mask) myfree((mask)->data) 222 223 /* Set operations, modeled after FD_ZERO/SET/ISSET/CLR. */ 224 #define EVENT_MASK_ZERO(mask) \ 225 memset((mask)->data, 0, (mask)->data_len) 226 #define EVENT_MASK_SET(fd, mask) \ 227 (EVENT_MASK_FD_BYTE((fd), (mask)) |= EVENT_MASK_FD_BIT(fd)) 228 #define EVENT_MASK_ISSET(fd, mask) \ 229 (EVENT_MASK_FD_BYTE((fd), (mask)) & EVENT_MASK_FD_BIT(fd)) 230 #define EVENT_MASK_CLR(fd, mask) \ 231 (EVENT_MASK_FD_BYTE((fd), (mask)) &= ~EVENT_MASK_FD_BIT(fd)) 232 #define EVENT_MASK_CMP(m1, m2) \ 233 memcmp((m1)->data, (m2)->data, EVENT_MASK_BYTE_COUNT(m1)) 234 #endif 235 236 /* 237 * I/O events. 238 */ 239 typedef struct EVENT_FDTABLE EVENT_FDTABLE; 240 241 struct EVENT_FDTABLE { 242 EVENT_NOTIFY_RDWR_FN callback; 243 char *context; 244 }; 245 static EVENT_MASK event_rmask; /* enabled read events */ 246 static EVENT_MASK event_wmask; /* enabled write events */ 247 static EVENT_MASK event_xmask; /* for bad news mostly */ 248 static int event_fdlimit; /* per-process open file limit */ 249 static EVENT_FDTABLE *event_fdtable; /* one slot per file descriptor */ 250 static int event_fdslots; /* number of file descriptor slots */ 251 static int event_max_fd = -1; /* highest fd number seen */ 252 253 /* 254 * FreeBSD kqueue supports no system call to find out what descriptors are 255 * registered in the kernel-based filter. To implement our own sanity checks 256 * we maintain our own descriptor bitmask. 257 * 258 * FreeBSD kqueue does support application context pointers. Unfortunately, 259 * changing that information would cost a system call, and some of the 260 * competitors don't support application context. To keep the implementation 261 * simple we maintain our own table with call-back information. 262 * 263 * FreeBSD kqueue silently unregisters a descriptor from its filter when the 264 * descriptor is closed, so our information could get out of sync with the 265 * kernel. But that will never happen, because we have to meticulously 266 * unregister a file descriptor before it is closed, to avoid errors on 267 * systems that are built with EVENTS_STYLE == EVENTS_STYLE_SELECT. 268 */ 269 #if (EVENTS_STYLE == EVENTS_STYLE_KQUEUE) 270 #include <sys/event.h> 271 272 /* 273 * Some early FreeBSD implementations don't have the EV_SET macro. 274 */ 275 #ifndef EV_SET 276 #define EV_SET(kp, id, fi, fl, ffl, da, ud) do { \ 277 (kp)->ident = (id); \ 278 (kp)->filter = (fi); \ 279 (kp)->flags = (fl); \ 280 (kp)->fflags = (ffl); \ 281 (kp)->data = (da); \ 282 (kp)->udata = (ud); \ 283 } while(0) 284 #endif 285 286 /* 287 * Macros to initialize the kernel-based filter; see event_init(). 288 */ 289 static int event_kq; /* handle to event filter */ 290 291 #define EVENT_REG_INIT_HANDLE(er, n) do { \ 292 er = event_kq = kqueue(); \ 293 } while (0) 294 #define EVENT_REG_INIT_TEXT "kqueue" 295 296 #define EVENT_REG_FORK_HANDLE(er, n) do { \ 297 (void) close(event_kq); \ 298 EVENT_REG_INIT_HANDLE(er, (n)); \ 299 } while (0) 300 301 /* 302 * Macros to update the kernel-based filter; see event_enable_read(), 303 * event_enable_write() and event_disable_readwrite(). 304 */ 305 #define EVENT_REG_FD_OP(er, fh, ev, op) do { \ 306 struct kevent dummy; \ 307 EV_SET(&dummy, (fh), (ev), (op), 0, 0, 0); \ 308 (er) = kevent(event_kq, &dummy, 1, 0, 0, 0); \ 309 } while (0) 310 311 #define EVENT_REG_ADD_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EV_ADD) 312 #define EVENT_REG_ADD_READ(e, f) EVENT_REG_ADD_OP((e), (f), EVFILT_READ) 313 #define EVENT_REG_ADD_WRITE(e, f) EVENT_REG_ADD_OP((e), (f), EVFILT_WRITE) 314 #define EVENT_REG_ADD_TEXT "kevent EV_ADD" 315 316 #define EVENT_REG_DEL_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EV_DELETE) 317 #define EVENT_REG_DEL_READ(e, f) EVENT_REG_DEL_OP((e), (f), EVFILT_READ) 318 #define EVENT_REG_DEL_WRITE(e, f) EVENT_REG_DEL_OP((e), (f), EVFILT_WRITE) 319 #define EVENT_REG_DEL_TEXT "kevent EV_DELETE" 320 321 /* 322 * Macros to retrieve event buffers from the kernel; see event_loop(). 323 */ 324 typedef struct kevent EVENT_BUFFER; 325 326 #define EVENT_BUFFER_READ(event_count, event_buf, buflen, delay) do { \ 327 struct timespec ts; \ 328 struct timespec *tsp; \ 329 if ((delay) < 0) { \ 330 tsp = 0; \ 331 } else { \ 332 tsp = &ts; \ 333 ts.tv_nsec = 0; \ 334 ts.tv_sec = (delay); \ 335 } \ 336 (event_count) = kevent(event_kq, (struct kevent *) 0, 0, (event_buf), \ 337 (buflen), (tsp)); \ 338 } while (0) 339 #define EVENT_BUFFER_READ_TEXT "kevent" 340 341 /* 342 * Macros to process event buffers from the kernel; see event_loop(). 343 */ 344 #define EVENT_GET_FD(bp) ((bp)->ident) 345 #define EVENT_GET_TYPE(bp) ((bp)->filter) 346 #define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) == EVFILT_READ) 347 #define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) == EVFILT_WRITE) 348 349 #endif 350 351 /* 352 * Solaris /dev/poll does not support application context, so we have to 353 * maintain our own. This has the benefit of avoiding an expensive system 354 * call just to change a call-back function or argument. 355 * 356 * Solaris /dev/poll does have a way to query if a specific descriptor is 357 * registered. However, we maintain a descriptor mask anyway because a) it 358 * avoids having to make an expensive system call to find out if something 359 * is registered, b) some EVENTS_STYLE_MUMBLE implementations need a 360 * descriptor bitmask anyway and c) we use the bitmask already to implement 361 * sanity checks. 362 */ 363 #if (EVENTS_STYLE == EVENTS_STYLE_DEVPOLL) 364 #include <sys/devpoll.h> 365 #include <fcntl.h> 366 367 /* 368 * Macros to initialize the kernel-based filter; see event_init(). 369 */ 370 static int event_pollfd; /* handle to file descriptor set */ 371 372 #define EVENT_REG_INIT_HANDLE(er, n) do { \ 373 er = event_pollfd = open("/dev/poll", O_RDWR); \ 374 if (event_pollfd >= 0) close_on_exec(event_pollfd, CLOSE_ON_EXEC); \ 375 } while (0) 376 #define EVENT_REG_INIT_TEXT "open /dev/poll" 377 378 #define EVENT_REG_FORK_HANDLE(er, n) do { \ 379 (void) close(event_pollfd); \ 380 EVENT_REG_INIT_HANDLE(er, (n)); \ 381 } while (0) 382 383 /* 384 * Macros to update the kernel-based filter; see event_enable_read(), 385 * event_enable_write() and event_disable_readwrite(). 386 */ 387 #define EVENT_REG_FD_OP(er, fh, ev) do { \ 388 struct pollfd dummy; \ 389 dummy.fd = (fh); \ 390 dummy.events = (ev); \ 391 (er) = write(event_pollfd, (void *) &dummy, \ 392 sizeof(dummy)) != sizeof(dummy) ? -1 : 0; \ 393 } while (0) 394 395 #define EVENT_REG_ADD_READ(e, f) EVENT_REG_FD_OP((e), (f), POLLIN) 396 #define EVENT_REG_ADD_WRITE(e, f) EVENT_REG_FD_OP((e), (f), POLLOUT) 397 #define EVENT_REG_ADD_TEXT "write /dev/poll" 398 399 #define EVENT_REG_DEL_BOTH(e, f) EVENT_REG_FD_OP((e), (f), POLLREMOVE) 400 #define EVENT_REG_DEL_TEXT "write /dev/poll" 401 402 /* 403 * Macros to retrieve event buffers from the kernel; see event_loop(). 404 */ 405 typedef struct pollfd EVENT_BUFFER; 406 407 #define EVENT_BUFFER_READ(event_count, event_buf, buflen, delay) do { \ 408 struct dvpoll dvpoll; \ 409 dvpoll.dp_fds = (event_buf); \ 410 dvpoll.dp_nfds = (buflen); \ 411 dvpoll.dp_timeout = (delay) < 0 ? -1 : (delay) * 1000; \ 412 (event_count) = ioctl(event_pollfd, DP_POLL, &dvpoll); \ 413 } while (0) 414 #define EVENT_BUFFER_READ_TEXT "ioctl DP_POLL" 415 416 /* 417 * Macros to process event buffers from the kernel; see event_loop(). 418 */ 419 #define EVENT_GET_FD(bp) ((bp)->fd) 420 #define EVENT_GET_TYPE(bp) ((bp)->revents) 421 #define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) & POLLIN) 422 #define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) & POLLOUT) 423 424 #endif 425 426 /* 427 * Linux epoll supports no system call to find out what descriptors are 428 * registered in the kernel-based filter. To implement our own sanity checks 429 * we maintain our own descriptor bitmask. 430 * 431 * Linux epoll does support application context pointers. Unfortunately, 432 * changing that information would cost a system call, and some of the 433 * competitors don't support application context. To keep the implementation 434 * simple we maintain our own table with call-back information. 435 * 436 * Linux epoll silently unregisters a descriptor from its filter when the 437 * descriptor is closed, so our information could get out of sync with the 438 * kernel. But that will never happen, because we have to meticulously 439 * unregister a file descriptor before it is closed, to avoid errors on 440 * systems that are built with EVENTS_STYLE == EVENTS_STYLE_SELECT. 441 */ 442 #if (EVENTS_STYLE == EVENTS_STYLE_EPOLL) 443 #include <sys/epoll.h> 444 445 /* 446 * Macros to initialize the kernel-based filter; see event_init(). 447 */ 448 static int event_epollfd; /* epoll handle */ 449 450 #define EVENT_REG_INIT_HANDLE(er, n) do { \ 451 er = event_epollfd = epoll_create(n); \ 452 if (event_epollfd >= 0) close_on_exec(event_epollfd, CLOSE_ON_EXEC); \ 453 } while (0) 454 #define EVENT_REG_INIT_TEXT "epoll_create" 455 456 #define EVENT_REG_FORK_HANDLE(er, n) do { \ 457 (void) close(event_epollfd); \ 458 EVENT_REG_INIT_HANDLE(er, (n)); \ 459 } while (0) 460 461 /* 462 * Macros to update the kernel-based filter; see event_enable_read(), 463 * event_enable_write() and event_disable_readwrite(). 464 */ 465 #define EVENT_REG_FD_OP(er, fh, ev, op) do { \ 466 struct epoll_event dummy; \ 467 dummy.events = (ev); \ 468 dummy.data.fd = (fh); \ 469 (er) = epoll_ctl(event_epollfd, (op), (fh), &dummy); \ 470 } while (0) 471 472 #define EVENT_REG_ADD_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EPOLL_CTL_ADD) 473 #define EVENT_REG_ADD_READ(e, f) EVENT_REG_ADD_OP((e), (f), EPOLLIN) 474 #define EVENT_REG_ADD_WRITE(e, f) EVENT_REG_ADD_OP((e), (f), EPOLLOUT) 475 #define EVENT_REG_ADD_TEXT "epoll_ctl EPOLL_CTL_ADD" 476 477 #define EVENT_REG_DEL_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EPOLL_CTL_DEL) 478 #define EVENT_REG_DEL_READ(e, f) EVENT_REG_DEL_OP((e), (f), EPOLLIN) 479 #define EVENT_REG_DEL_WRITE(e, f) EVENT_REG_DEL_OP((e), (f), EPOLLOUT) 480 #define EVENT_REG_DEL_TEXT "epoll_ctl EPOLL_CTL_DEL" 481 482 /* 483 * Macros to retrieve event buffers from the kernel; see event_loop(). 484 */ 485 typedef struct epoll_event EVENT_BUFFER; 486 487 #define EVENT_BUFFER_READ(event_count, event_buf, buflen, delay) do { \ 488 (event_count) = epoll_wait(event_epollfd, (event_buf), (buflen), \ 489 (delay) < 0 ? -1 : (delay) * 1000); \ 490 } while (0) 491 #define EVENT_BUFFER_READ_TEXT "epoll_wait" 492 493 /* 494 * Macros to process event buffers from the kernel; see event_loop(). 495 */ 496 #define EVENT_GET_FD(bp) ((bp)->data.fd) 497 #define EVENT_GET_TYPE(bp) ((bp)->events) 498 #define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) & EPOLLIN) 499 #define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) & EPOLLOUT) 500 501 #endif 502 503 /* 504 * Timer events. Timer requests are kept sorted, in a circular list. We use 505 * the RING abstraction, so we get to use a couple ugly macros. 506 * 507 * When a call-back function adds a timer request, we label the request with 508 * the event_loop() call instance that invoked the call-back. We use this to 509 * prevent zero-delay timer requests from running in a tight loop and 510 * starving I/O events. 511 */ 512 typedef struct EVENT_TIMER EVENT_TIMER; 513 514 struct EVENT_TIMER { 515 time_t when; /* when event is wanted */ 516 EVENT_NOTIFY_TIME_FN callback; /* callback function */ 517 char *context; /* callback context */ 518 long loop_instance; /* event_loop() call instance */ 519 RING ring; /* linkage */ 520 }; 521 522 static RING event_timer_head; /* timer queue head */ 523 static long event_loop_instance; /* event_loop() call instance */ 524 525 #define RING_TO_TIMER(r) \ 526 ((EVENT_TIMER *) ((void *) (r) - offsetof(EVENT_TIMER, ring))) 527 528 #define FOREACH_QUEUE_ENTRY(entry, head) \ 529 for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry)) 530 531 #define FIRST_TIMER(head) \ 532 (ring_succ(head) != (head) ? RING_TO_TIMER(ring_succ(head)) : 0) 533 534 /* 535 * Other private data structures. 536 */ 537 static time_t event_present; /* cached time of day */ 538 539 #define EVENT_INIT_NEEDED() (event_present == 0) 540 541 /* event_init - set up tables and such */ 542 543 static void event_init(void) 544 { 545 EVENT_FDTABLE *fdp; 546 int err; 547 548 if (!EVENT_INIT_NEEDED()) 549 msg_panic("event_init: repeated call"); 550 551 /* 552 * Initialize the file descriptor masks and the call-back table. Where 553 * possible we extend these data structures on the fly. With select(2) 554 * based implementations we can only handle FD_SETSIZE open files. 555 */ 556 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 557 if ((event_fdlimit = open_limit(FD_SETSIZE)) < 0) 558 msg_fatal("unable to determine open file limit"); 559 #else 560 if ((event_fdlimit = open_limit(INT_MAX)) < 0) 561 msg_fatal("unable to determine open file limit"); 562 #endif 563 if (event_fdlimit < FD_SETSIZE / 2 && event_fdlimit < 256) 564 msg_warn("could allocate space for only %d open files", event_fdlimit); 565 event_fdslots = EVENT_ALLOC_INCR; 566 event_fdtable = (EVENT_FDTABLE *) 567 mymalloc(sizeof(EVENT_FDTABLE) * event_fdslots); 568 for (fdp = event_fdtable; fdp < event_fdtable + event_fdslots; fdp++) { 569 fdp->callback = 0; 570 fdp->context = 0; 571 } 572 573 /* 574 * Initialize the I/O event request masks. 575 */ 576 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 577 EVENT_MASK_ZERO(&event_rmask); 578 EVENT_MASK_ZERO(&event_wmask); 579 EVENT_MASK_ZERO(&event_xmask); 580 #else 581 EVENT_MASK_ALLOC(&event_rmask, event_fdslots); 582 EVENT_MASK_ALLOC(&event_wmask, event_fdslots); 583 EVENT_MASK_ALLOC(&event_xmask, event_fdslots); 584 585 /* 586 * Initialize the kernel-based filter. 587 */ 588 EVENT_REG_INIT_HANDLE(err, event_fdslots); 589 if (err < 0) 590 msg_fatal("%s: %m", EVENT_REG_INIT_TEXT); 591 #endif 592 593 /* 594 * Initialize timer stuff. 595 */ 596 ring_init(&event_timer_head); 597 (void) time(&event_present); 598 599 /* 600 * Avoid an infinite initialization loop. 601 */ 602 if (EVENT_INIT_NEEDED()) 603 msg_panic("event_init: unable to initialize"); 604 } 605 606 /* event_extend - make room for more descriptor slots */ 607 608 static void event_extend(int fd) 609 { 610 const char *myname = "event_extend"; 611 int old_slots = event_fdslots; 612 int new_slots = (event_fdslots > fd / 2 ? 613 2 * old_slots : fd + EVENT_ALLOC_INCR); 614 EVENT_FDTABLE *fdp; 615 616 #ifdef EVENT_REG_UPD_HANDLE 617 int err; 618 619 #endif 620 621 if (msg_verbose > 2) 622 msg_info("%s: fd %d", myname, fd); 623 event_fdtable = (EVENT_FDTABLE *) 624 myrealloc((void *) event_fdtable, sizeof(EVENT_FDTABLE) * new_slots); 625 event_fdslots = new_slots; 626 for (fdp = event_fdtable + old_slots; 627 fdp < event_fdtable + new_slots; fdp++) { 628 fdp->callback = 0; 629 fdp->context = 0; 630 } 631 632 /* 633 * Initialize the I/O event request masks. 634 */ 635 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 636 EVENT_MASK_REALLOC(&event_rmask, new_slots); 637 EVENT_MASK_REALLOC(&event_wmask, new_slots); 638 EVENT_MASK_REALLOC(&event_xmask, new_slots); 639 #endif 640 #ifdef EVENT_REG_UPD_HANDLE 641 EVENT_REG_UPD_HANDLE(err, new_slots); 642 if (err < 0) 643 msg_fatal("%s: %s: %m", myname, EVENT_REG_UPD_TEXT); 644 #endif 645 } 646 647 /* event_time - look up cached time of day */ 648 649 time_t event_time(void) 650 { 651 if (EVENT_INIT_NEEDED()) 652 event_init(); 653 654 return (event_present); 655 } 656 657 /* event_drain - loop until all pending events are done */ 658 659 void event_drain(int time_limit) 660 { 661 EVENT_MASK zero_mask; 662 time_t max_time; 663 664 if (EVENT_INIT_NEEDED()) 665 return; 666 667 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 668 EVENT_MASK_ZERO(&zero_mask); 669 #else 670 EVENT_MASK_ALLOC(&zero_mask, event_fdslots); 671 #endif 672 (void) time(&event_present); 673 max_time = event_present + time_limit; 674 while (event_present < max_time 675 && (event_timer_head.pred != &event_timer_head 676 || EVENT_MASK_CMP(&zero_mask, &event_xmask) != 0)) { 677 event_loop(1); 678 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 679 if (EVENT_MASK_BYTE_COUNT(&zero_mask) 680 != EVENT_MASK_BYTES_NEEDED(event_fdslots)) 681 EVENT_MASK_REALLOC(&zero_mask, event_fdslots); 682 #endif 683 } 684 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 685 EVENT_MASK_FREE(&zero_mask); 686 #endif 687 } 688 689 /* event_fork - resume event processing after fork() */ 690 691 void event_fork(void) 692 { 693 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 694 EVENT_FDTABLE *fdp; 695 int err; 696 int fd; 697 698 /* 699 * No event was ever registered, so there's nothing to be done. 700 */ 701 if (EVENT_INIT_NEEDED()) 702 return; 703 704 /* 705 * Close the existing filter handle and open a new kernel-based filter. 706 */ 707 EVENT_REG_FORK_HANDLE(err, event_fdslots); 708 if (err < 0) 709 msg_fatal("%s: %m", EVENT_REG_INIT_TEXT); 710 711 /* 712 * Populate the new kernel-based filter with events that were registered 713 * in the parent process. 714 */ 715 for (fd = 0; fd <= event_max_fd; fd++) { 716 if (EVENT_MASK_ISSET(fd, &event_wmask)) { 717 EVENT_MASK_CLR(fd, &event_wmask); 718 fdp = event_fdtable + fd; 719 event_enable_write(fd, fdp->callback, fdp->context); 720 } else if (EVENT_MASK_ISSET(fd, &event_rmask)) { 721 EVENT_MASK_CLR(fd, &event_rmask); 722 fdp = event_fdtable + fd; 723 event_enable_read(fd, fdp->callback, fdp->context); 724 } 725 } 726 #endif 727 } 728 729 /* event_enable_read - enable read events */ 730 731 void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context) 732 { 733 const char *myname = "event_enable_read"; 734 EVENT_FDTABLE *fdp; 735 int err; 736 737 if (EVENT_INIT_NEEDED()) 738 event_init(); 739 740 /* 741 * Sanity checks. 742 */ 743 if (fd < 0 || fd >= event_fdlimit) 744 msg_panic("%s: bad file descriptor: %d", myname, fd); 745 746 if (msg_verbose > 2) 747 msg_info("%s: fd %d", myname, fd); 748 749 if (fd >= event_fdslots) 750 event_extend(fd); 751 752 /* 753 * Disallow mixed (i.e. read and write) requests on the same descriptor. 754 */ 755 if (EVENT_MASK_ISSET(fd, &event_wmask)) 756 msg_panic("%s: fd %d: read/write I/O request", myname, fd); 757 758 /* 759 * Postfix 2.4 allows multiple event_enable_read() calls on the same 760 * descriptor without requiring event_disable_readwrite() calls between 761 * them. With kernel-based filters (kqueue, /dev/poll, epoll) it's 762 * wasteful to make system calls when we change only application 763 * call-back information. It has a noticeable effect on smtp-source 764 * performance. 765 */ 766 if (EVENT_MASK_ISSET(fd, &event_rmask) == 0) { 767 EVENT_MASK_SET(fd, &event_xmask); 768 EVENT_MASK_SET(fd, &event_rmask); 769 if (event_max_fd < fd) 770 event_max_fd = fd; 771 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 772 EVENT_REG_ADD_READ(err, fd); 773 if (err < 0) 774 msg_fatal("%s: %s: %m", myname, EVENT_REG_ADD_TEXT); 775 #endif 776 } 777 fdp = event_fdtable + fd; 778 if (fdp->callback != callback || fdp->context != context) { 779 fdp->callback = callback; 780 fdp->context = context; 781 } 782 } 783 784 /* event_enable_write - enable write events */ 785 786 void event_enable_write(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context) 787 { 788 const char *myname = "event_enable_write"; 789 EVENT_FDTABLE *fdp; 790 int err; 791 792 if (EVENT_INIT_NEEDED()) 793 event_init(); 794 795 /* 796 * Sanity checks. 797 */ 798 if (fd < 0 || fd >= event_fdlimit) 799 msg_panic("%s: bad file descriptor: %d", myname, fd); 800 801 if (msg_verbose > 2) 802 msg_info("%s: fd %d", myname, fd); 803 804 if (fd >= event_fdslots) 805 event_extend(fd); 806 807 /* 808 * Disallow mixed (i.e. read and write) requests on the same descriptor. 809 */ 810 if (EVENT_MASK_ISSET(fd, &event_rmask)) 811 msg_panic("%s: fd %d: read/write I/O request", myname, fd); 812 813 /* 814 * Postfix 2.4 allows multiple event_enable_write() calls on the same 815 * descriptor without requiring event_disable_readwrite() calls between 816 * them. With kernel-based filters (kqueue, /dev/poll, epoll) it's 817 * incredibly wasteful to make unregister and register system calls when 818 * we change only application call-back information. It has a noticeable 819 * effect on smtp-source performance. 820 */ 821 if (EVENT_MASK_ISSET(fd, &event_wmask) == 0) { 822 EVENT_MASK_SET(fd, &event_xmask); 823 EVENT_MASK_SET(fd, &event_wmask); 824 if (event_max_fd < fd) 825 event_max_fd = fd; 826 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 827 EVENT_REG_ADD_WRITE(err, fd); 828 if (err < 0) 829 msg_fatal("%s: %s: %m", myname, EVENT_REG_ADD_TEXT); 830 #endif 831 } 832 fdp = event_fdtable + fd; 833 if (fdp->callback != callback || fdp->context != context) { 834 fdp->callback = callback; 835 fdp->context = context; 836 } 837 } 838 839 /* event_disable_readwrite - disable request for read or write events */ 840 841 void event_disable_readwrite(int fd) 842 { 843 const char *myname = "event_disable_readwrite"; 844 EVENT_FDTABLE *fdp; 845 int err; 846 847 if (EVENT_INIT_NEEDED()) 848 event_init(); 849 850 /* 851 * Sanity checks. 852 */ 853 if (fd < 0 || fd >= event_fdlimit) 854 msg_panic("%s: bad file descriptor: %d", myname, fd); 855 856 if (msg_verbose > 2) 857 msg_info("%s: fd %d", myname, fd); 858 859 /* 860 * Don't complain when there is nothing to cancel. The request may have 861 * been canceled from another thread. 862 */ 863 if (fd >= event_fdslots) 864 return; 865 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) 866 #ifdef EVENT_REG_DEL_BOTH 867 /* XXX Can't seem to disable READ and WRITE events selectively. */ 868 if (EVENT_MASK_ISSET(fd, &event_rmask) 869 || EVENT_MASK_ISSET(fd, &event_wmask)) { 870 EVENT_REG_DEL_BOTH(err, fd); 871 if (err < 0) 872 msg_fatal("%s: %s: %m", myname, EVENT_REG_DEL_TEXT); 873 } 874 #else 875 if (EVENT_MASK_ISSET(fd, &event_rmask)) { 876 EVENT_REG_DEL_READ(err, fd); 877 if (err < 0) 878 msg_fatal("%s: %s: %m", myname, EVENT_REG_DEL_TEXT); 879 } else if (EVENT_MASK_ISSET(fd, &event_wmask)) { 880 EVENT_REG_DEL_WRITE(err, fd); 881 if (err < 0) 882 msg_fatal("%s: %s: %m", myname, EVENT_REG_DEL_TEXT); 883 } 884 #endif /* EVENT_REG_DEL_BOTH */ 885 #endif /* != EVENTS_STYLE_SELECT */ 886 EVENT_MASK_CLR(fd, &event_xmask); 887 EVENT_MASK_CLR(fd, &event_rmask); 888 EVENT_MASK_CLR(fd, &event_wmask); 889 fdp = event_fdtable + fd; 890 fdp->callback = 0; 891 fdp->context = 0; 892 } 893 894 /* event_request_timer - (re)set timer */ 895 896 time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay) 897 { 898 const char *myname = "event_request_timer"; 899 RING *ring; 900 EVENT_TIMER *timer; 901 902 if (EVENT_INIT_NEEDED()) 903 event_init(); 904 905 /* 906 * Sanity checks. 907 */ 908 if (delay < 0) 909 msg_panic("%s: invalid delay: %d", myname, delay); 910 911 /* 912 * Make sure we schedule this event at the right time. 913 */ 914 time(&event_present); 915 916 /* 917 * See if they are resetting an existing timer request. If so, take the 918 * request away from the timer queue so that it can be inserted at the 919 * right place. 920 */ 921 FOREACH_QUEUE_ENTRY(ring, &event_timer_head) { 922 timer = RING_TO_TIMER(ring); 923 if (timer->callback == callback && timer->context == context) { 924 timer->when = event_present + delay; 925 timer->loop_instance = event_loop_instance; 926 ring_detach(ring); 927 if (msg_verbose > 2) 928 msg_info("%s: reset 0x%lx 0x%lx %d", myname, 929 (long) callback, (long) context, delay); 930 break; 931 } 932 } 933 934 /* 935 * If not found, schedule a new timer request. 936 */ 937 if (ring == &event_timer_head) { 938 timer = (EVENT_TIMER *) mymalloc(sizeof(EVENT_TIMER)); 939 timer->when = event_present + delay; 940 timer->callback = callback; 941 timer->context = context; 942 timer->loop_instance = event_loop_instance; 943 if (msg_verbose > 2) 944 msg_info("%s: set 0x%lx 0x%lx %d", myname, 945 (long) callback, (long) context, delay); 946 } 947 948 /* 949 * Timer requests are kept sorted to reduce lookup overhead in the event 950 * loop. 951 * 952 * XXX Append the new request after existing requests for the same time 953 * slot. The event_loop() routine depends on this to avoid starving I/O 954 * events when a call-back function schedules a zero-delay timer request. 955 */ 956 FOREACH_QUEUE_ENTRY(ring, &event_timer_head) { 957 if (timer->when < RING_TO_TIMER(ring)->when) 958 break; 959 } 960 ring_prepend(ring, &timer->ring); 961 962 return (timer->when); 963 } 964 965 /* event_cancel_timer - cancel timer */ 966 967 int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context) 968 { 969 const char *myname = "event_cancel_timer"; 970 RING *ring; 971 EVENT_TIMER *timer; 972 int time_left = -1; 973 974 if (EVENT_INIT_NEEDED()) 975 event_init(); 976 977 /* 978 * See if they are canceling an existing timer request. Do not complain 979 * when the request is not found. It might have been canceled from some 980 * other thread. 981 */ 982 FOREACH_QUEUE_ENTRY(ring, &event_timer_head) { 983 timer = RING_TO_TIMER(ring); 984 if (timer->callback == callback && timer->context == context) { 985 if ((time_left = timer->when - event_present) < 0) 986 time_left = 0; 987 ring_detach(ring); 988 myfree((void *) timer); 989 break; 990 } 991 } 992 if (msg_verbose > 2) 993 msg_info("%s: 0x%lx 0x%lx %d", myname, 994 (long) callback, (long) context, time_left); 995 return (time_left); 996 } 997 998 /* event_loop - wait for the next event */ 999 1000 void event_loop(int delay) 1001 { 1002 const char *myname = "event_loop"; 1003 static int nested; 1004 1005 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 1006 fd_set rmask; 1007 fd_set wmask; 1008 fd_set xmask; 1009 struct timeval tv; 1010 struct timeval *tvp; 1011 int new_max_fd; 1012 1013 #else 1014 EVENT_BUFFER event_buf[100]; 1015 EVENT_BUFFER *bp; 1016 1017 #endif 1018 int event_count; 1019 EVENT_TIMER *timer; 1020 int fd; 1021 EVENT_FDTABLE *fdp; 1022 int select_delay; 1023 1024 if (EVENT_INIT_NEEDED()) 1025 event_init(); 1026 1027 /* 1028 * XXX Also print the select() masks? 1029 */ 1030 if (msg_verbose > 2) { 1031 RING *ring; 1032 1033 FOREACH_QUEUE_ENTRY(ring, &event_timer_head) { 1034 timer = RING_TO_TIMER(ring); 1035 msg_info("%s: time left %3d for 0x%lx 0x%lx", myname, 1036 (int) (timer->when - event_present), 1037 (long) timer->callback, (long) timer->context); 1038 } 1039 } 1040 1041 /* 1042 * Find out when the next timer would go off. Timer requests are sorted. 1043 * If any timer is scheduled, adjust the delay appropriately. 1044 */ 1045 if ((timer = FIRST_TIMER(&event_timer_head)) != 0) { 1046 event_present = time((time_t *) 0); 1047 if ((select_delay = timer->when - event_present) < 0) { 1048 select_delay = 0; 1049 } else if (delay >= 0 && select_delay > delay) { 1050 select_delay = delay; 1051 } 1052 } else { 1053 select_delay = delay; 1054 } 1055 if (msg_verbose > 2) 1056 msg_info("event_loop: select_delay %d", select_delay); 1057 1058 /* 1059 * Negative delay means: wait until something happens. Zero delay means: 1060 * poll. Positive delay means: wait at most this long. 1061 */ 1062 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 1063 if (select_delay < 0) { 1064 tvp = 0; 1065 } else { 1066 tvp = &tv; 1067 tv.tv_usec = 0; 1068 tv.tv_sec = select_delay; 1069 } 1070 1071 /* 1072 * Pause until the next event happens. When select() has a problem, don't 1073 * go into a tight loop. Allow select() to be interrupted due to the 1074 * arrival of a signal. 1075 */ 1076 rmask = event_rmask; 1077 wmask = event_wmask; 1078 xmask = event_xmask; 1079 1080 event_count = select(event_max_fd + 1, &rmask, &wmask, &xmask, tvp); 1081 if (event_count < 0) { 1082 if (errno != EINTR) 1083 msg_fatal("event_loop: select: %m"); 1084 return; 1085 } 1086 #else 1087 EVENT_BUFFER_READ(event_count, event_buf, 1088 sizeof(event_buf) / sizeof(event_buf[0]), 1089 select_delay); 1090 if (event_count < 0) { 1091 if (errno != EINTR) 1092 msg_fatal("event_loop: " EVENT_BUFFER_READ_TEXT ": %m"); 1093 return; 1094 } 1095 #endif 1096 1097 /* 1098 * Before entering the application call-back routines, make sure we 1099 * aren't being called from a call-back routine. Doing so would make us 1100 * vulnerable to all kinds of race conditions. 1101 */ 1102 if (nested++ > 0) 1103 msg_panic("event_loop: recursive call"); 1104 1105 /* 1106 * Deliver timer events. Allow the application to add/delete timer queue 1107 * requests while it is being called back. Requests are sorted: we keep 1108 * running over the timer request queue from the start, and stop when we 1109 * reach the future or the list end. We also stop when we reach a timer 1110 * request that was added by a call-back that was invoked from this 1111 * event_loop() call instance, for reasons that are explained below. 1112 * 1113 * To avoid dangling pointer problems 1) we must remove a request from the 1114 * timer queue before delivering its event to the application and 2) we 1115 * must look up the next timer request *after* calling the application. 1116 * The latter complicates the handling of zero-delay timer requests that 1117 * are added by event_loop() call-back functions. 1118 * 1119 * XXX When a timer event call-back function adds a new timer request, 1120 * event_request_timer() labels the request with the event_loop() call 1121 * instance that invoked the timer event call-back. We use this instance 1122 * label here to prevent zero-delay timer requests from running in a 1123 * tight loop and starving I/O events. To make this solution work, 1124 * event_request_timer() appends a new request after existing requests 1125 * for the same time slot. 1126 */ 1127 event_present = time((time_t *) 0); 1128 event_loop_instance += 1; 1129 1130 while ((timer = FIRST_TIMER(&event_timer_head)) != 0) { 1131 if (timer->when > event_present) 1132 break; 1133 if (timer->loop_instance == event_loop_instance) 1134 break; 1135 ring_detach(&timer->ring); /* first this */ 1136 if (msg_verbose > 2) 1137 msg_info("%s: timer 0x%lx 0x%lx", myname, 1138 (long) timer->callback, (long) timer->context); 1139 timer->callback(EVENT_TIME, timer->context); /* then this */ 1140 myfree((void *) timer); 1141 } 1142 1143 /* 1144 * Deliver I/O events. Allow the application to cancel event requests 1145 * while it is being called back. To this end, we keep an eye on the 1146 * contents of event_xmask, so that we deliver only events that are still 1147 * wanted. We do not change the event request masks. It is up to the 1148 * application to determine when a read or write is complete. 1149 */ 1150 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT) 1151 if (event_count > 0) { 1152 for (new_max_fd = 0, fd = 0; fd <= event_max_fd; fd++) { 1153 if (FD_ISSET(fd, &event_xmask)) { 1154 new_max_fd = fd; 1155 /* In case event_fdtable is updated. */ 1156 fdp = event_fdtable + fd; 1157 if (FD_ISSET(fd, &xmask)) { 1158 if (msg_verbose > 2) 1159 msg_info("%s: exception fd=%d act=0x%lx 0x%lx", myname, 1160 fd, (long) fdp->callback, (long) fdp->context); 1161 fdp->callback(EVENT_XCPT, fdp->context); 1162 } else if (FD_ISSET(fd, &wmask)) { 1163 if (msg_verbose > 2) 1164 msg_info("%s: write fd=%d act=0x%lx 0x%lx", myname, 1165 fd, (long) fdp->callback, (long) fdp->context); 1166 fdp->callback(EVENT_WRITE, fdp->context); 1167 } else if (FD_ISSET(fd, &rmask)) { 1168 if (msg_verbose > 2) 1169 msg_info("%s: read fd=%d act=0x%lx 0x%lx", myname, 1170 fd, (long) fdp->callback, (long) fdp->context); 1171 fdp->callback(EVENT_READ, fdp->context); 1172 } 1173 } 1174 } 1175 event_max_fd = new_max_fd; 1176 } 1177 #else 1178 for (bp = event_buf; bp < event_buf + event_count; bp++) { 1179 fd = EVENT_GET_FD(bp); 1180 if (fd < 0 || fd > event_max_fd) 1181 msg_panic("%s: bad file descriptor: %d", myname, fd); 1182 if (EVENT_MASK_ISSET(fd, &event_xmask)) { 1183 fdp = event_fdtable + fd; 1184 if (EVENT_TEST_READ(bp)) { 1185 if (msg_verbose > 2) 1186 msg_info("%s: read fd=%d act=0x%lx 0x%lx", myname, 1187 fd, (long) fdp->callback, (long) fdp->context); 1188 fdp->callback(EVENT_READ, fdp->context); 1189 } else if (EVENT_TEST_WRITE(bp)) { 1190 if (msg_verbose > 2) 1191 msg_info("%s: write fd=%d act=0x%lx 0x%lx", myname, 1192 fd, (long) fdp->callback, 1193 (long) fdp->context); 1194 fdp->callback(EVENT_WRITE, fdp->context); 1195 } else { 1196 if (msg_verbose > 2) 1197 msg_info("%s: other fd=%d act=0x%lx 0x%lx", myname, 1198 fd, (long) fdp->callback, (long) fdp->context); 1199 fdp->callback(EVENT_XCPT, fdp->context); 1200 } 1201 } 1202 } 1203 #endif 1204 nested--; 1205 } 1206 1207 #ifdef TEST 1208 1209 /* 1210 * Proof-of-concept test program for the event manager. Schedule a series of 1211 * events at one-second intervals and let them happen, while echoing any 1212 * lines read from stdin. 1213 */ 1214 #include <stdio.h> 1215 #include <ctype.h> 1216 #include <stdlib.h> 1217 1218 /* timer_event - display event */ 1219 1220 static void timer_event(int unused_event, void *context) 1221 { 1222 printf("%ld: %s\n", (long) event_present, context); 1223 fflush(stdout); 1224 } 1225 1226 /* echo - echo text received on stdin */ 1227 1228 static void echo(int unused_event, void *unused_context) 1229 { 1230 char buf[BUFSIZ]; 1231 1232 if (fgets(buf, sizeof(buf), stdin) == 0) 1233 exit(0); 1234 printf("Result: %s", buf); 1235 } 1236 1237 /* request - request a bunch of timer events */ 1238 1239 static void request(int unused_event, void *unused_context) 1240 { 1241 event_request_timer(timer_event, "3 first", 3); 1242 event_request_timer(timer_event, "3 second", 3); 1243 event_request_timer(timer_event, "4 first", 4); 1244 event_request_timer(timer_event, "4 second", 4); 1245 event_request_timer(timer_event, "2 first", 2); 1246 event_request_timer(timer_event, "2 second", 2); 1247 event_request_timer(timer_event, "1 first", 1); 1248 event_request_timer(timer_event, "1 second", 1); 1249 event_request_timer(timer_event, "0 first", 0); 1250 event_request_timer(timer_event, "0 second", 0); 1251 } 1252 1253 int main(int argc, void **argv) 1254 { 1255 if (argv[1]) 1256 msg_verbose = atoi(argv[1]); 1257 event_request_timer(request, (void *) 0, 0); 1258 event_enable_read(fileno(stdin), echo, (void *) 0); 1259 event_drain(10); 1260 exit(0); 1261 } 1262 1263 #endif 1264