aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-12-16 10:45:09 -0500
committerGitHub <noreply@github.com>2019-12-16 10:45:09 -0500
commit650acc5e3d50f8fae82bfb8bddf297d1927f40d4 (patch)
tree1dec8f0ebf41223a84ca251a6397886b61ed86cb /lib
parent2c7a2aefbfd0dbab190f912b4fbcbda96fb5ac44 (diff)
parent9d9b0720f52059a5b18fdf313cb80fca6379e54d (diff)
downloadzig-650acc5e3d50f8fae82bfb8bddf297d1927f40d4.tar.gz
zig-650acc5e3d50f8fae82bfb8bddf297d1927f40d4.zip
Merge pull request #3922 from LemonBoy/eventfd-err
More eventfd stuff
Diffstat (limited to 'lib')
-rw-r--r--lib/std/child_process.zig65
1 files changed, 45 insertions, 20 deletions
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 62b134bcf4..a76dfd3528 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -280,22 +280,38 @@ pub const ChildProcess = struct {
}
fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
- defer {
- os.close(self.err_pipe[0]);
- os.close(self.err_pipe[1]);
- }
-
- // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
- // waitpid, so this write is guaranteed to be after the child
- // pid potentially wrote an error. This way we can do a blocking
- // read on the error pipe and either get maxInt(ErrInt) (no error) or
- // an error code.
- try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
- const err_int = try readIntFd(self.err_pipe[0]);
- // Here we potentially return the fork child's error
- // from the parent pid.
- if (err_int != maxInt(ErrInt)) {
- return @errSetCast(SpawnError, @intToError(err_int));
+ defer destroyPipe(self.err_pipe);
+
+ if (builtin.os == .linux) {
+ var fd = [1]std.os.pollfd{std.os.pollfd{
+ .fd = self.err_pipe[0],
+ .events = std.os.POLLIN,
+ .revents = undefined,
+ }};
+
+ // Check if the eventfd buffer stores a non-zero value by polling
+ // it, that's the error code returned by the child process.
+ _ = std.os.poll(&fd, 0) catch unreachable;
+
+ // According to eventfd(2) the descriptro is readable if the counter
+ // has a value greater than 0
+ if ((fd[0].revents & std.os.POLLIN) != 0) {
+ const err_int = try readIntFd(self.err_pipe[0]);
+ return @errSetCast(SpawnError, @intToError(err_int));
+ }
+ } else {
+ // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
+ // waitpid, so this write is guaranteed to be after the child
+ // pid potentially wrote an error. This way we can do a blocking
+ // read on the error pipe and either get maxInt(ErrInt) (no error) or
+ // an error code.
+ try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
+ const err_int = try readIntFd(self.err_pipe[0]);
+ // Here we potentially return the fork child's error from the parent
+ // pid.
+ if (err_int != maxInt(ErrInt)) {
+ return @errSetCast(SpawnError, @intToError(err_int));
+ }
}
return statusToTerm(status);
@@ -359,7 +375,16 @@ pub const ChildProcess = struct {
// This pipe is used to communicate errors between the time of fork
// and execve from the child process to the parent process.
- const err_pipe = try os.pipe();
+ const err_pipe = blk: {
+ if (builtin.os == .linux) {
+ const fd = try os.eventfd(0, 0);
+ // There's no distinction between the readable and the writeable
+ // end with eventfd
+ break :blk [2]os.fd_t{ fd, fd };
+ } else {
+ break :blk try os.pipe();
+ }
+ };
errdefer destroyPipe(err_pipe);
const pid_result = try os.fork();
@@ -773,7 +798,7 @@ fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const
fn destroyPipe(pipe: [2]os.fd_t) void {
os.close(pipe[0]);
- os.close(pipe[1]);
+ if (pipe[0] != pipe[1]) os.close(pipe[1]);
}
// Child of fork calls this to report an error to the fork parent.
@@ -787,12 +812,12 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
fn writeIntFd(fd: i32, value: ErrInt) !void {
const stream = &File.openHandle(fd).outStream().stream;
- stream.writeIntNative(ErrInt, value) catch return error.SystemResources;
+ stream.writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources;
}
fn readIntFd(fd: i32) !ErrInt {
const stream = &File.openHandle(fd).inStream().stream;
- return stream.readIntNative(ErrInt) catch return error.SystemResources;
+ return @intCast(ErrInt, stream.readIntNative(u64) catch return error.SystemResources);
}
/// Caller must free result.