| 1165 | } |
| 1166 | |
| 1167 | static cbm_proc_poll_t cbm_subprocess_poll_posix(cbm_subprocess_t *process, |
| 1168 | cbm_proc_result_t *out) { |
| 1169 | uint64_t now = cbm_now_ms(); |
| 1170 | |
| 1171 | if (!process->root_reaped) { |
| 1172 | int status = 0; |
| 1173 | pid_t waited = waitpid(process->pid, &status, WNOHANG); |
| 1174 | if (waited == process->pid) { |
| 1175 | cbm_posix_capture_root(process, status); |
| 1176 | } else if (waited < 0 && errno != EINTR) { |
| 1177 | /* ECHILD means another reaper consumed the status. Other permanent |
| 1178 | * wait failures are treated the same: retain containment, stop the |
| 1179 | * tree, and never spin forever on the failed wait operation. */ |
| 1180 | process->root_reaped = true; |
| 1181 | process->result.outcome = process->timed_out ? CBM_PROC_HANG : CBM_PROC_KILLED; |
| 1182 | process->result.exit_code = -1; |
| 1183 | process->result.term_signal = 0; |
| 1184 | cbm_posix_begin_termination(process, now); |
| 1185 | } |
| 1186 | } |
| 1187 | |
| 1188 | bool group_active = cbm_posix_group_active(process); |
| 1189 | if (!process->termination_started) { |
| 1190 | if (cbm_subprocess_cancellation_requested(process)) { |
| 1191 | cbm_posix_begin_termination(process, now); |
| 1192 | } else if (!process->root_reaped && process->quiet_timeout_ms > 0 && |
| 1193 | now - process->last_activity_ms >= (uint64_t)process->quiet_timeout_ms) { |
| 1194 | process->timed_out = true; |
| 1195 | cbm_posix_begin_termination(process, now); |
| 1196 | } else if (process->root_reaped && group_active) { |
| 1197 | /* A root that daemonizes children is not terminal. Preserve its exit |
| 1198 | * classification, but drain the descendants through the same path. */ |
| 1199 | cbm_posix_begin_termination(process, now); |
| 1200 | } |
| 1201 | } |
| 1202 | if (process->termination_started && group_active && !process->force_sent && |
| 1203 | now - process->termination_started_ms >= (uint64_t)process->cancel_grace_ms) { |
| 1204 | cbm_posix_force_tree(process, now); |
| 1205 | } |
| 1206 | group_active = cbm_posix_group_active(process); |
| 1207 | if (process->force_started_ms != 0 && group_active && |
| 1208 | now - process->force_started_ms >= CBM_SUBPROCESS_FORCE_SETTLE_MS) { |
| 1209 | return cbm_subprocess_finish_failed(process, out); |
| 1210 | } |
| 1211 | if (process->root_reaped && !group_active) { |
| 1212 | return cbm_subprocess_finish(process, out); |
| 1213 | } |
| 1214 | return CBM_PROC_POLL_RUNNING; |
| 1215 | } |
| 1216 | |
| 1217 | #endif /* _WIN32 */ |
| 1218 |
no test coverage detected