#if defined(USE_KQUEUE) || defined(USE_EPOLL)
int fd;
+ int waitfd;
#endif
#if defined(USE_KQUEUE)
struct kevent *fds;
}
static int
-eloop_event_kqueue(struct eloop *eloop, struct eloop_event *e,
- unsigned short events)
+eloop_event_kqueue(int fd, struct eloop_event *e, unsigned short events)
{
#ifdef EVFILT_PROCDESC
#define NKE 3
#define NKE 2
#endif
struct kevent ke[NKE], *kep = ke;
- int fd = e->fd;
+ uintptr_t efd = (uintptr_t)e->fd;
if (events & ELE_READ && !(e->events & ELE_READ))
- EV_SET(kep++, (uintptr_t)fd, EVFILT_READ, EV_ADD, 0, 0, e);
+ EV_SET(kep++, efd, EVFILT_READ, EV_ADD, 0, 0, e);
else if (!(events & ELE_READ) && e->events & ELE_READ)
- EV_SET(kep++, (uintptr_t)fd, EVFILT_READ, EV_DELETE, 0, 0, e);
+ EV_SET(kep++, efd, EVFILT_READ, EV_DELETE, 0, 0, e);
if (events & ELE_WRITE && !(e->events & ELE_WRITE))
- EV_SET(kep++, (uintptr_t)fd, EVFILT_WRITE, EV_ADD, 0, 0, e);
+ EV_SET(kep++, efd, EVFILT_WRITE, EV_ADD, 0, 0, e);
else if (!(events & ELE_WRITE) && e->events & ELE_WRITE)
- EV_SET(kep++, (uintptr_t)fd, EVFILT_WRITE, EV_DELETE, 0, 0, e);
+ EV_SET(kep++, efd, EVFILT_WRITE, EV_DELETE, 0, 0, e);
#ifdef EVFILT_PROCDESC
if (events & ELE_HANGUP && !(e->events & ELE_HANGUP))
- EV_SET(kep++, (uintptr_t)fd, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT,
- 0, e);
+ EV_SET(kep++, efd, EVFILT_PROCDESC, EV_ADD, NOTE_EXIT, 0, e);
else if (!(events & ELE_HANGUP) && e->events & ELE_HANGUP)
- EV_SET(kep++, (uintptr_t)fd, EVFILT_PROCDESC, EV_DELETE,
- NOTE_EXIT, 0, e);
+ EV_SET(kep++, efd, EVFILT_PROCDESC, EV_DELETE, NOTE_EXIT, 0, e);
#endif
if (kep == ke)
return 0;
- if (kevent(eloop->fd, ke, (KEVENT_N)(kep - ke), NULL, 0, NULL) == -1)
+ if (kevent(fd, ke, (KEVENT_N)(kep - ke), NULL, 0, NULL) == -1)
return -1;
return 1;
}
#elif defined(USE_EPOLL)
static int
-eloop_event_epoll(struct eloop *eloop, struct eloop_event *e,
- unsigned short events)
+eloop_event_epoll(int fd, struct eloop_event *e, unsigned short events)
{
struct epoll_event epe;
int op;
epe.events |= EPOLLIN;
if (events & ELE_WRITE)
epe.events |= EPOLLOUT;
- op = e->events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
+ if (events & ELE_HANGUP)
+ epe.events |= EPOLLHUP;
if (epe.events == 0)
- return 0;
- if (epoll_ctl(eloop->fd, op, e->fd, &epe) == -1)
+ op = EPOLL_CTL_DEL;
+ else
+ op = e->events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
+ if (epoll_ctl(fd, op, e->fd, &epe) == -1)
return -1;
return 1;
}
e->cb_arg = cb_arg;
#if defined(USE_KQUEUE)
- kadded = eloop_event_kqueue(eloop, e, events);
+ kadded = eloop_event_kqueue(eloop->fd, e, events);
#elif defined(USE_EPOLL)
- kadded = eloop_event_epoll(eloop, e, events);
+ kadded = eloop_event_epoll(eloop->fd, e, events);
#elif defined(USE_PPOLL)
e->pollfd = NULL;
kadded = 1;
#if defined(USE_KQUEUE) || defined(USE_EPOLL)
static int
-eloop_open(struct eloop *eloop)
+eloop_open(void)
{
int fd;
fd = epoll_create1(EPOLL_CLOEXEC);
#endif
- eloop->fd = fd;
return fd;
}
#endif
close(eloop->fd);
#endif
eloop->fd = -1;
- if (flags && eloop_open(eloop) == -1)
- return -1;
+ if (flags) {
+ if ((eloop->fd = eloop_open()) == -1)
+ return -1;
+
+ if (eloop->waitfd != -1) {
+#ifdef USE_EPOLL
+ close(eloop->waitfd);
+#endif
+ if ((eloop->waitfd = eloop_open()) == -1)
+ return -1;
+ }
+ } else {
+#ifdef USE_EPOLL
+ close(eloop->waitfd);
+#endif
+ eloop->waitfd = -1;
+ }
eloop_clear(eloop, flags);
if (!flags)
events = e->events;
e->events = 0;
#if defined(USE_KQUEUE)
- err = eloop_event_kqueue(eloop, e, events);
+ err = eloop_event_kqueue(eloop->fd, e, events);
#elif defined(USE_EPOLL)
- err = eloop_event_epoll(eloop, e, events);
+ err = eloop_event_epoll(eloop->fd, e, events);
#endif
if (err == -1)
return -1;
eloop->exitcode = EXIT_FAILURE;
#if defined(USE_KQUEUE) || defined(USE_EPOLL)
- if (eloop_open(eloop) == -1 || eloop_grow_events(eloop) == -1) {
+ eloop->waitfd = -1;
+ if ((eloop->fd = eloop_open()) == -1 ||
+ eloop_grow_events(eloop) == -1) {
eloop_free(eloop);
return NULL;
}
eloop_clear(eloop, 0);
#if defined(USE_KQUEUE) || defined(USE_EPOLL)
+ if (eloop->waitfd != -1)
+ close(eloop->waitfd);
if (eloop->fd != -1)
close(eloop->fd);
#endif
free(eloop);
}
+#if defined(USE_KQUEUE)
+static unsigned short
+eloop_kqueueevents(struct kevent *ke)
+{
+ unsigned short events;
+
+ if (ke->filter == EVFILT_READ)
+ events = ELE_READ;
+ else if (ke->filter == EVFILT_WRITE)
+ events = ELE_WRITE;
+#ifdef EVFILT_PROCDESC
+ else if (ke->filter == EVFILT_PROCDESC && ke->fflags & NOTE_EXIT)
+ /* exit status is in ke->data
+ * should we do anything with it? */
+ events = ELE_HANGUP;
+#endif
+ else
+ events = 0;
+ if (ke->flags & EV_EOF)
+ events |= ELE_HANGUP;
+ if (ke->flags & EV_ERROR)
+ events |= ELE_ERROR;
+ return events;
+}
+#elif defined(USE_EPOLL)
+static unsigned short
+eloop_epollevents(struct epoll_event *epe)
+{
+ unsigned short events = 0;
+
+ if (epe->events & EPOLLIN)
+ events |= ELE_READ;
+ if (epe->events & EPOLLOUT)
+ events |= ELE_WRITE;
+ if (epe->events & EPOLLHUP)
+ events |= ELE_HANGUP;
+ if (epe->events & EPOLLERR)
+ events |= ELE_ERROR;
+
+ return events;
+}
+#elif defined(USE_POLL)
static unsigned short
eloop_pollevents(struct pollfd *pfd)
{
events |= ELE_NVAL;
return events;
}
+#endif
int
-eloop_waitfd(int fd)
+eloop_openfdwaiter(struct eloop *eloop)
{
- struct pollfd pfd = { .fd = fd, .events = POLLIN };
- int err;
+#if defined(USE_KQUEUE) || defined(USE_EPOLL)
+ int fd;
+
+ fd = eloop_open();
+ if (fd == -1)
+ return -1;
+ eloop->waitfd = fd;
+ return fd;
+#else
+ /* Not an error, but no fd */
+ errno = 0;
+ return -1;
+#endif
+}
+
+int
+eloop_waitfd(struct eloop *eloop, int fd)
+{
+ int n;
+#if defined(USE_KQUEUE)
+ struct kevent ke;
+
+ EV_SET(&ke, (uintptr_t)fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0,
+ NULL);
+ n = kevent(eloop->waitfd, &ke, 1, &ke, 1, NULL);
+ if (n == -1 || n == 0)
+ return n;
+ return (int)eloop_kqueueevents(&ke);
+#elif defined(USE_EPOLL)
+ struct eloop_event e = { .fd = fd };
+ struct epoll_event epe;
- err = poll(&pfd, 1, -1);
- if (err == -1 || err == 0)
- return err;
+ if (eloop_event_epoll(eloop->waitfd, &e, ELE_READ) == -1)
+ return -1;
+ n = epoll_pwait(eloop->waitfd, &epe, 1, -1, NULL);
+ if (eloop_event_epoll(eloop->waitfd, &e, 0) == -1)
+ return -1;
+ if (n == -1 || n == 0)
+ return n;
+ return (int)eloop_epollevents(&epe);
+#else
+ struct pollfd pfd = { .fd = fd, .events = POLLIN };
+ n = poll(&pfd, 1, -1);
+ if (n == -1 || n == 0)
+ return n;
return (int)eloop_pollevents(&pfd);
+#endif
+}
+
+int
+eloop_closefdwaiter(struct eloop *eloop)
+{
+#if defined(USE_KQUEUE) || defined(USE_EPOLL)
+ int err = close(eloop->waitfd);
+ eloop->waitfd = -1;
+ return err;
+#else
+ return 0;
+#endif
}
#if defined(USE_KQUEUE)
eloop->signal_cb_ctx);
continue;
}
- if (ke->filter == EVFILT_READ)
- events = ELE_READ;
- else if (ke->filter == EVFILT_WRITE)
- events = ELE_WRITE;
-#ifdef EVFILT_PROCDESC
- else if (ke->filter == EVFILT_PROCDESC &&
- ke->fflags & NOTE_EXIT)
- /* exit status is in ke->data
- * should we do anything with it? */
- events = ELE_HANGUP;
-#endif
- else
- continue; /* assert? */
- if (ke->flags & EV_EOF)
- events |= ELE_HANGUP;
- if (ke->flags & EV_ERROR)
- events |= ELE_ERROR;
+ events = eloop_kqueueevents(ke);
e = (struct eloop_event *)ke->udata;
e->cb(e->cb_arg, events);
}
e = (struct eloop_event *)epe->data.ptr;
if (e->fd == -1)
continue;
- events = 0;
- if (epe->events & EPOLLIN)
- events |= ELE_READ;
- if (epe->events & EPOLLOUT)
- events |= ELE_WRITE;
- if (epe->events & EPOLLHUP)
- events |= ELE_HANGUP;
- if (epe->events & EPOLLERR)
- events |= ELE_ERROR;
+ events = eloop_epollevents(epe);
e->cb(e->cb_arg, events);
}