142 #include <sys/time.h>
150 #ifdef USE_SYS_SELECT_H
151 #include <sys/select.h>
162 #if !defined(EVENTS_STYLE)
163 #error "must define EVENTS_STYLE"
173 #define EVENT_ALLOC_INCR 10
175 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
178 #define EVENT_MASK_BYTE_COUNT(mask) sizeof(*(mask))
179 #define EVENT_MASK_ZERO(mask) FD_ZERO(mask)
180 #define EVENT_MASK_SET(fd, mask) FD_SET((fd), (mask))
181 #define EVENT_MASK_ISSET(fd, mask) FD_ISSET((fd), (mask))
182 #define EVENT_MASK_CLR(fd, mask) FD_CLR((fd), (mask))
183 #define EVENT_MASK_CMP(m1, m2) memcmp((m1), (m2), EVENT_MASK_BYTE_COUNT(m1))
196 #define EVENT_MASK_NBBY (8)
197 #define EVENT_MASK_FD_BYTE(fd, mask) \
198 (((unsigned char *) (mask)->data)[(fd) / EVENT_MASK_NBBY])
199 #define EVENT_MASK_FD_BIT(fd) (1 << ((fd) % EVENT_MASK_NBBY))
200 #define EVENT_MASK_BYTES_NEEDED(len) \
201 (((len) + (EVENT_MASK_NBBY -1)) / EVENT_MASK_NBBY)
202 #define EVENT_MASK_BYTE_COUNT(mask) ((mask)->data_len)
205 #define EVENT_MASK_ALLOC(mask, bit_len) do { \
206 size_t _byte_len = EVENT_MASK_BYTES_NEEDED(bit_len); \
207 (mask)->data = mymalloc(_byte_len); \
208 memset((mask)->data, 0, _byte_len); \
209 (mask)->data_len = _byte_len; \
211 #define EVENT_MASK_REALLOC(mask, bit_len) do { \
212 size_t _byte_len = EVENT_MASK_BYTES_NEEDED(bit_len); \
213 size_t _old_len = (mask)->data_len; \
214 (mask)->data = myrealloc((mask)->data, _byte_len); \
215 if (_byte_len > _old_len) \
216 memset((mask)->data + _old_len, 0, _byte_len - _old_len); \
217 (mask)->data_len = _byte_len; \
219 #define EVENT_MASK_FREE(mask) myfree((mask)->data)
222 #define EVENT_MASK_ZERO(mask) \
223 memset((mask)->data, 0, (mask)->data_len)
224 #define EVENT_MASK_SET(fd, mask) \
225 (EVENT_MASK_FD_BYTE((fd), (mask)) |= EVENT_MASK_FD_BIT(fd))
226 #define EVENT_MASK_ISSET(fd, mask) \
227 (EVENT_MASK_FD_BYTE((fd), (mask)) & EVENT_MASK_FD_BIT(fd))
228 #define EVENT_MASK_CLR(fd, mask) \
229 (EVENT_MASK_FD_BYTE((fd), (mask)) &= ~EVENT_MASK_FD_BIT(fd))
230 #define EVENT_MASK_CMP(m1, m2) \
231 memcmp((m1)->data, (m2)->data, EVENT_MASK_BYTE_COUNT(m1))
246 static int event_fdlimit;
248 static int event_fdslots;
249 static int event_max_fd = -1;
267 #if (EVENTS_STYLE == EVENTS_STYLE_KQUEUE)
268 #include <sys/event.h>
274 #define EV_SET(kp, id, fi, fl, ffl, da, ud) do { \
275 (kp)->ident = (id); \
276 (kp)->filter = (fi); \
277 (kp)->flags = (fl); \
278 (kp)->fflags = (ffl); \
280 (kp)->udata = (ud); \
289 #define EVENT_REG_INIT_HANDLE(er, n) do { \
290 er = event_kq = kqueue(); \
292 #define EVENT_REG_INIT_TEXT "kqueue"
294 #define EVENT_REG_FORK_HANDLE(er, n) do { \
295 (void) close(event_kq); \
296 EVENT_REG_INIT_HANDLE(er, (n)); \
303 #define EVENT_REG_FD_OP(er, fh, ev, op) do { \
304 struct kevent dummy; \
305 EV_SET(&dummy, (fh), (ev), (op), 0, 0, 0); \
306 (er) = kevent(event_kq, &dummy, 1, 0, 0, 0); \
309 #define EVENT_REG_ADD_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EV_ADD)
310 #define EVENT_REG_ADD_READ(e, f) EVENT_REG_ADD_OP((e), (f), EVFILT_READ)
311 #define EVENT_REG_ADD_WRITE(e, f) EVENT_REG_ADD_OP((e), (f), EVFILT_WRITE)
312 #define EVENT_REG_ADD_TEXT "kevent EV_ADD"
314 #define EVENT_REG_DEL_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EV_DELETE)
315 #define EVENT_REG_DEL_READ(e, f) EVENT_REG_DEL_OP((e), (f), EVFILT_READ)
316 #define EVENT_REG_DEL_WRITE(e, f) EVENT_REG_DEL_OP((e), (f), EVFILT_WRITE)
317 #define EVENT_REG_DEL_TEXT "kevent EV_DELETE"
322 typedef struct kevent EVENT_BUFFER;
324 #define EVENT_BUFFER_READ(event_count, event_buf, buflen, delay) do { \
325 struct timespec ts; \
326 struct timespec *tsp; \
332 ts.tv_sec = (delay); \
334 (event_count) = kevent(event_kq, (struct kevent *) 0, 0, (event_buf), \
337 #define EVENT_BUFFER_READ_TEXT "kevent"
342 #define EVENT_GET_FD(bp) ((bp)->ident)
343 #define EVENT_GET_TYPE(bp) ((bp)->filter)
344 #define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) == EVFILT_READ)
345 #define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) == EVFILT_WRITE)
361 #if (EVENTS_STYLE == EVENTS_STYLE_DEVPOLL)
362 #include <sys/devpoll.h>
368 static int event_pollfd;
370 #define EVENT_REG_INIT_HANDLE(er, n) do { \
371 er = event_pollfd = open("/dev/poll", O_RDWR); \
372 if (event_pollfd >= 0) close_on_exec(event_pollfd, CLOSE_ON_EXEC); \
374 #define EVENT_REG_INIT_TEXT "open /dev/poll"
376 #define EVENT_REG_FORK_HANDLE(er, n) do { \
377 (void) close(event_pollfd); \
378 EVENT_REG_INIT_HANDLE(er, (n)); \
385 #define EVENT_REG_FD_OP(er, fh, ev) do { \
386 struct pollfd dummy; \
388 dummy.events = (ev); \
389 (er) = write(event_pollfd, (void *) &dummy, \
390 sizeof(dummy)) != sizeof(dummy) ? -1 : 0; \
393 #define EVENT_REG_ADD_READ(e, f) EVENT_REG_FD_OP((e), (f), POLLIN)
394 #define EVENT_REG_ADD_WRITE(e, f) EVENT_REG_FD_OP((e), (f), POLLOUT)
395 #define EVENT_REG_ADD_TEXT "write /dev/poll"
397 #define EVENT_REG_DEL_BOTH(e, f) EVENT_REG_FD_OP((e), (f), POLLREMOVE)
398 #define EVENT_REG_DEL_TEXT "write /dev/poll"
403 typedef struct pollfd EVENT_BUFFER;
405 #define EVENT_BUFFER_READ(event_count, event_buf, buflen, delay) do { \
406 struct dvpoll dvpoll; \
407 dvpoll.dp_fds = (event_buf); \
408 dvpoll.dp_nfds = (buflen); \
409 dvpoll.dp_timeout = (delay) < 0 ? -1 : (delay) * 1000; \
410 (event_count) = ioctl(event_pollfd, DP_POLL, &dvpoll); \
412 #define EVENT_BUFFER_READ_TEXT "ioctl DP_POLL"
417 #define EVENT_GET_FD(bp) ((bp)->fd)
418 #define EVENT_GET_TYPE(bp) ((bp)->revents)
419 #define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) & POLLIN)
420 #define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) & POLLOUT)
440 #if (EVENTS_STYLE == EVENTS_STYLE_EPOLL)
441 #include <sys/epoll.h>
446 static int event_epollfd;
448 #define EVENT_REG_INIT_HANDLE(er, n) do { \
449 er = event_epollfd = epoll_create(n); \
450 if (event_epollfd >= 0) close_on_exec(event_epollfd, CLOSE_ON_EXEC); \
452 #define EVENT_REG_INIT_TEXT "epoll_create"
454 #define EVENT_REG_FORK_HANDLE(er, n) do { \
455 (void) close(event_epollfd); \
456 EVENT_REG_INIT_HANDLE(er, (n)); \
463 #define EVENT_REG_FD_OP(er, fh, ev, op) do { \
464 struct epoll_event dummy; \
465 dummy.events = (ev); \
466 dummy.data.fd = (fh); \
467 (er) = epoll_ctl(event_epollfd, (op), (fh), &dummy); \
470 #define EVENT_REG_ADD_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EPOLL_CTL_ADD)
471 #define EVENT_REG_ADD_READ(e, f) EVENT_REG_ADD_OP((e), (f), EPOLLIN)
472 #define EVENT_REG_ADD_WRITE(e, f) EVENT_REG_ADD_OP((e), (f), EPOLLOUT)
473 #define EVENT_REG_ADD_TEXT "epoll_ctl EPOLL_CTL_ADD"
475 #define EVENT_REG_DEL_OP(e, f, ev) EVENT_REG_FD_OP((e), (f), (ev), EPOLL_CTL_DEL)
476 #define EVENT_REG_DEL_READ(e, f) EVENT_REG_DEL_OP((e), (f), EPOLLIN)
477 #define EVENT_REG_DEL_WRITE(e, f) EVENT_REG_DEL_OP((e), (f), EPOLLOUT)
478 #define EVENT_REG_DEL_TEXT "epoll_ctl EPOLL_CTL_DEL"
483 typedef struct epoll_event EVENT_BUFFER;
485 #define EVENT_BUFFER_READ(event_count, event_buf, buflen, delay) do { \
486 (event_count) = epoll_wait(event_epollfd, (event_buf), (buflen), \
487 (delay) < 0 ? -1 : (delay) * 1000); \
489 #define EVENT_BUFFER_READ_TEXT "epoll_wait"
494 #define EVENT_GET_FD(bp) ((bp)->data.fd)
495 #define EVENT_GET_TYPE(bp) ((bp)->events)
496 #define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) & EPOLLIN)
497 #define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) & EPOLLOUT)
520 static RING event_timer_head;
521 static long event_loop_instance;
523 #define RING_TO_TIMER(r) \
524 ((EVENT_TIMER *) ((void *) (r) - offsetof(EVENT_TIMER, ring)))
526 #define FOREACH_QUEUE_ENTRY(entry, head) \
527 for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry))
529 #define FIRST_TIMER(head) \
530 (ring_succ(head) != (head) ? RING_TO_TIMER(ring_succ(head)) : 0)
535 static time_t event_present;
537 #define EVENT_INIT_NEEDED() (event_present == 0)
541 static void event_init(
void)
554 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
555 if ((event_fdlimit =
open_limit(FD_SETSIZE)) < 0)
556 msg_fatal(
"unable to determine open file limit");
558 if ((event_fdlimit =
open_limit(INT_MAX)) < 0)
559 msg_fatal(
"unable to determine open file limit");
561 if (event_fdlimit < FD_SETSIZE / 2 && event_fdlimit < 256)
562 msg_warn(
"could allocate space for only %d open files", event_fdlimit);
566 for (fdp = event_fdtable; fdp < event_fdtable + event_fdslots; fdp++) {
574 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
579 EVENT_MASK_ALLOC(&event_rmask, event_fdslots);
580 EVENT_MASK_ALLOC(&event_wmask, event_fdslots);
581 EVENT_MASK_ALLOC(&event_xmask, event_fdslots);
586 EVENT_REG_INIT_HANDLE(err, event_fdslots);
588 msg_fatal(
"%s: %m", EVENT_REG_INIT_TEXT);
595 (void) time(&event_present);
601 msg_panic(
"event_init: unable to initialize");
606 static void event_extend(
int fd)
608 const char *myname =
"event_extend";
609 int old_slots = event_fdslots;
610 int new_slots = (event_fdslots > fd / 2 ?
614 #ifdef EVENT_REG_UPD_HANDLE
623 event_fdslots = new_slots;
624 for (fdp = event_fdtable + old_slots;
625 fdp < event_fdtable + new_slots; fdp++) {
633 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
634 EVENT_MASK_REALLOC(&event_rmask, new_slots);
635 EVENT_MASK_REALLOC(&event_wmask, new_slots);
636 EVENT_MASK_REALLOC(&event_xmask, new_slots);
638 #ifdef EVENT_REG_UPD_HANDLE
639 EVENT_REG_UPD_HANDLE(err, new_slots);
641 msg_fatal(
"%s: %s: %m", myname, EVENT_REG_UPD_TEXT);
652 return (event_present);
665 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
668 EVENT_MASK_ALLOC(&zero_mask, event_fdslots);
670 (void) time(&event_present);
671 max_time = event_present + time_limit;
672 while (event_present < max_time
673 && (event_timer_head.
pred != &event_timer_head
676 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
678 != EVENT_MASK_BYTES_NEEDED(event_fdslots))
679 EVENT_MASK_REALLOC(&zero_mask, event_fdslots);
682 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
683 EVENT_MASK_FREE(&zero_mask);
691 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
705 EVENT_REG_FORK_HANDLE(err, event_fdslots);
707 msg_fatal(
"%s: %m", EVENT_REG_INIT_TEXT);
713 for (fd = 0; fd <= event_max_fd; fd++) {
716 fdp = event_fdtable + fd;
720 fdp = event_fdtable + fd;
731 const char *myname =
"event_enable_read";
741 if (fd < 0 || fd >= event_fdlimit)
742 msg_panic(
"%s: bad file descriptor: %d", myname, fd);
747 if (fd >= event_fdslots)
754 msg_panic(
"%s: fd %d: read/write I/O request", myname, fd);
767 if (event_max_fd < fd)
769 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
770 EVENT_REG_ADD_READ(err, fd);
772 msg_fatal(
"%s: %s: %m", myname, EVENT_REG_ADD_TEXT);
775 fdp = event_fdtable + fd;
786 const char *myname =
"event_enable_write";
796 if (fd < 0 || fd >= event_fdlimit)
797 msg_panic(
"%s: bad file descriptor: %d", myname, fd);
802 if (fd >= event_fdslots)
809 msg_panic(
"%s: fd %d: read/write I/O request", myname, fd);
822 if (event_max_fd < fd)
824 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
825 EVENT_REG_ADD_WRITE(err, fd);
827 msg_fatal(
"%s: %s: %m", myname, EVENT_REG_ADD_TEXT);
830 fdp = event_fdtable + fd;
841 const char *myname =
"event_disable_readwrite";
851 if (fd < 0 || fd >= event_fdlimit)
852 msg_panic(
"%s: bad file descriptor: %d", myname, fd);
861 if (fd >= event_fdslots)
863 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT)
864 #ifdef EVENT_REG_DEL_BOTH
868 EVENT_REG_DEL_BOTH(err, fd);
870 msg_fatal(
"%s: %s: %m", myname, EVENT_REG_DEL_TEXT);
874 EVENT_REG_DEL_READ(err, fd);
876 msg_fatal(
"%s: %s: %m", myname, EVENT_REG_DEL_TEXT);
878 EVENT_REG_DEL_WRITE(err, fd);
880 msg_fatal(
"%s: %s: %m", myname, EVENT_REG_DEL_TEXT);
887 fdp = event_fdtable + fd;
896 const char *myname =
"event_request_timer";
907 msg_panic(
"%s: invalid delay: %d", myname, delay);
912 time(&event_present);
922 timer->
when = event_present + delay;
926 msg_info(
"%s: reset 0x%lx 0x%lx %d", myname,
927 (
long) callback, (
long) context, delay);
935 if (ring == &event_timer_head) {
937 timer->
when = event_present + delay;
942 msg_info(
"%s: set 0x%lx 0x%lx %d", myname,
943 (
long) callback, (
long) context, delay);
960 return (timer->
when);
967 const char *myname =
"event_cancel_timer";
983 if ((time_left = timer->
when - event_present) < 0)
991 msg_info(
"%s: 0x%lx 0x%lx %d", myname,
992 (
long) callback, (
long) context, time_left);
1000 const char *myname =
"event_loop";
1003 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
1008 struct timeval *tvp;
1012 EVENT_BUFFER event_buf[100];
1033 msg_info(
"%s: time left %3d for 0x%lx 0x%lx", myname,
1034 (
int) (timer->
when - event_present),
1043 if ((timer =
FIRST_TIMER(&event_timer_head)) != 0) {
1044 event_present = time((time_t *) 0);
1045 if ((select_delay = timer->
when - event_present) < 0) {
1047 }
else if (delay >= 0 && select_delay > delay) {
1048 select_delay = delay;
1051 select_delay = delay;
1054 msg_info(
"event_loop: select_delay %d", select_delay);
1060 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
1061 if (select_delay < 0) {
1066 tv.tv_sec = select_delay;
1074 rmask = event_rmask;
1075 wmask = event_wmask;
1076 xmask = event_xmask;
1078 event_count = select(event_max_fd + 1, &rmask, &wmask, &xmask, tvp);
1079 if (event_count < 0) {
1085 EVENT_BUFFER_READ(event_count, event_buf,
1086 sizeof(event_buf) /
sizeof(event_buf[0]),
1088 if (event_count < 0) {
1090 msg_fatal(
"event_loop: " EVENT_BUFFER_READ_TEXT
": %m");
1101 msg_panic(
"event_loop: recursive call");
1125 event_present = time((time_t *) 0);
1126 event_loop_instance += 1;
1128 while ((timer =
FIRST_TIMER(&event_timer_head)) != 0) {
1129 if (timer->
when > event_present)
1135 msg_info(
"%s: timer 0x%lx 0x%lx", myname,
1148 #if (EVENTS_STYLE == EVENTS_STYLE_SELECT)
1149 if (event_count > 0) {
1150 for (new_max_fd = 0, fd = 0; fd <= event_max_fd; fd++) {
1151 if (FD_ISSET(fd, &event_xmask)) {
1154 fdp = event_fdtable + fd;
1155 if (FD_ISSET(fd, &xmask)) {
1157 msg_info(
"%s: exception fd=%d act=0x%lx 0x%lx", myname,
1160 }
else if (FD_ISSET(fd, &wmask)) {
1162 msg_info(
"%s: write fd=%d act=0x%lx 0x%lx", myname,
1165 }
else if (FD_ISSET(fd, &rmask)) {
1167 msg_info(
"%s: read fd=%d act=0x%lx 0x%lx", myname,
1173 event_max_fd = new_max_fd;
1176 for (bp = event_buf; bp < event_buf + event_count; bp++) {
1177 fd = EVENT_GET_FD(bp);
1178 if (fd < 0 || fd > event_max_fd)
1179 msg_panic(
"%s: bad file descriptor: %d", myname, fd);
1181 fdp = event_fdtable + fd;
1182 if (EVENT_TEST_READ(bp)) {
1184 msg_info(
"%s: read fd=%d act=0x%lx 0x%lx", myname,
1187 }
else if (EVENT_TEST_WRITE(bp)) {
1189 msg_info(
"%s: write fd=%d act=0x%lx 0x%lx", myname,
1195 msg_info(
"%s: other fd=%d act=0x%lx 0x%lx", myname,
1218 static void timer_event(
int unused_event,
void *context)
1220 printf(
"%ld: %s\n", (
long) event_present, context);
1226 static void echo(
int unused_event,
void *unused_context)
1230 if (fgets(buf,
sizeof(buf), stdin) == 0)
1232 printf(
"Result: %s", buf);
1237 static void request(
int unused_event,
void *unused_context)
1251 int main(
int argc,
void **argv)
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
#define EVENT_MASK_ISSET(fd, mask)
void ring_detach(RING *entry)
EVENT_NOTIFY_TIME_FN callback
NORETURN msg_panic(const char *fmt,...)
void * myrealloc(void *ptr, ssize_t len)
void ring_init(RING *ring)
int main(int argc, char **argv)
#define EVENT_MASK_CMP(m1, m2)
void event_enable_write(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
#define EVENT_NOTIFY_RDWR_FN
#define EVENT_NOTIFY_TIME_FN
#define FOREACH_QUEUE_ENTRY(entry, head)
#define EVENT_INIT_NEEDED()
#define EVENT_MASK_CLR(fd, mask)
void event_loop(int delay)
void msg_warn(const char *fmt,...)
#define EVENT_MASK_SET(fd, mask)
NORETURN msg_fatal(const char *fmt,...)
#define EVENT_MASK_BYTE_COUNT(mask)
#define FIRST_TIMER(head)
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
EVENT_NOTIFY_RDWR_FN callback
void event_drain(int time_limit)
void event_disable_readwrite(int fd)
struct EVENT_FDTABLE EVENT_FDTABLE
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
#define EVENT_MASK_ZERO(mask)
void * mymalloc(ssize_t len)
void msg_info(const char *fmt,...)
void ring_prepend(RING *ring, RING *entry)