From 9476ff9a9a0826a93ae1b533054ff79a24bae915 Mon Sep 17 00:00:00 2001 From: Irfan Bunjaku Date: Tue, 3 Mar 2026 14:39:17 +0100 Subject: [PATCH 1/2] [RAI-47876] Hard-code semaphore name to avoid thread-unsafe getenv calls --- src/aotcompile.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 51f9bcf5f8e5b..56faea2e16efa 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -1666,27 +1666,27 @@ void jl_dump_native_impl(void *native_code, }; sem_t *par_precomp_sem = SEM_FAILED; - const char *sem_name = getenv("JL_AOT_PRECOMPILE_SEMAPHORE"); - if (sem_name != NULL) { - // The count for the semaphore will be initialized by the parent process that spawns compilation sub-processes. - // This is to ensure that only already created semaphores are used and that we don't end up in a situation - // where every spawned compilation subprocess creates its own semaphore. Cleanup is handled by the parent process. - par_precomp_sem = sem_open(sem_name, 0); + // Hard-coded semaphore name to avoid thread-unsafe getenv() calls (RAI-47876) + const char *sem_name = "/jl_aot_par_precomp_semaphore"; + // Try to open the semaphore without O_CREAT. If it doesn't exist, sem_open will fail + // and we'll skip semaphore-based coordination (normal path when not using compcache). + // The count for the semaphore will be initialized by the parent process that spawns compilation sub-processes. + // This is to ensure that only already created semaphores are used and that we don't end up in a situation + // where every spawned compilation subprocess creates its own semaphore. Cleanup is handled by the parent process. + par_precomp_sem = sem_open(sem_name, 0); + if (par_precomp_sem != SEM_FAILED) { + // Semaphore exists, use it for coordination std::unique_ptr sem_guard(par_precomp_sem, cleanup); - if (par_precomp_sem == SEM_FAILED) { - jl_errorf("Failed to open parallel precompilation semaphore '%s': %s", sem_name, strerror(errno)); + // Wait for the semaphore, retrying if interrupted by a signal (EINTR). + int ret; + do { + ret = sem_wait(par_precomp_sem); + } while (ret == -1 && errno == EINTR); + + if (ret == 0) { + lock_acquired = true; } else { - // Wait for the semaphore, retrying if interrupted by a signal (EINTR). - int ret; - do { - ret = sem_wait(par_precomp_sem); - } while (ret == -1 && errno == EINTR); - - if (ret == 0) { - lock_acquired = true; - } else { - jl_errorf("Failed to wait on semaphore '%s': %s", sem_name, strerror(errno)); - } + jl_errorf("Failed to wait on semaphore '%s': %s", sem_name, strerror(errno)); } } #endif From 3f7f25dbcd47316005f49bbc8b917b76fbf60181 Mon Sep 17 00:00:00 2001 From: Irfan Bunjaku Date: Wed, 4 Mar 2026 10:47:25 +0100 Subject: [PATCH 2/2] [RAI-47876] Warn on unexpected sem_open errors (not ENOENT) --- src/aotcompile.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 56faea2e16efa..be73d88887ff6 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -1688,6 +1688,10 @@ void jl_dump_native_impl(void *native_code, } else { jl_errorf("Failed to wait on semaphore '%s': %s", sem_name, strerror(errno)); } + } else if (errno != ENOENT) { + // ENOENT means the semaphore doesn't exist, which is the normal path when not using + // compcache. Any other error is unexpected and worth surfacing. + jl_safe_printf("WARNING: sem_open(\"%s\") failed: %s\n", sem_name, strerror(errno)); } #endif