| 1371 | } |
| 1372 | |
| 1373 | cbm_proc_poll_t cbm_subprocess_poll(cbm_subprocess_t *process, cbm_proc_result_t *out) { |
| 1374 | if (!process) { |
| 1375 | return CBM_PROC_POLL_ERROR; |
| 1376 | } |
| 1377 | int lifecycle = atomic_load_explicit(&process->lifecycle, memory_order_acquire); |
| 1378 | if (lifecycle == CBM_SUBPROCESS_TERMINAL) { |
| 1379 | if (out) { |
| 1380 | *out = process->result; |
| 1381 | } |
| 1382 | return CBM_PROC_POLL_TERMINAL; |
| 1383 | } |
| 1384 | if (lifecycle == CBM_SUBPROCESS_DRAINING) { |
| 1385 | cbm_tail_result_t tail = cbm_subprocess_poll_log(process, true); |
| 1386 | if (tail.status == CBM_TAIL_MORE) { |
| 1387 | return CBM_PROC_POLL_RUNNING; |
| 1388 | } |
| 1389 | if (tail.status == CBM_TAIL_ERROR) { |
| 1390 | cbm_log_error("subprocess.log_drain_failed", "reason", "io_error"); |
| 1391 | return cbm_subprocess_publish_terminal(process, out, false); |
| 1392 | } |
| 1393 | return cbm_subprocess_publish_terminal(process, out, true); |
| 1394 | } |
| 1395 | /* The one owner-thread tail batch for this public poll. Platform-specific |
| 1396 | * reap paths never tail again, preserving the exact per-poll work cap. */ |
| 1397 | (void)cbm_subprocess_poll_log(process, false); |
| 1398 | #ifdef _WIN32 |
| 1399 | return cbm_subprocess_poll_win(process, out); |
| 1400 | #else |
| 1401 | return cbm_subprocess_poll_posix(process, out); |
| 1402 | #endif |
| 1403 | } |
| 1404 | |
| 1405 | bool cbm_subprocess_request_cancel(cbm_subprocess_t *process) { |
| 1406 | if (!process) { |