mirror of
https://github.com/troglobit/libuev.git
synced 2026-11-12 16:51:07 +00:00
Fix #12: Implement workaround for application < foo.txt
This patch implements a workaround for issue #12, i.e. when an I/O watcher for redirected stdin is registered and causes epoll_ctl() to return EPERM. The workaround registers the watcher as `active = -1` and bypasses the epoll_wait() call in the main loop until all data has been read from stdin and the temporary -1 watcher(s) have completed. Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
82a1018dd2
commit
e0cebc33b1
2 files changed
+52
-4
No files matched your search
@@ -46,6 +46,7 @@ typedef struct {
|
|||||||
int fd; /* For epoll() */
|
int fd; /* For epoll() */
|
||||||
uint32_t errors;
|
uint32_t errors;
|
||||||
LIST_HEAD(,uev) watchers;
|
LIST_HEAD(,uev) watchers;
|
||||||
|
uint32_t workaround; /* For workarounds, e.g. redirected stdin */
|
||||||
} uev_ctx_t;
|
} uev_ctx_t;
|
||||||
|
|
||||||
/* Forward declare due to dependencys, don't try this at home kids. */
|
/* Forward declare due to dependencys, don't try this at home kids. */
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <fcntl.h> /* O_CLOEXEC */
|
#include <fcntl.h> /* O_CLOEXEC */
|
||||||
#include <string.h> /* memset() */
|
#include <string.h> /* memset() */
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/select.h> /* for select() workaround */
|
||||||
#include <sys/signalfd.h> /* struct signalfd_siginfo */
|
#include <sys/signalfd.h> /* struct signalfd_siginfo */
|
||||||
#include <unistd.h> /* close(), read() */
|
#include <unistd.h> /* close(), read() */
|
||||||
|
|
||||||
@@ -56,6 +57,18 @@ static int is_valid_fd(int fd)
|
|||||||
return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
|
return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Used by file i/o workaround when epoll => EPERM */
|
||||||
|
static int has_data(int fd)
|
||||||
|
{
|
||||||
|
struct timeval timeout = { 0, 0 };
|
||||||
|
fd_set fds;
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
|
||||||
|
return select(1, &fds, NULL, NULL, &timeout) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Private to libuEv, do not use directly! */
|
/* Private to libuEv, do not use directly! */
|
||||||
int _uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, void *arg, int fd, int events)
|
int _uev_watcher_init(uev_ctx_t *ctx, uev_t *w, uev_type_t type, uev_cb_t *cb, void *arg, int fd, int events)
|
||||||
{
|
{
|
||||||
@@ -90,10 +103,23 @@ int _uev_watcher_start(uev_t *w)
|
|||||||
|
|
||||||
ev.events = w->events | EPOLLRDHUP;
|
ev.events = w->events | EPOLLRDHUP;
|
||||||
ev.data.ptr = w;
|
ev.data.ptr = w;
|
||||||
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
|
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
|
||||||
return -1;
|
if (errno != EPERM)
|
||||||
|
return -1;
|
||||||
|
|
||||||
w->active = 1;
|
/* Handle special case: `application < file.txt` */
|
||||||
|
if (w->type != UEV_IO_TYPE || w->events != UEV_READ)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Only allow this special handling for stdin */
|
||||||
|
if (w->fd != STDIN_FILENO)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
w->ctx->workaround = 1;
|
||||||
|
w->active = -1;
|
||||||
|
} else {
|
||||||
|
w->active = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add to internal list for bookkeeping */
|
/* Add to internal list for bookkeeping */
|
||||||
LIST_INSERT_HEAD(&w->ctx->watchers, w, link);
|
LIST_INSERT_HEAD(&w->ctx->watchers, w, link);
|
||||||
@@ -254,9 +280,30 @@ int uev_run(uev_ctx_t *ctx, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (ctx->running) {
|
while (ctx->running) {
|
||||||
int i, nfds;
|
int i, nfds, rerun = 0;
|
||||||
struct epoll_event events[UEV_MAX_EVENTS];
|
struct epoll_event events[UEV_MAX_EVENTS];
|
||||||
|
|
||||||
|
/* Handle special case: `application < file.txt` */
|
||||||
|
if (ctx->workaround) {
|
||||||
|
LIST_FOREACH(w, &ctx->watchers, link) {
|
||||||
|
if (w->active != -1 || !w->cb)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!has_data(w->fd)) {
|
||||||
|
w->active = 0;
|
||||||
|
LIST_REMOVE(w, link);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rerun++;
|
||||||
|
w->cb(w, w->arg, UEV_READ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rerun)
|
||||||
|
continue;
|
||||||
|
ctx->workaround = 0;
|
||||||
|
|
||||||
while ((nfds = epoll_wait(ctx->fd, events, UEV_MAX_EVENTS, timeout)) < 0) {
|
while ((nfds = epoll_wait(ctx->fd, events, UEV_MAX_EVENTS, timeout)) < 0) {
|
||||||
if (!ctx->running)
|
if (!ctx->running)
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in new issue
Block a user