Skip to content

Commit 67bb2b5

Browse files
committed
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: #162 Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
1 parent f2bb8d3 commit 67bb2b5

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

src/unix/linux-core.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,14 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
136136

137137

138138
void uv__io_poll(uv_loop_t* loop, int timeout) {
139+
static int no_epoll_pwait;
140+
static int no_epoll_wait;
139141
struct uv__epoll_event events[1024];
140142
struct uv__epoll_event* pe;
141143
struct uv__epoll_event e;
142144
QUEUE* q;
143145
uv__io_t* w;
146+
sigset_t sigset;
144147
uint64_t sigmask;
145148
uint64_t base;
146149
uint64_t diff;
@@ -150,7 +153,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
150153
int fd;
151154
int op;
152155
int i;
153-
static int no_epoll_wait;
154156

155157
if (loop->nfds == 0) {
156158
assert(QUEUE_EMPTY(&loop->watcher_queue));
@@ -193,31 +195,42 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
193195
}
194196

195197
sigmask = 0;
196-
if (loop->flags & UV_LOOP_BLOCK_SIGPROF)
198+
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
199+
sigemptyset(&sigset);
200+
sigaddset(&sigset, SIGPROF);
197201
sigmask |= 1 << (SIGPROF - 1);
202+
}
198203

199204
assert(timeout >= -1);
200205
base = loop->time;
201206
count = 48; /* Benchmarks suggest this gives the best throughput. */
202207

203208
for (;;) {
204-
if (no_epoll_wait || sigmask) {
209+
if (sigmask != 0 && no_epoll_pwait != 0)
210+
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
211+
abort();
212+
213+
if (sigmask != 0 && no_epoll_pwait == 0) {
205214
nfds = uv__epoll_pwait(loop->backend_fd,
206215
events,
207216
ARRAY_SIZE(events),
208217
timeout,
209218
sigmask);
219+
if (nfds == -1 && errno == ENOSYS)
220+
no_epoll_pwait = 1;
210221
} else {
211222
nfds = uv__epoll_wait(loop->backend_fd,
212223
events,
213224
ARRAY_SIZE(events),
214225
timeout);
215-
if (nfds == -1 && errno == ENOSYS) {
226+
if (nfds == -1 && errno == ENOSYS)
216227
no_epoll_wait = 1;
217-
continue;
218-
}
219228
}
220229

230+
if (sigmask != 0 && no_epoll_pwait != 0)
231+
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
232+
abort();
233+
221234
/* Update loop->time unconditionally. It's tempting to skip the update when
222235
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
223236
* 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) {
230243
}
231244

232245
if (nfds == -1) {
246+
if (errno == ENOSYS) {
247+
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
248+
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
249+
continue;
250+
}
251+
233252
if (errno != EINTR)
234253
abort();
235254

0 commit comments

Comments
 (0)