Run one literal argv vector in a contained process tree. active_git is * published under projects_lock before supervision starts, so stop/unwatch can * request cancellation without racing destruction of the handle. */
| 316 | * published under projects_lock before supervision starts, so stop/unwatch can |
| 317 | * request cancellation without racing destruction of the handle. */ |
| 318 | static watcher_git_status_t watcher_git_run(cbm_watcher_t *w, project_state_t *state, |
| 319 | const char *const *argv, size_t output_limit, |
| 320 | watcher_git_output_t *output) { |
| 321 | if (!w || !state || !argv || !argv[0]) { |
| 322 | return WATCHER_GIT_SUPERVISION_FAILED; |
| 323 | } |
| 324 | if (output) { |
| 325 | memset(output, 0, sizeof(*output)); |
| 326 | } |
| 327 | if (output_limit > 0 && (!output || !watcher_git_output_create(output))) { |
| 328 | return WATCHER_GIT_SUPERVISION_FAILED; |
| 329 | } |
| 330 | |
| 331 | #ifdef _WIN32 |
| 332 | char git_executable[CBM_SZ_4K]; |
| 333 | if (!watcher_resolve_git_executable(git_executable)) { |
| 334 | watcher_git_output_cleanup(output); |
| 335 | return WATCHER_GIT_SUPERVISION_FAILED; |
| 336 | } |
| 337 | #endif |
| 338 | |
| 339 | cbm_proc_opts_t options = { |
| 340 | #ifdef _WIN32 |
| 341 | .bin = git_executable, |
| 342 | #else |
| 343 | .bin = argv[0], |
| 344 | #endif |
| 345 | .argv = argv, |
| 346 | .log_file = output_limit > 0 ? output->path : NULL, |
| 347 | /* A wall deadline below is authoritative. Binary `status -z` output |
| 348 | * deliberately has no line-based quiet-timeout semantics. */ |
| 349 | .quiet_timeout_ms = 0, |
| 350 | .cancel_grace_ms = CBM_SUBPROCESS_DEFAULT_CANCEL_GRACE_MS, |
| 351 | .delete_log_on_exit = false, |
| 352 | }; |
| 353 | cbm_subprocess_t *process = NULL; |
| 354 | if (cbm_subprocess_spawn(&options, &process) != 0) { |
| 355 | watcher_git_output_cleanup(output); |
| 356 | return WATCHER_GIT_SUPERVISION_FAILED; |
| 357 | } |
| 358 | |
| 359 | bool cancelled = false; |
| 360 | bool deadline_expired = false; |
| 361 | bool output_exceeded = false; |
| 362 | bool publication_conflict = false; |
| 363 | cbm_mutex_lock(&w->projects_lock); |
| 364 | if (state->active_git) { |
| 365 | publication_conflict = true; |
| 366 | cancelled = cbm_subprocess_request_cancel(process); |
| 367 | } else { |
| 368 | state->active_git = process; |
| 369 | } |
| 370 | if (!cancelled && (atomic_load_explicit(&w->stopped, memory_order_acquire) || |
| 371 | !atomic_load_explicit(&state->registered, memory_order_acquire))) { |
| 372 | cancelled = cbm_subprocess_request_cancel(process); |
| 373 | } |
| 374 | cbm_mutex_unlock(&w->projects_lock); |
| 375 |
no test coverage detected