+ struct pollfd *p;
+ array_init(&pollfds);
+ poll_maxfd = 0;
+ Log(LOG_INFO, "IO subsystem: poll (initial maxfd %u).",
+ eventsize);
+ p = array_alloc(&pollfds, sizeof(struct pollfd), eventsize);
+ if (p) {
+ unsigned i;
+ p = array_start(&pollfds);
+ for (i = 0; i < eventsize; i++)
+ p[i].fd = -1;
+
+ library_initialized = true;
+ }
+}
+#else
+static inline void
+io_close_poll(int UNUSED x)
+{ /* NOTHING */ }
+static inline void
+io_library_init_poll(unsigned int UNUSED ev)
+{ /* NOTHING */ }
+#endif
+
+
+#ifdef IO_USE_SELECT
+static int
+io_dispatch_select(struct timeval *tv)
+{
+ fd_set readers_tmp;
+ fd_set writers_tmp;
+ short what;
+ int ret, i;
+ int fds_ready;
+
+ readers_tmp = readers;
+ writers_tmp = writers;
+
+ ret = select(select_maxfd + 1, &readers_tmp, &writers_tmp, NULL, tv);
+ if (ret <= 0)
+ return ret;
+
+ fds_ready = ret;
+
+ for (i = 0; i <= select_maxfd; i++) {
+ what = 0;
+ if (FD_ISSET(i, &readers_tmp)) {
+ what = IO_WANTREAD;
+ fds_ready--;
+ }
+
+ if (FD_ISSET(i, &writers_tmp)) {
+ what |= IO_WANTWRITE;
+ fds_ready--;
+ }
+ if (what)
+ io_docallback(i, what);
+ if (fds_ready <= 0)
+ break;
+ }
+
+ return ret;
+}
+
+static void
+io_library_init_select(unsigned int eventsize)
+{
+ if (library_initialized)
+ return;
+ Log(LOG_INFO, "IO subsystem: select (initial maxfd %u).",
+ eventsize);
+ FD_ZERO(&readers);
+ FD_ZERO(&writers);
+#ifdef FD_SETSIZE
+ if (Conf_MaxConnections >= (int)FD_SETSIZE) {
+ Log(LOG_WARNING,
+ "MaxConnections (%d) exceeds limit (%u), changed MaxConnections to %u.",
+ Conf_MaxConnections, FD_SETSIZE, FD_SETSIZE - 1);
+
+ Conf_MaxConnections = FD_SETSIZE - 1;
+ }
+#else
+ Log(LOG_WARNING,
+ "FD_SETSIZE undefined, don't know how many descriptors select() can handle on your platform ...");
+#endif /* FD_SETSIZE */
+ library_initialized = true;
+}
+
+static void
+io_close_select(int fd)
+{
+ io_event *i;
+
+ if (io_masterfd >= 0) /* Are we using epoll()? */
+ return;
+
+ FD_CLR(fd, &writers);
+ FD_CLR(fd, &readers);
+
+ i = io_event_get(fd);
+ if (!i) return;
+
+ if (fd == select_maxfd) {
+ while (select_maxfd>0) {
+ --select_maxfd; /* find largest fd */
+ i = io_event_get(select_maxfd);
+ if (i && i->callback) break;
+ }
+ }
+}
+#else
+static inline void
+io_library_init_select(int UNUSED x)
+{ /* NOTHING */ }
+static inline void
+io_close_select(int UNUSED x)
+{ /* NOTHING */ }
+#endif /* SELECT */
+
+
+#ifdef IO_USE_EPOLL
+static bool
+io_event_change_epoll(int fd, short what, const int action)
+{
+ struct epoll_event ev = { 0, {0} };
+ ev.data.fd = fd;
+
+ if (what & IO_WANTREAD)
+ ev.events = EPOLLIN | EPOLLPRI;
+ if (what & IO_WANTWRITE)
+ ev.events |= EPOLLOUT;
+
+ return epoll_ctl(io_masterfd, action, fd, &ev) == 0;
+}
+
+static int
+io_dispatch_epoll(struct timeval *tv)
+{
+ time_t sec = tv->tv_sec * 1000;
+ int i, ret, timeout = tv->tv_usec + sec;
+ struct epoll_event epoll_ev[MAX_EVENTS];
+ short type;
+
+ if (timeout < 0)
+ timeout = 1000;
+
+ ret = epoll_wait(io_masterfd, epoll_ev, MAX_EVENTS, timeout);
+
+ for (i = 0; i < ret; i++) {
+ type = 0;
+ if (epoll_ev[i].events & (EPOLLERR | EPOLLHUP))
+ type = IO_ERROR;
+
+ if (epoll_ev[i].events & (EPOLLIN | EPOLLPRI))
+ type |= IO_WANTREAD;
+
+ if (epoll_ev[i].events & EPOLLOUT)
+ type |= IO_WANTWRITE;
+
+ io_docallback(epoll_ev[i].data.fd, type);
+ }
+
+ return ret;
+}
+
+static void
+io_library_init_epoll(unsigned int eventsize)
+{
+ int ecreate_hint = (int)eventsize;
+ if (ecreate_hint <= 0)
+ ecreate_hint = 128;
+ io_masterfd = epoll_create(ecreate_hint);
+ if (io_masterfd >= 0) {
+ library_initialized = true;
+ Log(LOG_INFO,
+ "IO subsystem: epoll (hint size %d, initial maxfd %u, masterfd %d).",
+ ecreate_hint, eventsize, io_masterfd);
+ return;
+ }
+#ifdef IO_USE_SELECT
+ Log(LOG_INFO, "Can't initialize epoll() IO interface, falling back to select() ...");
+#endif
+}
+#else
+static inline void
+io_library_init_epoll(unsigned int UNUSED ev)
+{ /* NOTHING */ }
+#endif /* IO_USE_EPOLL */
+
+
+#ifdef IO_USE_KQUEUE
+static bool
+io_event_kqueue_commit_cache(void)
+{
+ struct kevent *events;
+ bool ret;
+ int len = (int) array_length(&io_evcache, sizeof (struct kevent));
+
+ if (!len) /* nothing to do */
+ return true;
+