|
|
- /* See LICENSE file for copyright and license details. */
- #include <stddef.h>
-
- #ifdef __linux__
- #include <sys/epoll.h>
- #else
- #include <sys/types.h>
- #include <sys/event.h>
- #include <sys/time.h>
- #endif
-
- #include "queue.h"
- #include "util.h"
-
- int
- queue_create(void)
- {
- int qfd;
-
- #ifdef __linux__
- if ((qfd = epoll_create1(0)) < 0) {
- warn("epoll_create1:");
- }
- #else
- if ((qfd = kqueue()) < 0) {
- warn("kqueue:");
- }
- #endif
-
- return qfd;
- }
-
- int
- queue_add_fd(int qfd, int fd, enum queue_event_type t, int shared,
- const void *data)
- {
- #ifdef __linux__
- struct epoll_event e;
-
- /* set event flag */
- if (shared) {
- /*
- * if the fd is shared, "exclusive" is the only
- * way to avoid spurious wakeups and "blocking"
- * accept()'s.
- */
- e.events = EPOLLEXCLUSIVE;
- } else {
- /*
- * if we have the fd for ourselves (i.e. only
- * within the thread), we want to be
- * edge-triggered, as our logic makes sure
- * that the buffers are drained when we return
- * to epoll_wait()
- */
- e.events = EPOLLET;
- }
-
- switch (t) {
- case QUEUE_EVENT_IN:
- e.events |= EPOLLIN;
- break;
- case QUEUE_EVENT_OUT:
- e.events |= EPOLLOUT;
- break;
- }
-
- /* set data pointer */
- e.data.ptr = (void *)data;
-
- /* register fd in the interest list */
- if (epoll_ctl(qfd, EPOLL_CTL_ADD, fd, &e) < 0) {
- warn("epoll_ctl:");
- return -1;
- }
- #else
- struct kevent e;
- int events;
-
- /* prepare event flag */
- events = (shared) ? 0 : EV_CLEAR;
-
- switch (t) {
- case QUEUE_EVENT_IN:
- events |= EVFILT_READ;
- break;
- case QUEUE_EVENT_OUT:
- events |= EVFILT_WRITE;
- break;
- }
-
- EV_SET(&e, fd, events, EV_ADD, 0, 0, (void *)data);
-
- if (kevent(qfd, &e, 1, NULL, 0, NULL) < 0) {
- warn("kevent:");
- return -1;
- }
- #endif
-
- return 0;
- }
-
- int
- queue_mod_fd(int qfd, int fd, enum queue_event_type t, const void *data)
- {
- #ifdef __linux__
- struct epoll_event e;
-
- /* set event flag (only for non-shared fd's) */
- e.events = EPOLLET;
-
- switch (t) {
- case QUEUE_EVENT_IN:
- e.events |= EPOLLIN;
- break;
- case QUEUE_EVENT_OUT:
- e.events |= EPOLLOUT;
- break;
- }
-
- /* set data pointer */
- e.data.ptr = (void *)data;
-
- /* register fd in the interest list */
- if (epoll_ctl(qfd, EPOLL_CTL_MOD, fd, &e) < 0) {
- warn("epoll_ctl:");
- return -1;
- }
- #else
- struct kevent e;
- int events;
-
- events = EV_CLEAR;
-
- switch (t) {
- case QUEUE_EVENT_IN:
- events |= EVFILT_READ;
- break;
- case QUEUE_EVENT_OUT:
- events |= EVFILT_WRITE;
- break;
- }
-
- EV_SET(&e, fd, events, EV_ADD, 0, 0, (void *)data);
-
- if (kevent(qfd, &e, 1, NULL, 0, NULL) < 0) {
- warn("kevent:");
- return -1;
- }
- #endif
-
- return 0;
- }
-
- int
- queue_rem_fd(int qfd, int fd)
- {
- #ifdef __linux__
- struct epoll_event e;
-
- if (epoll_ctl(qfd, EPOLL_CTL_DEL, fd, &e) < 0) {
- warn("epoll_ctl:");
- return -1;
- }
- #else
- struct kevent e;
-
- EV_SET(&e, fd, 0, EV_DELETE, 0, 0, 0);
-
- if (kevent(qfd, &e, 1, NULL, 0, NULL) < 0) {
- warn("kevent:");
- return -1;
- }
- #endif
-
- return 0;
- }
-
- ssize_t
- queue_wait(int qfd, queue_event *e, size_t elen)
- {
- ssize_t nready;
-
- #ifdef __linux__
- if ((nready = epoll_wait(qfd, e, elen, -1)) < 0) {
- warn("epoll_wait:");
- return -1;
- }
- #else
- if ((nready = kevent(qfd, NULL, 0, e, elen, NULL)) < 0) {
- warn("kevent:");
- return -1;
- }
- #endif
-
- return nready;
- }
-
- void *
- queue_event_get_data(const queue_event *e)
- {
- #ifdef __linux__
- return e->data.ptr;
- #else
- return e->udata;
- #endif
- }
-
- int
- queue_event_is_error(const queue_event *e)
- {
- #ifdef __linux__
- return (e->events & ~(EPOLLIN | EPOLLOUT)) ? 1 : 0;
- #else
- return (e->flags & EV_EOF) ? 1 : 0;
- #endif
- }
|