]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/io.c
d40b4850ce7d2794b8daaf37df261b49e8fc55bc
[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.28 2008/01/02 10:29:51 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         if (!(i->what & what)) /* event is already disabled */
639                 return true;
640
641         i->what &= ~what;
642
643 #ifdef IO_USE_DEVPOLL
644         return io_event_change_devpoll(fd, i->what);
645 #endif
646 #ifdef IO_USE_POLL
647         return io_event_change_poll(fd, i->what);
648 #endif
649 #ifdef IO_USE_EPOLL
650         if (io_masterfd >= 0)
651                 return io_event_change_epoll(fd, i->what, EPOLL_CTL_MOD);
652 #endif
653
654 #ifdef IO_USE_KQUEUE
655         return io_event_change_kqueue(fd, what, EV_DISABLE);
656 #endif
657 #ifdef IO_USE_SELECT
658         if (what & IO_WANTWRITE)
659                 FD_CLR(fd, &writers);
660
661         if (what & IO_WANTREAD)
662                 FD_CLR(fd, &readers);
663
664         return true;
665 #endif
666 }
667
668
669 #ifdef IO_USE_SELECT
670 static int
671 io_dispatch_select(struct timeval *tv)
672 {
673         fd_set readers_tmp = readers;
674         fd_set writers_tmp = writers;
675         short what;
676         int ret, i;
677         int fds_ready;
678         ret = select(select_maxfd + 1, &readers_tmp, &writers_tmp, NULL, tv);
679         if (ret <= 0)
680                 return ret;
681
682         fds_ready = ret;
683
684         for (i = 0; i <= select_maxfd; i++) {
685                 what = 0;
686                 if (FD_ISSET(i, &readers_tmp)) {
687                         what = IO_WANTREAD;
688                         fds_ready--;
689                 }
690
691                 if (FD_ISSET(i, &writers_tmp)) {
692                         what |= IO_WANTWRITE;
693                         fds_ready--;
694                 }
695                 if (what)
696                         io_docallback(i, what);
697                 if (fds_ready <= 0)
698                         break;
699         }
700
701         return ret;
702 }
703 #endif
704
705
706 #ifdef IO_USE_DEVPOLL
707 static int
708 io_dispatch_devpoll(struct timeval *tv)
709 {
710         struct dvpoll dvp;
711         time_t sec = tv->tv_sec * 1000;
712         int i, total, ret, timeout = tv->tv_usec + sec;
713         short what;
714         struct pollfd p[100];
715
716         if (timeout < 0)
717                 timeout = 1000;
718
719         total = 0;
720         do {
721                 dvp.dp_timeout = timeout;
722                 dvp.dp_nfds = 100;
723                 dvp.dp_fds = p;
724                 ret = ioctl(io_masterfd, DP_POLL, &dvp);
725                 total += ret;
726                 if (ret <= 0)
727                         return total;
728                 for (i=0; i < ret ; i++) {
729                         what = 0;
730                         if (p[i].revents & (POLLIN|POLLPRI))
731                                 what = IO_WANTREAD;
732
733                         if (p[i].revents & POLLOUT)
734                                 what |= IO_WANTWRITE;
735
736                         if (p[i].revents && !what) {
737                                 /* other flag is set, probably POLLERR */
738                                 what = IO_ERROR;
739                         }
740                         io_docallback(p[i].fd, what);
741                 }
742         } while (ret == 100);
743
744         return total;
745 }
746 #endif
747
748
749 #ifdef IO_USE_POLL
750 static int
751 io_dispatch_poll(struct timeval *tv)
752 {
753         time_t sec = tv->tv_sec * 1000;
754         int i, ret, timeout = tv->tv_usec + sec;
755         int fds_ready;
756         short what;
757         struct pollfd *p = array_start(&pollfds);
758
759         if (timeout < 0)
760                 timeout = 1000;
761
762         ret = poll(p, poll_maxfd + 1, timeout);
763         if (ret <= 0)
764                 return ret;
765
766         fds_ready = ret;
767         for (i=0; i <= poll_maxfd; i++) {
768                 what = 0;
769                 if (p[i].revents & (POLLIN|POLLPRI))
770                         what = IO_WANTREAD;
771
772                 if (p[i].revents & POLLOUT)
773                         what |= IO_WANTWRITE;
774
775                 if (p[i].revents && !what) {
776                         /* other flag is set, probably POLLERR */
777                         what = IO_ERROR;
778                 }
779                 if (what) {
780                         fds_ready--;
781                         io_docallback(i, what);
782                 }
783                 if (fds_ready <= 0)
784                         break;
785         }
786
787         return ret;
788 }
789 #endif
790
791
792 #ifdef IO_USE_EPOLL
793 static int
794 io_dispatch_epoll(struct timeval *tv)
795 {
796         time_t sec = tv->tv_sec * 1000;
797         int i, total = 0, ret, timeout = tv->tv_usec + sec;
798         struct epoll_event epoll_ev[100];
799         short type;
800
801         if (timeout < 0)
802                 timeout = 1000;
803
804         do {
805                 ret = epoll_wait(io_masterfd, epoll_ev, 100, timeout);
806                 total += ret;
807                 if (ret <= 0)
808                         return total;
809
810                 for (i = 0; i < ret; i++) {
811                         type = 0;
812                         if (epoll_ev[i].events & (EPOLLERR | EPOLLHUP))
813                                 type = IO_ERROR;
814
815                         if (epoll_ev[i].events & (EPOLLIN | EPOLLPRI))
816                                 type |= IO_WANTREAD;
817
818                         if (epoll_ev[i].events & EPOLLOUT)
819                                 type |= IO_WANTWRITE;
820
821                         io_docallback(epoll_ev[i].data.fd, type);
822                 }
823
824                 timeout = 0;
825         } while (ret == 100);
826
827         return total;
828 }
829 #endif
830
831
832 #ifdef IO_USE_KQUEUE
833 static int
834 io_dispatch_kqueue(struct timeval *tv)
835 {
836         int i, total = 0, ret;
837         struct kevent kev[100];
838         struct kevent *newevents;
839         struct timespec ts;
840         int newevents_len;
841         ts.tv_sec = tv->tv_sec;
842         ts.tv_nsec = tv->tv_usec * 1000;
843
844         do {
845                 newevents_len = (int) array_length(&io_evcache, sizeof (struct kevent));
846                 newevents = (newevents_len > 0) ? array_start(&io_evcache) : NULL;
847                 assert(newevents_len >= 0);
848
849                 ret = kevent(io_masterfd, newevents, newevents_len, kev, 100, &ts);
850                 if (newevents && ret != -1)
851                         array_trunc(&io_evcache);
852
853                 total += ret;
854                 if (ret <= 0)
855                         return total;
856
857                 for (i = 0; i < ret; i++) {
858 #ifdef DEBUG_IO
859                         LogDebug("fd %d, kev.flags: %x", (int)kev[i].ident, kev[i].flags);
860 #endif
861                         if (kev[i].flags & (EV_EOF|EV_ERROR)) {
862                                 if (kev[i].flags & EV_ERROR)
863                                         Log(LOG_ERR, "kevent fd %d: EV_ERROR (%s)",
864                                                 (int)kev[i].ident, strerror((int)kev[i].data));
865                                 io_docallback((int)kev[i].ident, IO_ERROR);
866                                 continue;
867                         }
868
869                         switch (kev[i].filter) {
870                         case EVFILT_READ:
871                                 io_docallback((int)kev[i].ident, IO_WANTREAD);
872                                 break;
873                         case EVFILT_WRITE:
874                                 io_docallback((int)kev[i].ident, IO_WANTWRITE);
875                                 break;
876                         default:
877                                 LogDebug("Unknown kev.filter number %d for fd %d",
878                                         kev[i].filter, kev[i].ident);
879                                 /* Fall through */
880                         case EV_ERROR:
881                                 io_docallback((int)kev[i].ident, IO_ERROR);
882                                 break;
883                         }
884                 }
885                 ts.tv_sec = 0;
886                 ts.tv_nsec = 0;
887         } while (ret == 100);
888
889         return total;
890 }
891 #endif
892
893
894 int
895 io_dispatch(struct timeval *tv)
896 {
897 #ifdef IO_USE_EPOLL
898         if (io_masterfd >= 0)
899                 return io_dispatch_epoll(tv);
900 #endif
901 #ifdef IO_USE_SELECT
902         return io_dispatch_select(tv);
903 #endif
904 #ifdef IO_USE_KQUEUE
905         return io_dispatch_kqueue(tv);
906 #endif
907 #ifdef IO_USE_DEVPOLL
908         return io_dispatch_devpoll(tv);
909 #endif
910 #ifdef IO_USE_POLL
911         return io_dispatch_poll(tv);
912 #endif
913 }
914
915
916 /* call the callback function inside the struct matching fd */
917 static void
918 io_docallback(int fd, short what)
919 {
920         io_event *i;
921 #ifdef DEBUG_IO
922         Log(LOG_DEBUG, "doing callback for fd %d, what %d", fd, what);
923 #endif
924         i = io_event_get(fd);
925
926         if (i->callback) {      /* callback might be NULL if a previous callback function
927                                    called io_close on this fd */
928                 i->callback(fd, (what & IO_ERROR) ? i->what : what);
929         }
930         /* if error indicator is set, we return the event(s) that were registered */
931 }