]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/io.c
kqueue: check for EV_ERROR in .flags
[ngircd-alex.git] / src / ngircd / io.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  * Please read the file COPYING, README and AUTHORS for more information.
7  *
8  * I/O abstraction interface.
9  * Copyright (c) 2005 Florian Westphal (westphal@foo.fh-furtwangen.de)
10  *
11  */
12
13 #include "portab.h"
14
15 static char UNUSED id[] = "$Id: io.c,v 1.27 2007/12/27 18:25:26 fw Exp $";
16
17 #include <assert.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24
25 #include "array.h"
26 #include "io.h"
27 #include "log.h"
28
29 /* Enables extra debug messages in event add/delete/callback code. */
30 /* #define DEBUG_IO */
31
32 typedef struct {
33 #ifdef PROTOTYPES
34  void (*callback)(int, short);
35 #else
36  void (*callback)();
37 #endif
38  short what;
39 } io_event;
40
41 #define INIT_IOEVENT            { NULL, -1, 0, NULL }
42 #define IO_ERROR                4
43
44 #ifdef HAVE_EPOLL_CREATE
45 #  define IO_USE_EPOLL          1
46 #  ifdef HAVE_SELECT
47 #    define IO_USE_SELECT       1
48 #  endif
49 #else
50 #  ifdef HAVE_KQUEUE
51 #    define IO_USE_KQUEUE       1
52 #  else
53 #    ifdef HAVE_SYS_DEVPOLL_H
54 #      define IO_USE_DEVPOLL    1
55 #    else
56 #      ifdef HAVE_POLL
57 #        define IO_USE_POLL     1
58 #      else
59 #        ifdef HAVE_SELECT
60 #          define IO_USE_SELECT 1
61 #        else
62 #          error "no IO API available!?"
63 #        endif /* HAVE_SELECT */
64 #      endif /* HAVE_POLL */
65 #    endif /* HAVE_SYS_DEVPOLL_H */
66 #  endif /* HAVE_KQUEUE */
67 #endif /* HAVE_EPOLL_CREATE */
68
69 static bool library_initialized = false;
70
71 #ifdef IO_USE_EPOLL
72 #include <sys/epoll.h>
73
74 static int io_masterfd = -1;
75 static bool io_event_change_epoll(int fd, short what, const int action);
76 static int io_dispatch_epoll(struct timeval *tv);
77 #endif
78
79 #ifdef IO_USE_KQUEUE
80 #include <sys/types.h>
81 #include <sys/event.h>
82 static array io_evcache;
83 static int io_masterfd;
84
85 static int io_dispatch_kqueue(struct timeval *tv);
86 static bool io_event_change_kqueue(int, short, const int action);
87 #endif
88
89 #ifdef IO_USE_POLL
90 #include <poll.h>
91
92 static array pollfds;
93 static int poll_maxfd;
94
95 static bool io_event_change_poll PARAMS((int fd, short what));
96 #endif
97
98 #ifdef IO_USE_DEVPOLL
99 #include <sys/devpoll.h>
100 static int io_masterfd;
101
102 static bool io_event_change_devpoll(int fd, short what);
103 #endif
104
105 #ifdef IO_USE_SELECT
106 #include "defines.h"    /* for conn.h */
107 #include "conn.h"       /* for CONN_IDX (needed by resolve.h) */
108 #include "resolve.h"    /* for RES_STAT (needed by conf.h) */
109 #include "conf.h"       /* for Conf_MaxConnections */
110
111 static fd_set readers;
112 static fd_set writers;
113 static int select_maxfd;                /* the select() interface sucks badly */
114 static int io_dispatch_select(struct timeval *tv);
115
116 #ifndef IO_USE_EPOLL
117 #define io_masterfd -1
118 #endif
119 #endif /* IO_USE_SELECT */
120
121 static array io_events;
122
123 static void io_docallback PARAMS((int fd, short what));
124
125 static io_event *
126 io_event_get(int fd)
127 {
128         io_event *i;
129
130         assert(fd >= 0);
131
132         i = (io_event *) array_get(&io_events, sizeof(io_event), (size_t) fd);
133
134         assert(i != NULL);
135
136         return i;
137 }
138
139
140 #ifdef IO_USE_DEVPOLL
141 static void
142 io_library_init_devpoll(unsigned int eventsize)
143 {
144         io_masterfd = open("/dev/poll", O_RDWR);
145         if (io_masterfd >= 0)
146                 library_initialized = true;
147         Log(LOG_INFO, "IO subsystem: /dev/poll (initial maxfd %u, masterfd %d).",
148                 eventsize, io_masterfd);
149 }
150 #endif
151
152
153 #ifdef IO_USE_POLL
154 static void
155 io_library_init_poll(unsigned int eventsize)
156 {
157         struct pollfd *p;
158         array_init(&pollfds);
159         poll_maxfd = 0;
160         Log(LOG_INFO, "IO subsystem: poll (initial maxfd %u).",
161             eventsize);
162         p = array_alloc(&pollfds, sizeof(struct pollfd), eventsize);
163         if (p) {
164                 unsigned i;
165                 p = array_start(&pollfds);
166                 for (i = 0; i < eventsize; i++)
167                         p[i].fd = -1;
168
169                 library_initialized = true;
170         }
171 }
172 #endif
173
174
175 #ifdef IO_USE_SELECT
176 static void
177 io_library_init_select(unsigned int eventsize)
178 {
179         Log(LOG_INFO, "IO subsystem: select (initial maxfd %u).",
180             eventsize);
181         FD_ZERO(&readers);
182         FD_ZERO(&writers);
183 #ifdef FD_SETSIZE
184         if (Conf_MaxConnections >= (int)FD_SETSIZE) {
185                 Log(LOG_WARNING,
186                     "MaxConnections (%d) exceeds limit (%u), changed MaxConnections to %u.",
187                     Conf_MaxConnections, FD_SETSIZE, FD_SETSIZE - 1);
188
189                 Conf_MaxConnections = FD_SETSIZE - 1;
190         }
191 #endif /* FD_SETSIZE */
192         library_initialized = true;
193 }
194 #endif /* SELECT */
195
196
197 #ifdef IO_USE_EPOLL
198 static void
199 io_library_init_epoll(unsigned int eventsize)
200 {
201         int ecreate_hint = (int)eventsize;
202         if (ecreate_hint <= 0)
203                 ecreate_hint = 128;
204         io_masterfd = epoll_create(ecreate_hint);
205         if (io_masterfd >= 0) {
206                 library_initialized = true;
207                 Log(LOG_INFO,
208                     "IO subsystem: epoll (hint size %d, initial maxfd %u, masterfd %d).",
209                     ecreate_hint, eventsize, io_masterfd);
210         }
211 }
212 #endif
213
214
215 #ifdef IO_USE_KQUEUE
216 static void
217 io_library_init_kqueue(unsigned int eventsize)
218 {
219         io_masterfd = kqueue();
220
221         Log(LOG_INFO,
222             "IO subsystem: kqueue (initial maxfd %u, masterfd %d)",
223             eventsize, io_masterfd);
224         if (io_masterfd >= 0)
225                 library_initialized = true;
226 }
227 #endif
228
229
230 bool
231 io_library_init(unsigned int eventsize)
232 {
233         if (library_initialized)
234                 return true;
235 #ifdef IO_USE_SELECT
236 #ifndef FD_SETSIZE
237         Log(LOG_WARNING,
238             "FD_SETSIZE undefined, don't know how many descriptors select() can handle on your platform ...");
239 #else
240         if (eventsize >= FD_SETSIZE)
241                 eventsize = FD_SETSIZE - 1;
242 #endif /* FD_SETSIZE */
243 #endif /* IO_USE_SELECT */
244         if ((eventsize > 0) && !array_alloc(&io_events, sizeof(io_event), (size_t)eventsize))
245                 eventsize = 0;
246 #ifdef IO_USE_EPOLL
247         io_library_init_epoll(eventsize);
248 #ifdef IO_USE_SELECT
249         if (io_masterfd < 0)
250                 Log(LOG_INFO, "Can't initialize epoll() IO interface, falling back to select() ...");
251 #endif
252 #endif
253 #ifdef IO_USE_KQUEUE
254         io_library_init_kqueue(eventsize);
255 #endif
256 #ifdef IO_USE_DEVPOLL
257         io_library_init_devpoll(eventsize);
258 #endif
259 #ifdef IO_USE_POLL
260         io_library_init_poll(eventsize);
261 #endif
262 #ifdef IO_USE_SELECT
263         if (! library_initialized)
264                 io_library_init_select(eventsize);
265 #endif
266         return library_initialized;
267 }
268
269
270 void
271 io_library_shutdown(void)
272 {
273 #ifdef IO_USE_SELECT
274         FD_ZERO(&readers);
275         FD_ZERO(&writers);
276 #endif
277 #ifdef IO_USE_EPOLL
278         if (io_masterfd >= 0)
279                 close(io_masterfd);
280         io_masterfd = -1;
281 #endif
282 #ifdef IO_USE_KQUEUE
283         close(io_masterfd);
284         io_masterfd = -1;
285         array_free(&io_evcache);
286 #endif
287         library_initialized = false;
288 }
289
290
291 bool
292 io_event_setcb(int fd, void (*cbfunc) (int, short))
293 {
294         io_event *i = io_event_get(fd);
295         if (!i)
296                 return false;
297
298         i->callback = cbfunc;
299         return true;
300 }
301
302
303 bool
304 io_event_create(int fd, short what, void (*cbfunc) (int, short))
305 {
306         bool ret;
307         io_event *i;
308
309         assert(fd >= 0);
310 #if defined(IO_USE_SELECT) && defined(FD_SETSIZE)
311         if (fd >= FD_SETSIZE) {
312                 Log(LOG_ERR,
313                     "fd %d exceeds FD_SETSIZE (%u) (select can't handle more file descriptors)",
314                     fd, FD_SETSIZE);
315                 return false;
316         }
317 #endif
318         i = (io_event *) array_alloc(&io_events, sizeof(io_event), (size_t) fd);
319         if (!i) {
320                 Log(LOG_WARNING,
321                     "array_alloc failed: could not allocate space for %d io_event structures",
322                     fd);
323                 return false;
324         }
325
326         i->callback = cbfunc;
327         i->what = 0;
328 #ifdef IO_USE_DEVPOLL
329         ret = io_event_change_devpoll(fd, what);
330 #endif
331 #ifdef IO_USE_POLL
332         ret = io_event_change_poll(fd, what);
333 #endif
334 #ifdef IO_USE_EPOLL
335         ret = io_event_change_epoll(fd, what, EPOLL_CTL_ADD);
336 #endif
337 #ifdef IO_USE_KQUEUE
338         ret = io_event_change_kqueue(fd, what, EV_ADD|EV_ENABLE);
339 #endif
340 #ifdef IO_USE_SELECT
341         if (io_masterfd < 0)
342                 ret = io_event_add(fd, what);
343 #endif
344         if (ret) i->what = what;
345         return ret;
346 }
347
348
349 #ifdef IO_USE_DEVPOLL
350 static bool
351 io_event_change_devpoll(int fd, short what)
352 {
353         struct pollfd p;
354
355         p.events = 0;
356
357         if (what & IO_WANTREAD)
358                 p.events = POLLIN | POLLPRI;
359         if (what & IO_WANTWRITE)
360                 p.events |= POLLOUT;
361
362         p.fd = fd;
363         return write(io_masterfd, &p, sizeof p) == (ssize_t)sizeof p;
364 }
365 #endif
366
367
368
369 #ifdef IO_USE_POLL
370 static bool
371 io_event_change_poll(int fd, short what)
372 {
373         struct pollfd *p;
374         short events = 0;
375
376         if (what & IO_WANTREAD)
377                 events = POLLIN | POLLPRI;
378         if (what & IO_WANTWRITE)
379                 events |= POLLOUT;
380
381         p = array_alloc(&pollfds, sizeof *p, fd);
382         if (p) {
383                 p->events = events;
384                 p->fd = fd;
385                 if (fd > poll_maxfd)
386                         poll_maxfd = fd;
387         }
388         return p != NULL;
389 }
390 #endif
391
392 #ifdef IO_USE_EPOLL
393 static bool
394 io_event_change_epoll(int fd, short what, const int action)
395 {
396         struct epoll_event ev = { 0, {0} };
397         ev.data.fd = fd;
398
399         if (what & IO_WANTREAD)
400                 ev.events = EPOLLIN | EPOLLPRI;
401         if (what & IO_WANTWRITE)
402                 ev.events |= EPOLLOUT;
403
404         return epoll_ctl(io_masterfd, action, fd, &ev) == 0;
405 }
406 #endif
407
408 #ifdef IO_USE_KQUEUE
409 static bool
410 io_event_kqueue_commit_cache(void)
411 {
412         struct kevent *events;
413         bool ret;
414         int len = (int) array_length(&io_evcache, sizeof (struct kevent));
415
416         if (!len) /* nothing to do */
417                 return true;
418
419         assert(len>0);
420
421         if (len < 0) {
422                 array_free(&io_evcache);
423                 return false;
424         }
425
426         events = array_start(&io_evcache);
427
428         assert(events != NULL);
429
430         ret = kevent(io_masterfd, events, len, NULL, 0, NULL) == 0;
431         if (ret)
432                 array_trunc(&io_evcache);
433         return ret;
434 }
435
436
437 static bool
438 io_event_change_kqueue(int fd, short what, const int action)
439 {
440         struct kevent kev;
441         bool ret = true;
442
443         if (what & IO_WANTREAD) {
444                 EV_SET(&kev, fd, EVFILT_READ, action, 0, 0, 0);
445                 ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev));
446                 if (!ret)
447                         ret = kevent(io_masterfd, &kev,1, NULL, 0, NULL) == 0;
448         }
449
450         if (ret && (what & IO_WANTWRITE)) {
451                 EV_SET(&kev, fd, EVFILT_WRITE, action, 0, 0, 0);
452                 ret = array_catb(&io_evcache, (char*) &kev, sizeof (kev));
453                 if (!ret)
454                         ret = kevent(io_masterfd, &kev, 1, NULL, 0, NULL) == 0;
455         }
456
457         if (array_length(&io_evcache, sizeof kev) >= 100)
458                 io_event_kqueue_commit_cache();
459         return ret;
460 }
461 #endif
462
463
464 bool
465 io_event_add(int fd, short what)
466 {
467         io_event *i = io_event_get(fd);
468
469         if (!i) return false;
470
471         if ((i->what & what) == what) /* event type is already registered */
472                 return true;
473 #ifdef DEBUG_IO
474         Log(LOG_DEBUG, "io_event_add(): fd %d, what %d.", fd, what);
475 #endif
476         i->what |= what;
477 #ifdef IO_USE_EPOLL
478         if (io_masterfd >= 0)
479                 return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD);
480 #endif
481
482 #ifdef IO_USE_KQUEUE
483         return io_event_change_kqueue(fd, what, EV_ADD | EV_ENABLE);
484 #endif
485 #ifdef IO_USE_DEVPOLL
486         return io_event_change_devpoll(fd, i->what);
487 #endif
488 #ifdef IO_USE_POLL
489         return io_event_change_poll(fd, i->what);
490 #endif
491 #ifdef IO_USE_SELECT
492         if (fd > select_maxfd)
493                 select_maxfd = fd;
494
495         if (what & IO_WANTREAD)
496                 FD_SET(fd, &readers);
497         if (what & IO_WANTWRITE)
498                 FD_SET(fd, &writers);
499
500         return true;
501 #endif
502 }
503
504
505 bool
506 io_setnonblock(int fd)
507 {
508         int flags = fcntl(fd, F_GETFL);
509         if (flags == -1)
510                 return false;
511
512 #ifndef O_NONBLOCK
513 #define O_NONBLOCK O_NDELAY
514 #endif
515         flags |= O_NONBLOCK;
516
517         return fcntl(fd, F_SETFL, flags) == 0;
518 }
519
520
521 #ifdef IO_USE_DEVPOLL
522 static void
523 io_close_devpoll(int fd)
524 {
525         struct pollfd p;
526         p.events = POLLREMOVE;
527         p.fd = fd;
528         write(io_masterfd, &p, sizeof p);
529 }
530 #else
531 static inline void
532 io_close_devpoll(int UNUSED x)
533
534         /* NOTHING */
535 }
536 #endif
537
538
539
540 #ifdef IO_USE_POLL
541 static void
542 io_close_poll(int fd)
543 {
544         struct pollfd *p;
545         p = array_get(&pollfds, sizeof *p, fd);
546         if (!p) return;
547
548         p->fd = -1;
549         if (fd == poll_maxfd) {
550                 while (poll_maxfd > 0) {
551                         --poll_maxfd;
552                         p = array_get(&pollfds, sizeof *p, poll_maxfd);
553                         if (p && p->fd >= 0)
554                                 break;
555                 }
556         }
557 }
558 #else
559 static inline void io_close_poll(int UNUSED x) { /* NOTHING */ }
560 #endif
561
562
563 #ifdef IO_USE_SELECT
564 static void
565 io_close_select(int fd)
566 {
567         io_event *i;
568
569         if (io_masterfd >= 0)   /* Are we using epoll()? */
570                 return;
571
572         FD_CLR(fd, &writers);
573         FD_CLR(fd, &readers);
574
575         i = io_event_get(fd);
576         if (!i) return;
577
578         if (fd == select_maxfd) {
579                 while (select_maxfd>0) {
580                         --select_maxfd; /* find largest fd */
581                         i = io_event_get(select_maxfd);
582                         if (i && i->callback) break;
583                 }
584         }
585 }
586 #else
587 static inline void
588 io_close_select(int UNUSED x)
589
590         /* NOTHING */
591 }
592 #endif
593
594
595 bool
596 io_close(int fd)
597 {
598         io_event *i;
599
600         i = io_event_get(fd);
601 #ifdef IO_USE_KQUEUE
602         if (array_length(&io_evcache, sizeof (struct kevent)))  /* pending data in cache? */
603                 io_event_kqueue_commit_cache();
604
605         /* both kqueue and epoll remove fd from all sets automatically on the last close
606          * of the descriptor. since we don't know if this is the last close we'll have
607          * to remove the set explicitly. */
608         if (i) {
609                 io_event_change_kqueue(fd, i->what, EV_DELETE);
610                 io_event_kqueue_commit_cache();
611         }
612 #endif
613
614         io_close_devpoll(fd);
615         io_close_poll(fd);
616         io_close_select(fd);
617
618 #ifdef IO_USE_EPOLL
619         io_event_change_epoll(fd, 0, EPOLL_CTL_DEL);
620 #endif
621         if (i) {
622                 i->callback = NULL;
623                 i->what = 0;
624         }
625         return close(fd) == 0;
626 }
627
628
629 bool
630 io_event_del(int fd, short what)
631 {
632         io_event *i = io_event_get(fd);
633 #ifdef DEBUG_IO
634         Log(LOG_DEBUG, "io_event_del(): trying to delete eventtype %d on fd %d", what, fd);
635 #endif
636         if (!i) return false;
637
638         i->what &= ~what;
639
640 #ifdef IO_USE_DEVPOLL
641         return io_event_change_devpoll(fd, i->what);
642 #endif
643 #ifdef IO_USE_POLL
644         return io_event_change_poll(fd, i->what);
645 #endif
646 #ifdef IO_USE_EPOLL
647         if (io_masterfd >= 0)
648                 return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD);
649 #endif
650
651 #ifdef IO_USE_KQUEUE
652         return io_event_change_kqueue(fd, what, EV_DISABLE);
653 #endif
654 #ifdef IO_USE_SELECT
655         if (what & IO_WANTWRITE)
656                 FD_CLR(fd, &writers);
657
658         if (what & IO_WANTREAD)
659                 FD_CLR(fd, &readers);
660
661         return true;
662 #endif
663 }
664
665
666 #ifdef IO_USE_SELECT
667 static int
668 io_dispatch_select(struct timeval *tv)
669 {
670         fd_set readers_tmp = readers;
671         fd_set writers_tmp = writers;
672         short what;
673         int ret, i;
674         int fds_ready;
675         ret = select(select_maxfd + 1, &readers_tmp, &writers_tmp, NULL, tv);
676         if (ret <= 0)
677                 return ret;
678
679         fds_ready = ret;
680
681         for (i = 0; i <= select_maxfd; i++) {
682                 what = 0;
683                 if (FD_ISSET(i, &readers_tmp)) {
684                         what = IO_WANTREAD;
685                         fds_ready--;
686                 }
687
688                 if (FD_ISSET(i, &writers_tmp)) {
689                         what |= IO_WANTWRITE;
690                         fds_ready--;
691                 }
692                 if (what)
693                         io_docallback(i, what);
694                 if (fds_ready <= 0)
695                         break;
696         }
697
698         return ret;
699 }
700 #endif
701
702
703 #ifdef IO_USE_DEVPOLL
704 static int
705 io_dispatch_devpoll(struct timeval *tv)
706 {
707         struct dvpoll dvp;
708         time_t sec = tv->tv_sec * 1000;
709         int i, total, ret, timeout = tv->tv_usec + sec;
710         short what;
711         struct pollfd p[100];
712
713         if (timeout < 0)
714                 timeout = 1000;
715
716         total = 0;
717         do {
718                 dvp.dp_timeout = timeout;
719                 dvp.dp_nfds = 100;
720                 dvp.dp_fds = p;
721                 ret = ioctl(io_masterfd, DP_POLL, &dvp);
722                 total += ret;
723                 if (ret <= 0)
724                         return total;
725                 for (i=0; i < ret ; i++) {
726                         what = 0;
727                         if (p[i].revents & (POLLIN|POLLPRI))
728                                 what = IO_WANTREAD;
729
730                         if (p[i].revents & POLLOUT)
731                                 what |= IO_WANTWRITE;
732
733                         if (p[i].revents && !what) {
734                                 /* other flag is set, probably POLLERR */
735                                 what = IO_ERROR;
736                         }
737                         io_docallback(p[i].fd, what);
738                 }
739         } while (ret == 100);
740
741         return total;
742 }
743 #endif
744
745
746 #ifdef IO_USE_POLL
747 static int
748 io_dispatch_poll(struct timeval *tv)
749 {
750         time_t sec = tv->tv_sec * 1000;
751         int i, ret, timeout = tv->tv_usec + sec;
752         int fds_ready;
753         short what;
754         struct pollfd *p = array_start(&pollfds);
755
756         if (timeout < 0)
757                 timeout = 1000;
758
759         ret = poll(p, poll_maxfd + 1, timeout);
760         if (ret <= 0)
761                 return ret;
762
763         fds_ready = ret;
764         for (i=0; i <= poll_maxfd; i++) {
765                 what = 0;
766                 if (p[i].revents & (POLLIN|POLLPRI))
767                         what = IO_WANTREAD;
768
769                 if (p[i].revents & POLLOUT)
770                         what |= IO_WANTWRITE;
771
772                 if (p[i].revents && !what) {
773                         /* other flag is set, probably POLLERR */
774                         what = IO_ERROR;
775                 }
776                 if (what) {
777                         fds_ready--;
778                         io_docallback(i, what);
779                 }
780                 if (fds_ready <= 0)
781                         break;
782         }
783
784         return ret;
785 }
786 #endif
787
788
789 #ifdef IO_USE_EPOLL
790 static int
791 io_dispatch_epoll(struct timeval *tv)
792 {
793         time_t sec = tv->tv_sec * 1000;
794         int i, total = 0, ret, timeout = tv->tv_usec + sec;
795         struct epoll_event epoll_ev[100];
796         short type;
797
798         if (timeout < 0)
799                 timeout = 1000;
800
801         do {
802                 ret = epoll_wait(io_masterfd, epoll_ev, 100, timeout);
803                 total += ret;
804                 if (ret <= 0)
805                         return total;
806
807                 for (i = 0; i < ret; i++) {
808                         type = 0;
809                         if (epoll_ev[i].events & (EPOLLERR | EPOLLHUP))
810                                 type = IO_ERROR;
811
812                         if (epoll_ev[i].events & (EPOLLIN | EPOLLPRI))
813                                 type |= IO_WANTREAD;
814
815                         if (epoll_ev[i].events & EPOLLOUT)
816                                 type |= IO_WANTWRITE;
817
818                         io_docallback(epoll_ev[i].data.fd, type);
819                 }
820
821                 timeout = 0;
822         } while (ret == 100);
823
824         return total;
825 }
826 #endif
827
828
829 #ifdef IO_USE_KQUEUE
830 static int
831 io_dispatch_kqueue(struct timeval *tv)
832 {
833         int i, total = 0, ret;
834         struct kevent kev[100];
835         struct kevent *newevents;
836         struct timespec ts;
837         int newevents_len;
838         ts.tv_sec = tv->tv_sec;
839         ts.tv_nsec = tv->tv_usec * 1000;
840
841         do {
842                 newevents_len = (int) array_length(&io_evcache, sizeof (struct kevent));
843                 newevents = (newevents_len > 0) ? array_start(&io_evcache) : NULL;
844                 assert(newevents_len >= 0);
845
846                 ret = kevent(io_masterfd, newevents, newevents_len, kev, 100, &ts);
847                 if (newevents && ret != -1)
848                         array_trunc(&io_evcache);
849
850                 total += ret;
851                 if (ret <= 0)
852                         return total;
853
854                 for (i = 0; i < ret; i++) {
855 #ifdef DEBUG_IO
856                         LogDebug("fd %d, kev.flags: %x", (int)kev[i].ident, kev[i].flags);
857 #endif
858                         if (kev[i].flags & (EV_EOF|EV_ERROR)) {
859                                 if (kev[i].flags & EV_ERROR)
860                                         Log(LOG_ERR, "kevent fd %d: EV_ERROR (%s)",
861                                                 (int)kev[i].ident, strerror((int)kev[i].data));
862                                 io_docallback((int)kev[i].ident, IO_ERROR);
863                                 continue;
864                         }
865
866                         switch (kev[i].filter) {
867                         case EVFILT_READ:
868                                 io_docallback((int)kev[i].ident, IO_WANTREAD);
869                                 break;
870                         case EVFILT_WRITE:
871                                 io_docallback((int)kev[i].ident, IO_WANTWRITE);
872                                 break;
873                         default:
874                                 LogDebug("Unknown kev.filter number %d for fd %d",
875                                         kev[i].filter, kev[i].ident);
876                                 /* Fall through */
877                         case EV_ERROR:
878                                 io_docallback((int)kev[i].ident, IO_ERROR);
879                                 break;
880                         }
881                 }
882                 ts.tv_sec = 0;
883                 ts.tv_nsec = 0;
884         } while (ret == 100);
885
886         return total;
887 }
888 #endif
889
890
891 int
892 io_dispatch(struct timeval *tv)
893 {
894 #ifdef IO_USE_EPOLL
895         if (io_masterfd >= 0)
896                 return io_dispatch_epoll(tv);
897 #endif
898 #ifdef IO_USE_SELECT
899         return io_dispatch_select(tv);
900 #endif
901 #ifdef IO_USE_KQUEUE
902         return io_dispatch_kqueue(tv);
903 #endif
904 #ifdef IO_USE_DEVPOLL
905         return io_dispatch_devpoll(tv);
906 #endif
907 #ifdef IO_USE_POLL
908         return io_dispatch_poll(tv);
909 #endif
910 }
911
912
913 /* call the callback function inside the struct matching fd */
914 static void
915 io_docallback(int fd, short what)
916 {
917         io_event *i;
918 #ifdef DEBUG_IO
919         Log(LOG_DEBUG, "doing callback for fd %d, what %d", fd, what);
920 #endif
921         i = io_event_get(fd);
922
923         if (i->callback) {      /* callback might be NULL if a previous callback function
924                                    called io_close on this fd */
925                 i->callback(fd, (what & IO_ERROR) ? i->what : what);
926         }
927         /* if error indicator is set, we return the event(s) that were registered */
928 }