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
signaturebadge-question-mark 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 {
280280 }
281281
282282 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
283 defer {
284 os.close(self.err_pipe[0]);
285 os.close(self.err_pipe[1]);
286 }
287
288 // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
289 // waitpid, so this write is guaranteed to be after the child
290 // pid potentially wrote an error. This way we can do a blocking
291 // read on the error pipe and either get maxInt(ErrInt) (no error) or
292 // an error code.
293 try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
294 const err_int = try readIntFd(self.err_pipe[0]);
295 // Here we potentially return the fork child's error
296 // from the parent pid.
297 if (err_int != maxInt(ErrInt)) {
298 return @errSetCast(SpawnError, @intToError(err_int));
283 defer destroyPipe(self.err_pipe);
284
285 if (builtin.os == .linux) {
286 var fd = [1]std.os.pollfd{std.os.pollfd{
287 .fd = self.err_pipe[0],
288 .events = std.os.POLLIN,
289 .revents = undefined,
290 }};
291
292 // Check if the eventfd buffer stores a non-zero value by polling
293 // it, that's the error code returned by the child process.
294 _ = std.os.poll(&fd, 0) catch unreachable;
295
296 // According to eventfd(2) the descriptro is readable if the counter
297 // has a value greater than 0
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 }
299315 }
300316
301317 return statusToTerm(status);
......@@ -359,7 +375,16 @@ pub const ChildProcess = struct {
359375
360376 // This pipe is used to communicate errors between the time of fork
361377 // 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 };
363388 errdefer destroyPipe(err_pipe);
364389
365390 const pid_result = try os.fork();
......@@ -773,7 +798,7 @@ fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const
773798
774799fn destroyPipe(pipe: [2]os.fd_t) void {
775800 os.close(pipe[0]);
776 os.close(pipe[1]);
801 if (pipe[0] != pipe[1]) os.close(pipe[1]);
777802}
778803
779804// Child of fork calls this to report an error to the fork parent.
......@@ -787,12 +812,12 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
787812
788813fn writeIntFd(fd: i32, value: ErrInt) !void {
789814 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;
791816}
792817
793818fn readIntFd(fd: i32) !ErrInt {
794819 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);
796821}
797822
798823/// Caller must free result.