mirror of
https://github.com/troglobit/libuev.git
synced 2026-10-13 10:04:41 +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() */
|
||||
uint32_t errors;
|
||||
LIST_HEAD(,uev) watchers;
|
||||
uint32_t workaround; /* For workarounds, e.g. redirected stdin */
|
||||
} uev_ctx_t;
|
||||
|
||||
/* Forward declare due to dependencys, don't try this at home kids. */
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <fcntl.h> /* O_CLOEXEC */
|
||||
#include <string.h> /* memset() */
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/select.h> /* for select() workaround */
|
||||
#include <sys/signalfd.h> /* struct signalfd_siginfo */
|
||||
#include <unistd.h> /* close(), read() */
|
||||
|
||||
@@ -56,6 +57,18 @@ static int is_valid_fd(int fd)
|
||||
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! */
|
||||
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.data.ptr = w;
|
||||
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
|
||||
return -1;
|
||||
if (epoll_ctl(w->ctx->fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
|
||||
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 */
|
||||
LIST_INSERT_HEAD(&w->ctx->watchers, w, link);
|
||||
@@ -254,9 +280,30 @@ int uev_run(uev_ctx_t *ctx, int flags)
|
||||
}
|
||||
|
||||
while (ctx->running) {
|
||||
int i, nfds;
|
||||
int i, nfds, rerun = 0;
|
||||
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) {
|
||||
if (!ctx->running)
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user