| 1385 | } |
| 1386 | |
| 1387 | cbm_proc_poll_t cbm_subprocess_poll(cbm_subprocess_t *process, cbm_proc_result_t *out) { |
| 1388 | if (!process) { |
| 1389 | return CBM_PROC_POLL_ERROR; |
| 1390 | } |
| 1391 | int lifecycle = atomic_load_explicit(&process->lifecycle, memory_order_acquire); |
| 1392 | if (lifecycle == CBM_SUBPROCESS_TERMINAL) { |
| 1393 | if (out) { |
| 1394 | *out = process->result; |
| 1395 | } |
| 1396 | return CBM_PROC_POLL_TERMINAL; |
| 1397 | } |
| 1398 | if (lifecycle == CBM_SUBPROCESS_DRAINING) { |
| 1399 | cbm_tail_result_t tail = cbm_subprocess_poll_log(process, true); |
| 1400 | if (tail.status == CBM_TAIL_MORE) { |
| 1401 | return CBM_PROC_POLL_RUNNING; |
| 1402 | } |
| 1403 | if (tail.status == CBM_TAIL_ERROR) { |
| 1404 | cbm_log_error("subprocess.log_drain_failed", "reason", "io_error"); |
| 1405 | return cbm_subprocess_publish_terminal(process, out, false); |
| 1406 | } |
| 1407 | return cbm_subprocess_publish_terminal(process, out, true); |
| 1408 | } |
| 1409 | /* The one owner-thread tail batch for this public poll. Platform-specific |
| 1410 | * reap paths never tail again, preserving the exact per-poll work cap. */ |
| 1411 | (void)cbm_subprocess_poll_log(process, false); |
| 1412 | #ifdef _WIN32 |
| 1413 | return cbm_subprocess_poll_win(process, out); |
| 1414 | #else |
| 1415 | return cbm_subprocess_poll_posix(process, out); |
| 1416 | #endif |
| 1417 | } |
| 1418 | |
| 1419 | bool cbm_subprocess_request_cancel(cbm_subprocess_t *process) { |
| 1420 | if (!process) { |