From c084cbe5659bb94e75d25f8e98bc85e4dc8e7d3c Mon Sep 17 00:00:00 2001 From: Christopher Albert Date: Thu, 4 Jun 2026 08:11:07 +0200 Subject: [PATCH] fix: serialize mkdir shell fork on the run_command lock build_target created the output directory inside an unnamed `!$omp critical`. mkdir shells out twice (is_dir runs `test -d`, then `mkdir -p`), and both fork. The unnamed critical is a different lock than `critical(run_command)` that guards every other shell fork (the compile/link/archive fallbacks), so a mkdir fork on one thread could run concurrently with a run_command fork on another - the exact concurrent-fork hazard the run_command lock exists to prevent. Put the directory creation under `critical(run_command)` so all shell forks share one lock. --- src/fpm_backend.F90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fpm_backend.F90 b/src/fpm_backend.F90 index 090efbb674..af79a0af12 100644 --- a/src/fpm_backend.F90 +++ b/src/fpm_backend.F90 @@ -327,11 +327,14 @@ subroutine build_target(model,target,verbose,dry_run,table,stat) integer :: fh - !$omp critical + ! mkdir shells out (is_dir 'test -d' and 'mkdir -p'), which forks. Serialize + ! it on the same run_command lock as every other shell fork so it cannot run + ! concurrently with a link/archive/compile shell fallback on another thread. + !$omp critical (run_command) if (.not.exists(dirname(target%output_file)) .and. .not.dry_run) then call mkdir(dirname(target%output_file),verbose) end if - !$omp end critical + !$omp end critical (run_command) select case(target%target_type)