From eca09957e470682517528b6cbbe63157aa7e588a Mon Sep 17 00:00:00 2001 From: Marek Vavrusa <marek.vavrusa@nic.cz> Date: Fri, 5 Jul 2013 17:47:18 +0200 Subject: [PATCH] Added support for different events (READ/WRITE) for fdset. To do: * Disabled epoll/kqueue backend as there is something broken for write events refs #65 --- src/common/fdset.c | 24 ++++++++++++------------ src/common/fdset.h | 14 ++++++++++++++ src/common/fdset_epoll.c | 29 ++++++++++++++++++++++++++++- src/common/fdset_epoll.h | 11 +++++++++++ src/common/fdset_kqueue.c | 33 ++++++++++++++++++++++++++++++--- src/common/fdset_kqueue.h | 11 +++++++++++ src/common/fdset_poll.c | 33 +++++++++++++++++++++++++++++---- src/common/fdset_poll.h | 11 +++++++++++ 8 files changed, 146 insertions(+), 20 deletions(-) diff --git a/src/common/fdset.c b/src/common/fdset.c index 3b4b75aa7..96a6e51be 100644 --- a/src/common/fdset.c +++ b/src/common/fdset.c @@ -62,20 +62,20 @@ static void fdset_set_backend(struct fdset_backend_t *backend) { void __attribute__ ((constructor)) fdset_init() { /* Preference: epoll */ -#ifdef HAVE_EPOLL_WAIT - if (dlsym(RTLD_DEFAULT, "epoll_wait") != 0) { - fdset_set_backend(&FDSET_EPOLL); - return; - } -#endif +//#ifdef HAVE_EPOLL_WAIT +// if (dlsym(RTLD_DEFAULT, "epoll_wait") != 0) { +// fdset_set_backend(&FDSET_EPOLL); +// return; +// } +//#endif /* Preference: kqueue */ -#ifdef HAVE_KQUEUE - if (dlsym(RTLD_DEFAULT, "kqueue") != 0) { - fdset_set_backend(&FDSET_KQUEUE); - return; - } -#endif +//#ifdef HAVE_KQUEUE +// if (dlsym(RTLD_DEFAULT, "kqueue") != 0) { +// fdset_set_backend(&FDSET_KQUEUE); +// return; +// } +//#endif /* Fallback: poll */ #ifdef HAVE_POLL diff --git a/src/common/fdset.h b/src/common/fdset.h index e1facdb06..0edc50b33 100644 --- a/src/common/fdset.h +++ b/src/common/fdset.h @@ -92,6 +92,7 @@ struct fdset_backend_t int (*fdset_destroy)(fdset_t*); int (*fdset_add)(fdset_t*, int, int); int (*fdset_remove)(fdset_t*, int); + int (*fdset_set_events)(fdset_t*, int, int); int (*fdset_wait)(fdset_t*, int); int (*fdset_begin)(fdset_t*, fdset_it_t*); int (*fdset_end)(fdset_t*, fdset_it_t*); @@ -149,6 +150,19 @@ static inline int fdset_add(fdset_t *fdset, int fd, int events) { */ int fdset_remove(fdset_t *fdset, int fd); +/*! + * \brief Change descriptor watched events mask. + * + * \param fdset Target set. + * \param fd Related file descriptor. + * + * \retval 0 if successful. + * \retval -1 if not found. + */ +static inline int fdset_set_events(fdset_t *fdset, int fd, int events) { + return _fdset_backend.fdset_set_events(fdset, fd, events); +} + /*! * \brief Poll set for new events. * diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c index f889dd33c..993a432fc 100644 --- a/src/common/fdset_epoll.c +++ b/src/common/fdset_epoll.c @@ -81,8 +81,13 @@ int fdset_epoll_add(fdset_t *fdset, int fd, int events) /* Add to epoll set. */ struct epoll_event ev; memset(&ev, 0, sizeof(struct epoll_event)); - ev.events = EPOLLIN; ev.data.fd = fd; + /* Build mask. */ + ev.events = 0; + if (events & OS_EV_READ) + ev.events = EPOLLIN; + if (events & OS_EV_WRITE) + ev.events = EPOLLOUT; if (epoll_ctl(fdset->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { return -1; } @@ -114,6 +119,27 @@ int fdset_epoll_remove(fdset_t *fdset, int fd) return 0; } +int fdset_epoll_set_events(fdset_t *fdset, int fd, int events) +{ + /* Add to epoll set. */ + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + ev.data.fd = fd; + + /* Build mask. */ + ev.events = 0; + if (events & OS_EV_READ) + ev.events = EPOLLIN; + if (events & OS_EV_WRITE) + ev.events = EPOLLOUT; + + if (epoll_ctl(fdset->epfd, EPOLL_CTL_MOD, fd, &ev) < 0) { + return -1; + } + return 0; +} + + int fdset_epoll_wait(fdset_t *fdset, int timeout) { if (fdset == NULL || fdset->nfds < 1 || fdset->events == NULL) { @@ -195,6 +221,7 @@ struct fdset_backend_t FDSET_EPOLL = { .fdset_destroy = fdset_epoll_destroy, .fdset_add = fdset_epoll_add, .fdset_remove = fdset_epoll_remove, + .fdset_set_events = fdset_epoll_set_events, .fdset_wait = fdset_epoll_wait, .fdset_begin = fdset_epoll_begin, .fdset_end = fdset_epoll_end, diff --git a/src/common/fdset_epoll.h b/src/common/fdset_epoll.h index 58f25f81e..a5947378c 100644 --- a/src/common/fdset_epoll.h +++ b/src/common/fdset_epoll.h @@ -70,6 +70,17 @@ int fdset_epoll_add(fdset_t *fdset, int fd, int events); */ int fdset_epoll_remove(fdset_t *fdset, int fd); +/*! + * \brief Change descriptor watched events mask. + * + * \param fdset Target set. + * \param fd Related file descriptor. + * + * \retval 0 if successful. + * \retval -1 if not found. + */ +int fdset_epoll_set_events(fdset_t *fdset, int fd, int events); + /*! * \brief Poll set for new events. * diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c index 7c52f71ba..0685f87ae 100644 --- a/src/common/fdset_kqueue.c +++ b/src/common/fdset_kqueue.c @@ -91,10 +91,15 @@ int fdset_kqueue_add(fdset_t *fdset, int fd, int events) return ret; } + /* Build mask. */ + int mask = 0; + if (events & OS_EV_READ) + mask |= EVFILT_READ; + if (events & OS_EV_WRITE) + mask |= EVFILT_WRITE; + /* Add to kqueue set. */ - int evfilt = EVFILT_READ; - EV_SET(&fdset->events[fdset->nfds], fd, evfilt, - EV_ADD|EV_ENABLE, 0, 0, 0); + EV_SET(&fdset->events[fdset->nfds], fd, mask, EV_ADD|EV_ENABLE, 0, 0, 0); memset(fdset->revents + fdset->nfds, 0, sizeof(struct kevent)); ++fdset->nfds; @@ -154,6 +159,27 @@ int fdset_kqueue_remove(fdset_t *fdset, int fd) return 0; } +int fdset_kqueue_set_events(fdset_t *fdset, int fd, int events) +{ + /* Build mask. */ + int mask = 0; + if (events & OS_EV_READ) + mask |= EVFILT_READ; + if (events & OS_EV_WRITE) + mask |= EVFILT_WRITE; + + /* Find in set. */ + struct kevent *evs = fdset->events; + for (int i = 0; i < fdset->nfds; ++i) { + if (evs[i].ident == fd) { + EV_SET(evs + i, fd, mask, EV_ADD|EV_ENABLE, 0, 0, 0); + return 0; + } + } + + return -1; +} + int fdset_kqueue_wait(fdset_t *fdset, int timeout) { if (fdset == NULL || fdset->nfds < 1 || fdset->events == NULL) { @@ -250,6 +276,7 @@ struct fdset_backend_t FDSET_KQUEUE = { .fdset_destroy = fdset_kqueue_destroy, .fdset_add = fdset_kqueue_add, .fdset_remove = fdset_kqueue_remove, + .fdset_set_events = fdset_kqueue_set_events, .fdset_wait = fdset_kqueue_wait, .fdset_begin = fdset_kqueue_begin, .fdset_end = fdset_kqueue_end, diff --git a/src/common/fdset_kqueue.h b/src/common/fdset_kqueue.h index 4b650a7b9..3d6d118c4 100644 --- a/src/common/fdset_kqueue.h +++ b/src/common/fdset_kqueue.h @@ -70,6 +70,17 @@ int fdset_kqueue_add(fdset_t *fdset, int fd, int events); */ int fdset_kqueue_remove(fdset_t *fdset, int fd); +/*! + * \brief Change descriptor watched events mask. + * + * \param fdset Target set. + * \param fd Related file descriptor. + * + * \retval 0 if successful. + * \retval -1 if not found. + */ +int fdset_kqueue_set_events(fdset_t *fdset, int fd, int events); + /*! * \brief Poll set for new events. * diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c index e16ae11e0..d2ea86a15 100644 --- a/src/common/fdset_poll.c +++ b/src/common/fdset_poll.c @@ -73,8 +73,15 @@ int fdset_poll_add(fdset_t *fdset, int fd, int events) /* Append. */ int nid = fdset->nfds++; fdset->fds[nid].fd = fd; - fdset->fds[nid].events = POLLIN; fdset->fds[nid].revents = 0; + + /* Build mask. */ + fdset->fds[nid].events = 0; + if (events & OS_EV_READ) + fdset->fds[nid].events |= POLLIN; + if (events & OS_EV_WRITE) + fdset->fds[nid].events |= POLLOUT; + return 0; } @@ -112,6 +119,23 @@ int fdset_poll_remove(fdset_t *fdset, int fd) return 0; } +int fdset_poll_set_events(fdset_t *fdset, int fd, int events) +{ + struct pollfd *pfd = fdset->fds; + for (size_t i = 0; i < fdset->nfds; ++i) { + if (pfd[i].fd == fd) { + pfd[i].events = 0; + if (events & OS_EV_READ) + pfd[i].events |= POLLIN; + if (events & OS_EV_WRITE) + pfd[i].events |= POLLOUT; + return 0; + } + } + + return -1; +} + int fdset_poll_wait(fdset_t *fdset, int timeout) { if (fdset == NULL || fdset->nfds < 1 || fdset->fds == NULL) { @@ -125,7 +149,7 @@ int fdset_poll_wait(fdset_t *fdset, int timeout) /* Poll for events. */ int ret = poll(fdset->fds, fdset->nfds, timeout); if (ret < 0) { - return -1; + return ret; } /* Set pointers for iterating. */ @@ -161,7 +185,7 @@ int fdset_poll_end(fdset_t *fdset, fdset_it_t *it) /* Trace last matching item from the end. */ struct pollfd* pfd = fdset->fds + fdset->nfds - 1; while (pfd != fdset->fds) { - if (pfd->events & pfd->revents) { + if (pfd->revents != 0) { it->fd = pfd->fd; it->pos = pfd - fdset->fds; return 0; @@ -183,7 +207,7 @@ int fdset_poll_next(fdset_t *fdset, fdset_it_t *it) /* Find next with matching flags. */ for (; it->pos < fdset->nfds; ++it->pos) { struct pollfd* pfd = fdset->fds + it->pos; - if (pfd->events & pfd->revents) { + if (pfd->revents != 0) { it->fd = pfd->fd; it->events = pfd->revents; ++it->pos; /* Next will start after current. */ @@ -208,6 +232,7 @@ struct fdset_backend_t FDSET_POLL = { .fdset_destroy = fdset_poll_destroy, .fdset_add = fdset_poll_add, .fdset_remove = fdset_poll_remove, + .fdset_set_events = fdset_poll_set_events, .fdset_wait = fdset_poll_wait, .fdset_begin = fdset_poll_begin, .fdset_end = fdset_poll_end, diff --git a/src/common/fdset_poll.h b/src/common/fdset_poll.h index 68e9e6909..4adc48670 100644 --- a/src/common/fdset_poll.h +++ b/src/common/fdset_poll.h @@ -70,6 +70,17 @@ int fdset_poll_add(fdset_t *fdset, int fd, int events); */ int fdset_poll_remove(fdset_t *fdset, int fd); +/*! + * \brief Change descriptor watched events mask. + * + * \param fdset Target set. + * \param fd Related file descriptor. + * + * \retval 0 if successful. + * \retval -1 if not found. + */ +int fdset_poll_set_events(fdset_t *fdset, int fd, int events); + /*! * \brief Poll set for new events. * -- GitLab