authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-16 10:45:09-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-12-16 10:45:09-05:00
log650acc5e3d50f8fae82bfb8bddf297d1927f40d4
tree1dec8f0ebf41223a84ca251a6397886b61ed86cb
parent2c7a2aefbfd0dbab190f912b4fbcbda96fb5ac44
parent9d9b0720f52059a5b18fdf313cb80fca6379e54d
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3922 from LemonBoy/eventfd-err

More eventfd stuff

1 files changed, 45 insertions(+), 20 deletions(-)

lib/std/child_process.zig+45-20
...@@ -280,22 +280,38 @@ pub const ChildProcess = struct {...@@ -280,22 +280,38 @@ pub const ChildProcess = struct {
280 }280 }
281281
282 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {282 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
283 defer {283 defer destroyPipe(self.err_pipe);
284 os.close(self.err_pipe[0]);284
285 os.close(self.err_pipe[1]);285 if (builtin.os == .linux) {
286 }286 var fd = [1]std.os.pollfd{std.os.pollfd{
287287 .fd = self.err_pipe[0],
288 // Write maxInt(ErrInt) to the write end of the err_pipe. This is after288 .events = std.os.POLLIN,
289 // waitpid, so this write is guaranteed to be after the child289 .revents = undefined,
290 // pid potentially wrote an error. This way we can do a blocking290 }};
291 // read on the error pipe and either get maxInt(ErrInt) (no error) or291
292 // an error code.292 // Check if the eventfd buffer stores a non-zero value by polling
293 try writeIntFd(self.err_pipe[1], maxInt(ErrInt));293 // it, that's the error code returned by the child process.
294 const err_int = try readIntFd(self.err_pipe[0]);294 _ = std.os.poll(&fd, 0) catch unreachable;
295 // Here we potentially return the fork child's error295
296 // from the parent pid.296 // According to eventfd(2) the descriptro is readable if the counter
297 if (err_int != maxInt(ErrInt)) {297 // has a value greater than 0
298 return @errSetCast(SpawnError, @intToError(err_int));298 if ((fd[0].revents & std.os.POLLIN) != 0) {
299 const err_int = try readIntFd(self.err_pipe[0]);
300 return @errSetCast(SpawnError, @intToError(err_int));
301 }
302 } else {
303 // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
304 // waitpid, so this write is guaranteed to be after the child
305 // pid potentially wrote an error. This way we can do a blocking
306 // read on the error pipe and either get maxInt(ErrInt) (no error) or
307 // an error code.
308 try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
309 const err_int = try readIntFd(self.err_pipe[0]);
310 // Here we potentially return the fork child's error from the parent
311 // pid.
312 if (err_int != maxInt(ErrInt)) {
313 return @errSetCast(SpawnError, @intToError(err_int));
314 }
299 }315 }
300316
301 return statusToTerm(status);317 return statusToTerm(status);
...@@ -359,7 +375,16 @@ pub const ChildProcess = struct {...@@ -359,7 +375,16 @@ pub const ChildProcess = struct {
359375
360 // This pipe is used to communicate errors between the time of fork376 // This pipe is used to communicate errors between the time of fork
361 // and execve from the child process to the parent process.377 // and execve from the child process to the parent process.
362 const err_pipe = try os.pipe();378 const err_pipe = blk: {
379 if (builtin.os == .linux) {
380 const fd = try os.eventfd(0, 0);
381 // There's no distinction between the readable and the writeable
382 // end with eventfd
383 break :blk [2]os.fd_t{ fd, fd };
384 } else {
385 break :blk try os.pipe();
386 }
387 };
363 errdefer destroyPipe(err_pipe);388 errdefer destroyPipe(err_pipe);
364389
365 const pid_result = try os.fork();390 const pid_result = try os.fork();
...@@ -773,7 +798,7 @@ fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const...@@ -773,7 +798,7 @@ fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const
773798
774fn destroyPipe(pipe: [2]os.fd_t) void {799fn destroyPipe(pipe: [2]os.fd_t) void {
775 os.close(pipe[0]);800 os.close(pipe[0]);
776 os.close(pipe[1]);801 if (pipe[0] != pipe[1]) os.close(pipe[1]);
777}802}
778803
779// Child of fork calls this to report an error to the fork parent.804// Child of fork calls this to report an error to the fork parent.
...@@ -787,12 +812,12 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);...@@ -787,12 +812,12 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
787812
788fn writeIntFd(fd: i32, value: ErrInt) !void {813fn writeIntFd(fd: i32, value: ErrInt) !void {
789 const stream = &File.openHandle(fd).outStream().stream;814 const stream = &File.openHandle(fd).outStream().stream;
790 stream.writeIntNative(ErrInt, value) catch return error.SystemResources;815 stream.writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources;
791}816}
792817
793fn readIntFd(fd: i32) !ErrInt {818fn readIntFd(fd: i32) !ErrInt {
794 const stream = &File.openHandle(fd).inStream().stream;819 const stream = &File.openHandle(fd).inStream().stream;
795 return stream.readIntNative(ErrInt) catch return error.SystemResources;820 return @intCast(ErrInt, stream.readIntNative(u64) catch return error.SystemResources);
796}821}
797822
798/// Caller must free result.823/// Caller must free result.