linux: fix epoll_pwait() regression with < 2.6.19
Linux before kernel 2.6.19 does not support epoll_pwait(). Due to a
logic error in commit 2daf944 ("unix: add flag for blocking SIGPROF
during poll"), the fallback path for ENOSYS was not taken.
This commit also adds epoll_pwait() emulation using pthread_sigmask().
The block/unblock operations are not atomic but that is fine for our
particular use case, to wit, sleep through SIGPROF signals.
PR-URL: https://github.com/libuv/libuv/pull/162
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
parent
f2bb8d394c
commit
67bb2b5f70
@ -136,11 +136,14 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
|||||||
|
|
||||||
|
|
||||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||||
|
static int no_epoll_pwait;
|
||||||
|
static int no_epoll_wait;
|
||||||
struct uv__epoll_event events[1024];
|
struct uv__epoll_event events[1024];
|
||||||
struct uv__epoll_event* pe;
|
struct uv__epoll_event* pe;
|
||||||
struct uv__epoll_event e;
|
struct uv__epoll_event e;
|
||||||
QUEUE* q;
|
QUEUE* q;
|
||||||
uv__io_t* w;
|
uv__io_t* w;
|
||||||
|
sigset_t sigset;
|
||||||
uint64_t sigmask;
|
uint64_t sigmask;
|
||||||
uint64_t base;
|
uint64_t base;
|
||||||
uint64_t diff;
|
uint64_t diff;
|
||||||
@ -150,7 +153,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||||||
int fd;
|
int fd;
|
||||||
int op;
|
int op;
|
||||||
int i;
|
int i;
|
||||||
static int no_epoll_wait;
|
|
||||||
|
|
||||||
if (loop->nfds == 0) {
|
if (loop->nfds == 0) {
|
||||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||||
@ -193,31 +195,42 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sigmask = 0;
|
sigmask = 0;
|
||||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF)
|
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||||
|
sigemptyset(&sigset);
|
||||||
|
sigaddset(&sigset, SIGPROF);
|
||||||
sigmask |= 1 << (SIGPROF - 1);
|
sigmask |= 1 << (SIGPROF - 1);
|
||||||
|
}
|
||||||
|
|
||||||
assert(timeout >= -1);
|
assert(timeout >= -1);
|
||||||
base = loop->time;
|
base = loop->time;
|
||||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (no_epoll_wait || sigmask) {
|
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||||
|
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
|
||||||
|
abort();
|
||||||
|
|
||||||
|
if (sigmask != 0 && no_epoll_pwait == 0) {
|
||||||
nfds = uv__epoll_pwait(loop->backend_fd,
|
nfds = uv__epoll_pwait(loop->backend_fd,
|
||||||
events,
|
events,
|
||||||
ARRAY_SIZE(events),
|
ARRAY_SIZE(events),
|
||||||
timeout,
|
timeout,
|
||||||
sigmask);
|
sigmask);
|
||||||
|
if (nfds == -1 && errno == ENOSYS)
|
||||||
|
no_epoll_pwait = 1;
|
||||||
} else {
|
} else {
|
||||||
nfds = uv__epoll_wait(loop->backend_fd,
|
nfds = uv__epoll_wait(loop->backend_fd,
|
||||||
events,
|
events,
|
||||||
ARRAY_SIZE(events),
|
ARRAY_SIZE(events),
|
||||||
timeout);
|
timeout);
|
||||||
if (nfds == -1 && errno == ENOSYS) {
|
if (nfds == -1 && errno == ENOSYS)
|
||||||
no_epoll_wait = 1;
|
no_epoll_wait = 1;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||||
|
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
|
||||||
|
abort();
|
||||||
|
|
||||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||||
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
||||||
* operating system didn't reschedule our process while in the syscall.
|
* operating system didn't reschedule our process while in the syscall.
|
||||||
@ -230,6 +243,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nfds == -1) {
|
if (nfds == -1) {
|
||||||
|
if (errno == ENOSYS) {
|
||||||
|
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
|
||||||
|
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
abort();
|
abort();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user