| ... | @@ -282,17 +282,36 @@ pub const ChildProcess = struct { | ... | @@ -282,17 +282,36 @@ pub const ChildProcess = struct { |
| 282 | fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term { | 282 | fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term { |
| 283 | defer destroyPipe(self.err_pipe); | 283 | defer destroyPipe(self.err_pipe); |
| 284 | | 284 | |
| 285 | // Write maxInt(ErrInt) to the write end of the err_pipe. This is after | 285 | if (builtin.os == .linux) { |
| 286 | // waitpid, so this write is guaranteed to be after the child | 286 | var fd = [1]std.os.pollfd{std.os.pollfd{ |
| 287 | // pid potentially wrote an error. This way we can do a blocking | 287 | .fd = self.err_pipe[0], |
| 288 | // read on the error pipe and either get maxInt(ErrInt) (no error) or | 288 | .events = std.os.POLLIN, |
| 289 | // an error code. | 289 | .revents = undefined, |
| 290 | try writeIntFd(self.err_pipe[1], maxInt(ErrInt)); | 290 | }}; |
| 291 | const err_int = try readIntFd(self.err_pipe[0]); | 291 | |
| 292 | // Here we potentially return the fork child's error | 292 | // Check if the eventfd buffer stores a non-zero value by polling |
| 293 | // from the parent pid. | 293 | // it, that's the error code returned by the child process. |
| 294 | if (err_int != maxInt(ErrInt)) { | 294 | _ = std.os.poll(&fd, 0) catch unreachable; |
| 295 | return @errSetCast(SpawnError, @intToError(err_int)); | 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 | } |
| 296 | } | 315 | } |
| 297 | | 316 | |
| 298 | return statusToTerm(status); | 317 | return statusToTerm(status); |