aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nix-worker/main.cc32
1 files changed, 30 insertions, 2 deletions
diff --git a/src/nix-worker/main.cc b/src/nix-worker/main.cc
index c4a2d8a7a..666f61572 100644
--- a/src/nix-worker/main.cc
+++ b/src/nix-worker/main.cc
@@ -76,7 +76,34 @@ static void startWork()
canSendStderr = true;
/* Handle client death asynchronously. */
- signal(SIGIO, sigioHandler);
+ if (signal(SIGIO, sigioHandler) == SIG_ERR)
+ throw SysError("setting handler for SIGIO");
+
+ /* Of course, there is a race condition here: the socket could
+ have closed between when we last read from / wrote to it, and
+ between the time we set the handler for SIGIO. In that case we
+ won't get the signal. So do a non-blocking select() to find
+ out if any input is available on the socket. If there is, it
+ has to be the 0-byte read that indicates that the socket has
+ closed. */
+
+ struct timeval timeout;
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+
+ if (select(STDIN_FILENO + 1, &fds, 0, 0, &timeout) == -1)
+ throw SysError("select()");
+
+ if (FD_ISSET(STDIN_FILENO, &fds)) {
+ char c;
+ if (read(STDIN_FILENO, &c, 1) != 0)
+ throw Error("EOF expected (protocol error?)");
+ _isInterrupted = 1;
+ checkInterrupt();
+ }
}
@@ -87,7 +114,8 @@ static void stopWork()
/* Stop handling async client death; we're going to a state where
we're either sending or receiving from the client, so we'll be
notified of client death anyway. */
- signal(SIGIO, SIG_IGN);
+ if (signal(SIGIO, SIG_IGN) == SIG_ERR)
+ throw SysError("ignoring SIGIO");
canSendStderr = false;
writeInt(STDERR_LAST, *_to);