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