| ... | ... | @@ -203,16 +203,18 @@ pub const ChildProcess = struct { |
| 203 | 203 | // of space an ArrayList will allocate grows exponentially. |
| 204 | 204 | const bump_amt = 512; |
| 205 | 205 | |
| 206 | | // TODO https://github.com/ziglang/zig/issues/8724 |
| 207 | | // parent process does not receive POLLHUP events |
| 208 | | const dragonfly_workaround = builtin.os.tag == .dragonfly; |
| 206 | const err_mask = os.POLLERR | os.POLLNVAL | os.POLLHUP; |
| 209 | 207 | |
| 210 | 208 | while (dead_fds < poll_fds.len) { |
| 211 | 209 | const events = try os.poll(&poll_fds, std.math.maxInt(i32)); |
| 212 | 210 | if (events == 0) continue; |
| 213 | 211 | |
| 212 | var remove_stdout = false; |
| 213 | var remove_stderr = false; |
| 214 | 214 | // Try reading whatever is available before checking the error |
| 215 | 215 | // conditions. |
| 216 | // It's still possible to read after a POLLHUP is received, always |
| 217 | // check if there's some data waiting to be read first. |
| 216 | 218 | if (poll_fds[0].revents & os.POLLIN != 0) { |
| 217 | 219 | // stdout is ready. |
| 218 | 220 | const new_capacity = std.math.min(stdout.items.len + bump_amt, max_output_bytes); |
| ... | ... | @@ -222,9 +224,12 @@ pub const ChildProcess = struct { |
| 222 | 224 | const nread = try os.read(poll_fds[0].fd, buf); |
| 223 | 225 | stdout.items.len += nread; |
| 224 | 226 | |
| 225 | | // insert POLLHUP event because dragonfly fails to do so |
| 226 | | if (dragonfly_workaround and nread == 0) poll_fds[0].revents |= os.POLLHUP; |
| 227 | // Remove the fd when the EOF condition is met. |
| 228 | remove_stdout = nread == 0; |
| 229 | } else { |
| 230 | remove_stdout = poll_fds[0].revents & err_mask != 0; |
| 227 | 231 | } |
| 232 | |
| 228 | 233 | if (poll_fds[1].revents & os.POLLIN != 0) { |
| 229 | 234 | // stderr is ready. |
| 230 | 235 | const new_capacity = std.math.min(stderr.items.len + bump_amt, max_output_bytes); |
| ... | ... | @@ -234,16 +239,18 @@ pub const ChildProcess = struct { |
| 234 | 239 | const nread = try os.read(poll_fds[1].fd, buf); |
| 235 | 240 | stderr.items.len += nread; |
| 236 | 241 | |
| 237 | | // insert POLLHUP event because dragonfly fails to do so |
| 238 | | if (dragonfly_workaround and nread == 0) poll_fds[1].revents |= os.POLLHUP; |
| 242 | // Remove the fd when the EOF condition is met. |
| 243 | remove_stderr = nread == 0; |
| 244 | } else { |
| 245 | remove_stderr = poll_fds[1].revents & err_mask != 0; |
| 239 | 246 | } |
| 240 | 247 | |
| 241 | 248 | // Exclude the fds that signaled an error. |
| 242 | | if (poll_fds[0].revents & (os.POLLERR | os.POLLNVAL | os.POLLHUP) != 0) { |
| 249 | if (remove_stdout) { |
| 243 | 250 | poll_fds[0].fd = -1; |
| 244 | 251 | dead_fds += 1; |
| 245 | 252 | } |
| 246 | | if (poll_fds[1].revents & (os.POLLERR | os.POLLNVAL | os.POLLHUP) != 0) { |
| 253 | if (remove_stderr) { |
| 247 | 254 | poll_fds[1].fd = -1; |
| 248 | 255 | dead_fds += 1; |
| 249 | 256 | } |
| ... | ... | @@ -294,6 +301,10 @@ pub const ChildProcess = struct { |
| 294 | 301 | |
| 295 | 302 | var stdout = std.ArrayList(u8).init(args.allocator); |
| 296 | 303 | var stderr = std.ArrayList(u8).init(args.allocator); |
| 304 | errdefer { |
| 305 | stdout.deinit(); |
| 306 | stderr.deinit(); |
| 307 | } |
| 297 | 308 | |
| 298 | 309 | try collectOutputPosix(child, &stdout, &stderr, args.max_output_bytes); |
| 299 | 310 | |