unix: delay signal handling until after normal i/o

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: https://github.com/libuv/libuv/issues/610
PR-URL: https://github.com/libuv/libuv/pull/611
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Ben Noordhuis 2015-11-07 00:26:44 +01:00
parent 572d31599f
commit 4a5b3f982e
4 changed files with 67 additions and 4 deletions

View File

@ -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;
@ -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);
@ -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. */

View File

@ -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;
@ -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);
@ -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. */

View File

@ -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;
@ -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);
@ -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. */

View File

@ -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;
@ -230,6 +231,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
return;
}
have_signals = 0;
nevents = 0;
assert(loop->watchers != NULL);
@ -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])
@ -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. */