| ... | @@ -12790,9 +12790,15 @@ fn processSpawnUnsupported(userdata: ?*anyopaque, options: process.SpawnOptions) | ... | @@ -12790,9 +12790,15 @@ fn processSpawnUnsupported(userdata: ?*anyopaque, options: process.SpawnOptions) |
| 12790 | return error.Unexpected; | 12790 | return error.Unexpected; |
| 12791 | } | 12791 | } |
| 12792 | | 12792 | |
| 12793 | fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child { | 12793 | const Spawned = struct { |
| 12794 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 12794 | pid: posix.pid_t, |
| | 12795 | err_fd: posix.fd_t, |
| | 12796 | stdin: ?File, |
| | 12797 | stdout: ?File, |
| | 12798 | stderr: ?File, |
| | 12799 | }; |
| 12795 | | 12800 | |
| | 12801 | fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Spawned { |
| 12796 | // The child process does need to access (one end of) these pipes. However, | 12802 | // The child process does need to access (one end of) these pipes. However, |
| 12797 | // we must initially set CLOEXEC to avoid a race condition. If another thread | 12803 | // we must initially set CLOEXEC to avoid a race condition. If another thread |
| 12798 | // is racing to spawn a different child process, we don't want it to inherit | 12804 | // is racing to spawn a different child process, we don't want it to inherit |
| ... | @@ -12947,9 +12953,9 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce | ... | @@ -12947,9 +12953,9 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce |
| 12947 | } | 12953 | } |
| 12948 | | 12954 | |
| 12949 | const pid: posix.pid_t = @intCast(pid_result); // We are the parent. | 12955 | const pid: posix.pid_t = @intCast(pid_result); // We are the parent. |
| | 12956 | errdefer comptime unreachable; // The child is forked; we must not error from now on |
| 12950 | | 12957 | |
| 12951 | posix.close(err_pipe[1]); // make sure only the child holds the write end open | 12958 | posix.close(err_pipe[1]); // make sure only the child holds the write end open |
| 12952 | defer posix.close(err_pipe[0]); | | |
| 12953 | | 12959 | |
| 12954 | if (options.stdin == .pipe) posix.close(stdin_pipe[0]); | 12960 | if (options.stdin == .pipe) posix.close(stdin_pipe[0]); |
| 12955 | if (options.stdout == .pipe) posix.close(stdout_pipe[1]); | 12961 | if (options.stdout == .pipe) posix.close(stdout_pipe[1]); |
| ... | @@ -12959,8 +12965,31 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce | ... | @@ -12959,8 +12965,31 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce |
| 12959 | | 12965 | |
| 12960 | options.progress_node.setIpcFd(prog_pipe[0]); | 12966 | options.progress_node.setIpcFd(prog_pipe[0]); |
| 12961 | | 12967 | |
| | 12968 | return .{ |
| | 12969 | .pid = pid, |
| | 12970 | .err_fd = err_pipe[0], |
| | 12971 | .stdin = switch (options.stdin) { |
| | 12972 | .pipe => .{ .handle = stdin_pipe[1] }, |
| | 12973 | else => null, |
| | 12974 | }, |
| | 12975 | .stdout = switch (options.stdout) { |
| | 12976 | .pipe => .{ .handle = stdout_pipe[0] }, |
| | 12977 | else => null, |
| | 12978 | }, |
| | 12979 | .stderr = switch (options.stderr) { |
| | 12980 | .pipe => .{ .handle = stderr_pipe[0] }, |
| | 12981 | else => null, |
| | 12982 | }, |
| | 12983 | }; |
| | 12984 | } |
| | 12985 | |
| | 12986 | fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child { |
| | 12987 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| | 12988 | const spawned = try spawnPosix(t, options); |
| | 12989 | defer posix.close(spawned.err_fd); |
| | 12990 | |
| 12962 | // Wait for the child to report any errors in or before `execvpe`. | 12991 | // Wait for the child to report any errors in or before `execvpe`. |
| 12963 | if (readIntFd(t, err_pipe[0])) |child_err_int| { | 12992 | if (readIntFd(t, spawned.err_fd)) |child_err_int| { |
| 12964 | const child_err: process.SpawnError = @errorCast(@errorFromInt(child_err_int)); | 12993 | const child_err: process.SpawnError = @errorCast(@errorFromInt(child_err_int)); |
| 12965 | return child_err; | 12994 | return child_err; |
| 12966 | } else |read_err| switch (read_err) { | 12995 | } else |read_err| switch (read_err) { |
| ... | @@ -12976,20 +13005,11 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce | ... | @@ -12976,20 +13005,11 @@ fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) proce |
| 12976 | } | 13005 | } |
| 12977 | | 13006 | |
| 12978 | return .{ | 13007 | return .{ |
| 12979 | .id = pid, | 13008 | .id = spawned.pid, |
| 12980 | .thread_handle = {}, | 13009 | .thread_handle = {}, |
| 12981 | .stdin = switch (options.stdin) { | 13010 | .stdin = spawned.stdin, |
| 12982 | .pipe => .{ .handle = stdin_pipe[1] }, | 13011 | .stdout = spawned.stdout, |
| 12983 | else => null, | 13012 | .stderr = spawned.stderr, |
| 12984 | }, | | |
| 12985 | .stdout = switch (options.stdout) { | | |
| 12986 | .pipe => .{ .handle = stdout_pipe[0] }, | | |
| 12987 | else => null, | | |
| 12988 | }, | | |
| 12989 | .stderr = switch (options.stderr) { | | |
| 12990 | .pipe => .{ .handle = stderr_pipe[0] }, | | |
| 12991 | else => null, | | |
| 12992 | }, | | |
| 12993 | .request_resource_usage_statistics = options.request_resource_usage_statistics, | 13013 | .request_resource_usage_statistics = options.request_resource_usage_statistics, |
| 12994 | }; | 13014 | }; |
| 12995 | } | 13015 | } |
| ... | @@ -13156,10 +13176,13 @@ fn forkBail(fd: posix.fd_t, err: ForkBailError) noreturn { | ... | @@ -13156,10 +13176,13 @@ fn forkBail(fd: posix.fd_t, err: ForkBailError) noreturn { |
| 13156 | // it caused a deadlock instead of doing an exit syscall. In the words of Avril Lavigne, | 13176 | // it caused a deadlock instead of doing an exit syscall. In the words of Avril Lavigne, |
| 13157 | // "Why'd you have to go and make things so complicated?" | 13177 | // "Why'd you have to go and make things so complicated?" |
| 13158 | if (builtin.link_libc) { | 13178 | if (builtin.link_libc) { |
| 13159 | // The _exit(2) function does nothing but make the exit syscall, unlike exit(3) | 13179 | // The `_exit` function does nothing but make the exit syscall, unlike `exit`. |
| 13160 | std.c._exit(1); | 13180 | std.c._exit(1); |
| | 13181 | } else if (native_os == .linux and !builtin.single_threaded) { |
| | 13182 | std.os.linux.exit_group(1); |
| | 13183 | } else { |
| | 13184 | posix.system.exit(1); |
| 13161 | } | 13185 | } |
| 13162 | posix.system.exit(1); | | |
| 13163 | } | 13186 | } |
| 13164 | | 13187 | |
| 13165 | fn writeIntFd(fd: posix.fd_t, value: ErrInt) !void { | 13188 | fn writeIntFd(fd: posix.fd_t, value: ErrInt) !void { |
| ... | @@ -13190,7 +13213,7 @@ fn readIntFd(t: *Threaded, fd: posix.fd_t) !ErrInt { | ... | @@ -13190,7 +13213,7 @@ fn readIntFd(t: *Threaded, fd: posix.fd_t) !ErrInt { |
| 13190 | switch (posix.errno(rc)) { | 13213 | switch (posix.errno(rc)) { |
| 13191 | .SUCCESS => { | 13214 | .SUCCESS => { |
| 13192 | const n: usize = @intCast(rc); | 13215 | const n: usize = @intCast(rc); |
| 13193 | if (n == 0) return error.EndOfStream; | 13216 | if (n == 0) break; |
| 13194 | i += n; | 13217 | i += n; |
| 13195 | continue; | 13218 | continue; |
| 13196 | }, | 13219 | }, |
| ... | @@ -13198,6 +13221,7 @@ fn readIntFd(t: *Threaded, fd: posix.fd_t) !ErrInt { | ... | @@ -13198,6 +13221,7 @@ fn readIntFd(t: *Threaded, fd: posix.fd_t) !ErrInt { |
| 13198 | else => |err| return posix.unexpectedErrno(err), | 13221 | else => |err| return posix.unexpectedErrno(err), |
| 13199 | } | 13222 | } |
| 13200 | } | 13223 | } |
| | 13224 | if (buffer.len - i != 0) return error.EndOfStream; |
| 13201 | return @intCast(std.mem.readInt(u64, &buffer, .little)); | 13225 | return @intCast(std.mem.readInt(u64, &buffer, .little)); |
| 13202 | } | 13226 | } |
| 13203 | | 13227 | |
| ... | @@ -14371,9 +14395,9 @@ pub fn execvpeZ( | ... | @@ -14371,9 +14395,9 @@ pub fn execvpeZ( |
| 14371 | file: [*:0]const u8, | 14395 | file: [*:0]const u8, |
| 14372 | argv_ptr: [*:null]const ?[*:0]const u8, | 14396 | argv_ptr: [*:null]const ?[*:0]const u8, |
| 14373 | envp: [*:null]const ?[*:0]const u8, | 14397 | envp: [*:null]const ?[*:0]const u8, |
| 14374 | optional_PATH: ?[]const u8, | 14398 | PATH: []const u8, |
| 14375 | ) process.ReplaceError { | 14399 | ) process.ReplaceError { |
| 14376 | return execvpeZ_expandArg0(.no_expand, file, argv_ptr, envp, optional_PATH); | 14400 | return execvpeZ_expandArg0(.no_expand, file, argv_ptr, envp, PATH); |
| 14377 | } | 14401 | } |
| 14378 | | 14402 | |
| 14379 | fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void { | 14403 | fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void { |