Skip to content

Commit

Permalink
unix: delay signal handling until after normal i/o
Browse files Browse the repository at this point in the history
It was reported that some node.js tests fail on AIX because the exit
event sometimes comes before the final stdio output of a child process.

Work around that by deferring the signal watcher that is used for
process management until after the dispatch of regular i/o watchers.

Fixes: #610
PR-URL: #611
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
  • Loading branch information
bnoordhuis committed Apr 15, 2016
1 parent 572d315 commit 4a5b3f9
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
17 changes: 16 additions & 1 deletion src/unix/aix.c
Expand Up @@ -118,6 +118,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
uv__io_t* w;
uint64_t base;
uint64_t diff;
int have_signals;
int nevents;
int count;
int nfds;
Expand Down Expand Up @@ -225,6 +226,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
goto update_timeout;
}

have_signals = 0;
nevents = 0;

assert(loop->watchers != NULL);
Expand Down Expand Up @@ -255,13 +257,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
continue;
}

w->cb(loop, w, pe->revents);
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
have_signals = 1;
else
w->cb(loop, w, pe->revents);

nevents++;
}

if (have_signals != 0)
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);

loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;

if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */

if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
Expand Down
18 changes: 17 additions & 1 deletion src/unix/kqueue.c
Expand Up @@ -78,6 +78,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
sigset_t set;
uint64_t base;
uint64_t diff;
int have_signals;
int filter;
int fflags;
int count;
Expand Down Expand Up @@ -192,6 +193,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
goto update_timeout;
}

have_signals = 0;
nevents = 0;

assert(loop->watchers != NULL);
Expand Down Expand Up @@ -265,12 +267,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (revents == 0)
continue;

w->cb(loop, w, revents);
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
have_signals = 1;
else
w->cb(loop, w, revents);

nevents++;
}

if (have_signals != 0)
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);

loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;

if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */

if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
Expand Down
18 changes: 17 additions & 1 deletion src/unix/linux-core.c
Expand Up @@ -188,6 +188,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
sigset_t sigset;
uint64_t sigmask;
uint64_t base;
int have_signals;
int nevents;
int count;
int nfds;
Expand Down Expand Up @@ -315,6 +316,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
goto update_timeout;
}

have_signals = 0;
nevents = 0;

assert(loop->watchers != NULL);
Expand Down Expand Up @@ -369,13 +371,27 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
pe->events |= w->pevents & (POLLIN | POLLOUT);

if (pe->events != 0) {
w->cb(loop, w, pe->events);
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
have_signals = 1;
else
w->cb(loop, w, pe->events);

nevents++;
}
}

if (have_signals != 0)
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);

loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;

if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */

if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
Expand Down
18 changes: 17 additions & 1 deletion src/unix/sunos.c
Expand Up @@ -140,6 +140,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
unsigned int nfds;
unsigned int i;
int saved_errno;
int have_signals;
int nevents;
int count;
int err;
Expand Down Expand Up @@ -230,6 +231,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
return;
}

have_signals = 0;
nevents = 0;

assert(loop->watchers != NULL);
Expand All @@ -252,7 +254,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (w == NULL)
continue;

w->cb(loop, w, pe->portev_events);
/* Run signal watchers last. This also affects child process watchers
* because those are implemented in terms of signal watchers.
*/
if (w == &loop->signal_io_watcher)
have_signals = 1;
else
w->cb(loop, w, pe->portev_events);

nevents++;

if (w != loop->watchers[fd])
Expand All @@ -262,9 +271,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
}

if (have_signals != 0)
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);

loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;

if (have_signals != 0)
return; /* Event loop should cycle now so don't poll again. */

if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */
Expand Down

0 comments on commit 4a5b3f9

Please sign in to comment.