From 4e5ccba9d45f3c22adfb3b6f341de17f424135db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:04:34 +0000 Subject: [PATCH 01/15] Initial plan From f096f709003d834cb9553f4080f7323630806add Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:14:28 +0000 Subject: [PATCH 02/15] Remove dead code related to thread suspension semaphores - Removed unused methods: PostOnSuspendSemaphore, WaitOnSuspendSemaphore, PostOnResumeSemaphore, WaitOnResumeSemaphore - Removed semaphore member variables from CThreadSuspensionInfo class - Removed DestroySemaphoreIds method and PROCCleanupThreadSemIds function - Removed USE_POSIX_SEMAPHORES, USE_SYSV_SEMAPHORES, USE_PTHREAD_CONDVARS defines - Removed HAS_POSIX_SEMAPHORES configuration checks - Simplified InitializePreCreate to just return NO_ERROR Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- eng/native/tryrun.browser.cmake | 3 - eng/native/tryrun.cmake | 2 - eng/native/tryrun_ios_tvos.cmake | 1 - src/coreclr/pal/src/config.h.in | 1 - src/coreclr/pal/src/configure.cmake | 15 - src/coreclr/pal/src/include/pal/process.h | 13 - .../pal/src/include/pal/threadsusp.hpp | 118 ----- src/coreclr/pal/src/thread/process.cpp | 33 -- src/coreclr/pal/src/thread/threadsusp.cpp | 456 +----------------- 9 files changed, 2 insertions(+), 640 deletions(-) diff --git a/eng/native/tryrun.browser.cmake b/eng/native/tryrun.browser.cmake index 87425dc4d7eee7..15ec4d234974b0 100644 --- a/eng/native/tryrun.browser.cmake +++ b/eng/native/tryrun.browser.cmake @@ -101,9 +101,6 @@ set(COMPILER_SUPPORTS_F_ALIGNED_NEW 1 CACHE INTERNAL "") set(COMPILER_SUPPORTS_W_IMPLICIT_FALLTHROUGH 1 CACHE INTERNAL "") set(COMPILER_SUPPORTS_W_PRE_C11_COMPAT 1 CACHE INTERNAL "") set(COMPILER_SUPPORTS_W_RESERVED_IDENTIFIER 1 CACHE INTERNAL "") -set(HAS_POSIX_SEMAPHORES_COMPILED TRUE CACHE INTERNAL "") -set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 0) -set(HAS_POSIX_SEMAPHORES 1 CACHE INTERNAL "") set(HAS_PTHREAD_MUTEXES 1 CACHE INTERNAL "") set(HAS_SYSV_SEMAPHORES "" CACHE INTERNAL "") set(HAVE___GREGSET_T "" CACHE INTERNAL "") diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index 4f84aa93668096..ed879865a21daa 100644 --- a/eng/native/tryrun.cmake +++ b/eng/native/tryrun.cmake @@ -51,7 +51,6 @@ endif() if(DARWIN AND NOT DEFINED ANDROID_BUILD) if(TARGET_ARCH_NAME MATCHES "^(arm64|x64)$") - set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 1) set_cache_value(HAVE_BROKEN_FIFO_KEVENT_EXITCODE 1) set_cache_value(HAVE_BROKEN_FIFO_SELECT_EXITCODE 1) set_cache_value(HAVE_CLOCK_MONOTONIC_COARSE_EXITCODE 1) @@ -77,7 +76,6 @@ if(DARWIN AND NOT DEFINED ANDROID_BUILD) message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only arm64 or x64 is supported for OSX cross build!") endif() else() - set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 0) set_cache_value(HAVE_CLOCK_MONOTONIC_COARSE_EXITCODE 0) set_cache_value(HAVE_CLOCK_MONOTONIC_EXITCODE 0) set_cache_value(HAVE_CLOCK_REALTIME_EXITCODE 0) diff --git a/eng/native/tryrun_ios_tvos.cmake b/eng/native/tryrun_ios_tvos.cmake index 8dfecf22e12e69..bfeb06c78e84ad 100644 --- a/eng/native/tryrun_ios_tvos.cmake +++ b/eng/native/tryrun_ios_tvos.cmake @@ -10,7 +10,6 @@ set_cache_value(HAVE_CLOCK_MONOTONIC_EXITCODE 0) # TODO: these are taken from macOS, check these whether they're correct for iOS # some of them are probably not used by what we use from NativeAOT so could be reduced -set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 1) set_cache_value(HAVE_BROKEN_FIFO_KEVENT_EXITCODE 1) set_cache_value(HAVE_BROKEN_FIFO_SELECT_EXITCODE 1) set_cache_value(HAVE_CLOCK_REALTIME_EXITCODE 0) diff --git a/src/coreclr/pal/src/config.h.in b/src/coreclr/pal/src/config.h.in index 3338faf883ce30..6f95934232627f 100644 --- a/src/coreclr/pal/src/config.h.in +++ b/src/coreclr/pal/src/config.h.in @@ -94,7 +94,6 @@ #cmakedefine01 SEM_INIT_MODIFIES_ERRNO #cmakedefine01 HAVE_PROCFS_CTL #cmakedefine01 HAVE_PROCFS_STAT -#cmakedefine01 HAS_POSIX_SEMAPHORES #define PAL_THREAD_PRIORITY_MIN 0 #define PAL_THREAD_PRIORITY_MAX 0 diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake index c5814814ff446e..4ae982d355172f 100644 --- a/src/coreclr/pal/src/configure.cmake +++ b/src/coreclr/pal/src/configure.cmake @@ -592,21 +592,6 @@ int main(void) { }" HAVE_PROCFS_STAT) set(CMAKE_REQUIRED_LIBRARIES) -set(CMAKE_REQUIRED_LIBRARIES ${PTHREAD_LIBRARY}) -check_cxx_source_runs(" -#include -#include -#include - -int main() { - sem_t sema; - if (sem_init(&sema, 0, 0) == -1){ - exit(1); - } - exit(0); -}" HAS_POSIX_SEMAPHORES) -set(CMAKE_REQUIRED_LIBRARIES) - set(SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING 1) set(ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS 1) diff --git a/src/coreclr/pal/src/include/pal/process.h b/src/coreclr/pal/src/include/pal/process.h index fde6cce8d88956..45529a1edff900 100644 --- a/src/coreclr/pal/src/include/pal/process.h +++ b/src/coreclr/pal/src/include/pal/process.h @@ -95,19 +95,6 @@ Return --*/ VOID PROCCleanupInitialProcess(VOID); -#if USE_SYSV_SEMAPHORES -/*++ -Function: - PROCCleanupThreadSemIds(VOID); - -Abstract - Cleanup SysV semaphore ids for all threads. - -(no parameters, no return value) ---*/ -VOID PROCCleanupThreadSemIds(VOID); -#endif - /*++ Function: PROCProcessLock diff --git a/src/coreclr/pal/src/include/pal/threadsusp.hpp b/src/coreclr/pal/src/include/pal/threadsusp.hpp index eba859afe678e3..2844cb691fd872 100644 --- a/src/coreclr/pal/src/include/pal/threadsusp.hpp +++ b/src/coreclr/pal/src/include/pal/threadsusp.hpp @@ -28,48 +28,6 @@ Module Name: #if !HAVE_MACH_EXCEPTIONS #include #endif // !HAVE_MACH_EXCEPTIONS -#include -#include - -// We have a variety of options for synchronizing thread suspensions and resumptions between the requestor and -// target threads. Analyze the various capabilities given to us by configure and define one of three macros -// here for simplicity: -// USE_POSIX_SEMAPHORES -// USE_SYSV_SEMAPHORES -// USE_PTHREAD_CONDVARS -#if HAS_POSIX_SEMAPHORES - -// Favor posix semaphores. -#define USE_POSIX_SEMAPHORES 1 - -#if HAVE_SYS_SEMAPHORE_H -#include -#elif HAVE_SEMAPHORE_H -#include -#endif // HAVE_SYS_SEMAPHORE_H - -#elif HAS_PTHREAD_MUTEXES && (HAVE_MACH_EXCEPTIONS || defined(TARGET_TVOS)) - -// Can only use the pthread solution if we're not using signals since pthread mutexes are not signal safe. - -// On tvOS, HAVE_MACH_EXCEPTIONS is 0 because thread_set_exception_ports is not available in the SDK. -// However, System V IPC (semget) is also not available due to sandbox restrictions so we use pthread instead. -#define USE_PTHREAD_CONDVARS 1 - -#include - -#elif HAS_SYSV_SEMAPHORES - -// SYSV semaphores are our last choice since they're shared across processes so it's possible to leak them -// on abnormal process termination. -#define USE_SYSV_SEMAPHORES 1 - -#include -#include - -#else -#error "Don't know how to synchronize thread suspends and resumes on this platform" -#endif // HAS_POSIX_SEMAPHORES #include @@ -102,27 +60,6 @@ namespace CorUnix pthread_mutex_t m_ptmSuspmutex; // thread's suspension mutex, which is used to synchronize suspension and resumption attempts BOOL m_fSuspmutexInitialized; #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX -#if USE_POSIX_SEMAPHORES - sem_t m_semSusp; // suspension semaphore - sem_t m_semResume; // resumption semaphore - BOOL m_fSemaphoresInitialized; -#elif USE_SYSV_SEMAPHORES - // necessary id's and sembuf structures for SysV semaphores - int m_nSemsuspid; // id for the suspend semaphore - int m_nSemrespid; // id for the resume semaphore - struct sembuf m_sbSemwait; // struct representing a wait operation - struct sembuf m_sbSempost; // struct representing a post operation -#elif USE_PTHREAD_CONDVARS - pthread_cond_t m_condSusp; // suspension condition variable - pthread_mutex_t m_mutexSusp; // mutex associated with the condition above - BOOL m_fSuspended; // set to true once the suspend has been acknowledged - - pthread_cond_t m_condResume; // resumption condition variable - pthread_mutex_t m_mutexResume; // mutex associated with the condition above - BOOL m_fResumed; // set to true once the resume has been acknowledged - - BOOL m_fSemaphoresInitialized; -#endif // USE_POSIX_SEMAPHORES /* Most of the variables above are either accessed by a thread holding the appropriate suspension mutex(es) or are only @@ -168,40 +105,6 @@ namespace CorUnix CPalThread *pthrTarget ); -#if USE_POSIX_SEMAPHORES - sem_t* - GetSuspendSemaphore( - void - ) - { - return &m_semSusp; - }; - - sem_t* - GetResumeSemaphore( - void - ) - { - return &m_semResume; - }; -#elif USE_SYSV_SEMAPHORES - int - GetSuspendSemaphoreId( - void - ) - { - return m_nSemsuspid; - }; - - sembuf* - GetSemaphorePostBuffer( - void - ) - { - return &m_sbSempost; - }; -#endif // USE_POSIX_SEMAPHORES - #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX LONG* GetSuspensionSpinlock( @@ -252,18 +155,6 @@ namespace CorUnix return m_fSelfsusp; }; - void - PostOnSuspendSemaphore(); - - void - WaitOnSuspendSemaphore(); - - void - PostOnResumeSemaphore(); - - void - WaitOnResumeSemaphore(); - static BOOL TryAcquireSuspensionLock( @@ -290,9 +181,6 @@ namespace CorUnix #endif // _DEBUG #if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX , m_fSuspmutexInitialized(FALSE) -#endif -#if USE_POSIX_SEMAPHORES || USE_PTHREAD_CONDVARS - , m_fSemaphoresInitialized(FALSE) #endif { InitializeSuspensionLock(); @@ -310,12 +198,6 @@ namespace CorUnix }; #endif // _DEBUG -#if USE_SYSV_SEMAPHORES - void - DestroySemaphoreIds( - void - ); -#endif void SetSuspendedForShutdown( BOOL fSuspendedForShutdown diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 42897270a9456f..4c4e55476db750 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -3352,39 +3352,6 @@ PROCProcessUnlock( minipal_mutex_leave(&g_csProcess); } - -#if USE_SYSV_SEMAPHORES -/*++ -Function: - PROCCleanupThreadSemIds - -Abstract - Cleanup SysV semaphore ids for all threads - -(no parameters, no return value) ---*/ -VOID -PROCCleanupThreadSemIds(void) -{ - // - // When using SysV semaphores, the semaphore ids used by PAL threads must be removed - // so they can be used again. - // - - PROCProcessLock(); - - CPalThread *pTargetThread = pGThreadList; - while (NULL != pTargetThread) - { - pTargetThread->suspensionInfo.DestroySemaphoreIds(); - pTargetThread = pTargetThread->GetNext(); - } - - PROCProcessUnlock(); - -} -#endif // USE_SYSV_SEMAPHORES - /*++ Function: TerminateCurrentProcessNoExit diff --git a/src/coreclr/pal/src/thread/threadsusp.cpp b/src/coreclr/pal/src/thread/threadsusp.cpp index ec0dc9c5b92594..0d64feeae12df8 100644 --- a/src/coreclr/pal/src/thread/threadsusp.cpp +++ b/src/coreclr/pal/src/thread/threadsusp.cpp @@ -591,226 +591,6 @@ CThreadSuspensionInfo::ReleaseSuspensionLocks( #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION } -/*++ -Function: - PostOnSuspendSemaphore - -PostOnSuspendSemaphore is a utility function for a thread -to post on its POSIX or SysV suspension semaphore. ---*/ -void -CThreadSuspensionInfo::PostOnSuspendSemaphore() -{ -#if USE_POSIX_SEMAPHORES - if (sem_post(&m_semSusp) == -1) - { - ASSERT("sem_post returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_SYSV_SEMAPHORES - if (semop(m_nSemsuspid, &m_sbSempost, 1) == -1) - { - ASSERT("semop - post returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_PTHREAD_CONDVARS - int status; - - // The suspending thread may not have entered the wait yet, in which case the cond var - // signal below will be a no-op. To prevent the race condition we set m_fSuspended to - // TRUE first (which the suspender will take as an indication that no wait is required). - // But the setting of the flag and the signal must appear atomic to the suspender (as - // reading the flag and potentially waiting must appear to us) to avoid the race - // condition where the suspender reads the flag as FALSE, we set it and signal and the - // suspender then waits. - - // Acquire the suspend mutex. Once we enter the critical section the suspender has - // either gotten there before us (and is waiting for our signal) or is yet to even - // check the flag (so we can set it here to stop them attempting a wait). - status = pthread_mutex_lock(&m_mutexSusp); - if (status != 0) - { - ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status)); - } - - m_fSuspended = TRUE; - - status = pthread_cond_signal(&m_condSusp); - if (status != 0) - { - ASSERT("pthread_cond_signal returned %d (%s)\n", status, strerror(status)); - } - - status = pthread_mutex_unlock(&m_mutexSusp); - if (status != 0) - { - ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status)); - } -#endif // USE_POSIX_SEMAPHORES -} - -/*++ -Function: - WaitOnSuspendSemaphore - -WaitOnSuspendSemaphore is a utility function for a thread -to wait on its POSIX or SysV suspension semaphore. ---*/ -void -CThreadSuspensionInfo::WaitOnSuspendSemaphore() -{ -#if USE_POSIX_SEMAPHORES - while (sem_wait(&m_semSusp) == -1) - { - ASSERT("sem_wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_SYSV_SEMAPHORES - while (semop(m_nSemsuspid, &m_sbSemwait, 1) == -1) - { - ASSERT("semop wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_PTHREAD_CONDVARS - int status; - - // By the time we wait the target thread may have already signalled its suspension (in - // which case m_fSuspended will be TRUE and we shouldn't wait on the cond var). But we - // must check the flag and potentially wait atomically to avoid the race where we read - // the flag and the target thread sets it and signals before we have a chance to wait. - - status = pthread_mutex_lock(&m_mutexSusp); - if (status != 0) - { - ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status)); - } - - // If the target has already acknowledged the suspend we shouldn't wait. - while (!m_fSuspended) - { - // We got here before the target could signal. Wait on them (which atomically releases - // the mutex during the wait). - status = pthread_cond_wait(&m_condSusp, &m_mutexSusp); - if (status != 0) - { - ASSERT("pthread_cond_wait returned %d (%s)\n", status, strerror(status)); - } - } - - status = pthread_mutex_unlock(&m_mutexSusp); - if (status != 0) - { - ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status)); - } -#endif // USE_POSIX_SEMAPHORES -} - -/*++ -Function: - PostOnResumeSemaphore - -PostOnResumeSemaphore is a utility function for a thread -to post on its POSIX or SysV resume semaphore. ---*/ -void -CThreadSuspensionInfo::PostOnResumeSemaphore() -{ -#if USE_POSIX_SEMAPHORES - if (sem_post(&m_semResume) == -1) - { - ASSERT("sem_post returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_SYSV_SEMAPHORES - if (semop(m_nSemrespid, &m_sbSempost, 1) == -1) - { - ASSERT("semop - post returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_PTHREAD_CONDVARS - int status; - - // The resuming thread may not have entered the wait yet, in which case the cond var - // signal below will be a no-op. To prevent the race condition we set m_fResumed to - // TRUE first (which the resumer will take as an indication that no wait is required). - // But the setting of the flag and the signal must appear atomic to the resumer (as - // reading the flag and potentially waiting must appear to us) to avoid the race - // condition where the resumer reads the flag as FALSE, we set it and signal and the - // resumer then waits. - - // Acquire the resume mutex. Once we enter the critical section the resumer has - // either gotten there before us (and is waiting for our signal) or is yet to even - // check the flag (so we can set it here to stop them attempting a wait). - status = pthread_mutex_lock(&m_mutexResume); - if (status != 0) - { - ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status)); - } - - m_fResumed = TRUE; - - status = pthread_cond_signal(&m_condResume); - if (status != 0) - { - ASSERT("pthread_cond_signal returned %d (%s)\n", status, strerror(status)); - } - - status = pthread_mutex_unlock(&m_mutexResume); - if (status != 0) - { - ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status)); - } -#endif // USE_POSIX_SEMAPHORES -} - -/*++ -Function: - WaitOnResumeSemaphore - -WaitOnResumeSemaphore is a utility function for a thread -to wait on its POSIX or SysV resume semaphore. ---*/ -void -CThreadSuspensionInfo::WaitOnResumeSemaphore() -{ -#if USE_POSIX_SEMAPHORES - while (sem_wait(&m_semResume) == -1) - { - ASSERT("sem_wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_SYSV_SEMAPHORES - while (semop(m_nSemrespid, &m_sbSemwait, 1) == -1) - { - ASSERT("semop wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_PTHREAD_CONDVARS - int status; - - // By the time we wait the target thread may have already signalled its resumption (in - // which case m_fResumed will be TRUE and we shouldn't wait on the cond var). But we - // must check the flag and potentially wait atomically to avoid the race where we read - // the flag and the target thread sets it and signals before we have a chance to wait. - - status = pthread_mutex_lock(&m_mutexResume); - if (status != 0) - { - ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status)); - } - - // If the target has already acknowledged the resume we shouldn't wait. - while (!m_fResumed) - { - // We got here before the target could signal. Wait on them (which atomically releases - // the mutex during the wait). - status = pthread_cond_wait(&m_condResume, &m_mutexResume); - if (status != 0) - { - ASSERT("pthread_cond_wait returned %d (%s)\n", status, strerror(status)); - } - } - - status = pthread_mutex_unlock(&m_mutexResume); - if (status != 0) - { - ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status)); - } -#endif // USE_POSIX_SEMAPHORES -} - /*++ Function: InitializeSuspensionLock @@ -839,170 +619,12 @@ CThreadSuspensionInfo::InitializeSuspensionLock() Function: InitializePreCreate -InitializePreCreate initializes the semaphores and signal masks used -for thread suspension. At the end, it sets the calling thread's -signal mask to the default signal mask. +InitializePreCreate is called from the CThreadSuspensionInfo constructor. --*/ PAL_ERROR CThreadSuspensionInfo::InitializePreCreate() { - PAL_ERROR palError = ERROR_INTERNAL_ERROR; - int iError = 0; -#if SEM_INIT_MODIFIES_ERRNO - int nStoredErrno; -#endif // SEM_INIT_MODIFIES_ERRNO - -#if USE_POSIX_SEMAPHORES - -#if SEM_INIT_MODIFIES_ERRNO - nStoredErrno = errno; -#endif // SEM_INIT_MODIFIES_ERRNO - - // initialize suspension semaphore - iError = sem_init(&m_semSusp, 0, 0); - -#if SEM_INIT_MODIFIES_ERRNO - if (iError == 0) - { - // Restore errno if sem_init succeeded. - errno = nStoredErrno; - } -#endif // SEM_INIT_MODIFIES_ERRNO - - if (0 != iError ) - { - ASSERT("sem_init(&suspsem) returned %d\n", iError); - goto InitializePreCreateExit; - } - -#if SEM_INIT_MODIFIES_ERRNO - nStoredErrno = errno; -#endif // SEM_INIT_MODIFIES_ERRNO - - // initialize resume semaphore - iError = sem_init(&m_semResume, 0, 0); - -#if SEM_INIT_MODIFIES_ERRNO - if (iError == 0) - { - // Restore errno if sem_init succeeded. - errno = nStoredErrno; - } -#endif // SEM_INIT_MODIFIES_ERRNO - - if (0 != iError ) - { - ASSERT("sem_init(&suspsem) returned %d\n", iError); - sem_destroy(&m_semSusp); - goto InitializePreCreateExit; - } - - m_fSemaphoresInitialized = TRUE; - -#elif USE_SYSV_SEMAPHORES - // preparing to initialize the SysV semaphores. - union semun semunData; - m_nSemsuspid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666); - if (m_nSemsuspid == -1) - { - ASSERT("semget for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - goto InitializePreCreateExit; - } - - m_nSemrespid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666); - if (m_nSemrespid == -1) - { - ASSERT("semget for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - goto InitializePreCreateExit; - } - - if (m_nSemsuspid == m_nSemrespid) - { - ASSERT("Suspension and Resumption Semaphores have the same id\n"); - goto InitializePreCreateExit; - } - - semunData.val = 0; - iError = semctl(m_nSemsuspid, 0, SETVAL, semunData); - if (iError == -1) - { - ASSERT("semctl for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - goto InitializePreCreateExit; - } - - semunData.val = 0; - iError = semctl(m_nSemrespid, 0, SETVAL, semunData); - if (iError == -1) - { - ASSERT("semctl for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno)); - goto InitializePreCreateExit; - } - - // initialize suspend semaphore - m_sbSemwait.sem_num = 0; - m_sbSemwait.sem_op = -1; - m_sbSemwait.sem_flg = 0; - - // initialize resume semaphore - m_sbSempost.sem_num = 0; - m_sbSempost.sem_op = 1; - m_sbSempost.sem_flg = 0; -#elif USE_PTHREAD_CONDVARS - iError = pthread_cond_init(&m_condSusp, NULL); - if (iError != 0) - { - ASSERT("pthread_cond_init for suspension returned %d (%s)\n", iError, strerror(iError)); - goto InitializePreCreateExit; - } - - iError = pthread_mutex_init(&m_mutexSusp, NULL); - if (iError != 0) - { - ASSERT("pthread_mutex_init for suspension returned %d (%s)\n", iError, strerror(iError)); - goto InitializePreCreateExit; - } - - iError = pthread_cond_init(&m_condResume, NULL); - if (iError != 0) - { - ASSERT("pthread_cond_init for resume returned %d (%s)\n", iError, strerror(iError)); - goto InitializePreCreateExit; - } - - iError = pthread_mutex_init(&m_mutexResume, NULL); - if (iError != 0) - { - ASSERT("pthread_mutex_init for resume returned %d (%s)\n", iError, strerror(iError)); - goto InitializePreCreateExit; - } - - m_fSemaphoresInitialized = TRUE; -#endif // USE_POSIX_SEMAPHORES - - // Initialization was successful. - palError = NO_ERROR; - -InitializePreCreateExit: - - if (NO_ERROR == palError && 0 != iError) - { - switch (iError) - { - case ENOMEM: - case EAGAIN: - { - palError = ERROR_OUTOFMEMORY; - break; - } - default: - { - ASSERT("A pthrSuspender init call returned %d (%s)\n", iError, strerror(iError)); - palError = ERROR_INTERNAL_ERROR; - } - } - } - - return palError; + return NO_ERROR; } CThreadSuspensionInfo::~CThreadSuspensionInfo() @@ -1015,78 +637,4 @@ CThreadSuspensionInfo::~CThreadSuspensionInfo() _ASSERT_MSG(0 == iError, "pthread_mutex_destroy returned %d (%s)\n", iError, strerror(iError)); } #endif - -#if USE_POSIX_SEMAPHORES - if (m_fSemaphoresInitialized) - { - int iError; - - iError = sem_destroy(&m_semSusp); - _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno)); - - iError = sem_destroy(&m_semResume); - _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno)); - } -#elif USE_SYSV_SEMAPHORES - DestroySemaphoreIds(); -#elif USE_PTHREAD_CONDVARS - if (m_fSemaphoresInitialized) - { - int iError; - - iError = pthread_cond_destroy(&m_condSusp); - _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError)); - - iError = pthread_mutex_destroy(&m_mutexSusp); - _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError)); - - iError = pthread_cond_destroy(&m_condResume); - _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError)); - - iError = pthread_mutex_destroy(&m_mutexResume); - _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError)); - } -#endif // USE_POSIX_SEMAPHORES -} - -#if USE_SYSV_SEMAPHORES -/*++ -Function: - DestroySemaphoreIds - -DestroySemaphoreIds is called from the CThreadSuspensionInfo destructor and -from PROCCleanupThreadSemIds. If a thread exits before shutdown or is suspended -during shutdown, its destructor will be invoked and the semaphore ids destroyed. -In assert or exceptions situations that are suspension unsafe, -PROCCleanupThreadSemIds is called, which uses DestroySemaphoreIds. ---*/ -void -CThreadSuspensionInfo::DestroySemaphoreIds() -{ - union semun semunData; - if (m_nSemsuspid != 0) - { - semunData.val = 0; - if (0 != semctl(m_nSemsuspid, 0, IPC_RMID, semunData)) - { - ERROR("semctl(Semsuspid) failed and set errno to %d (%s)\n", errno, strerror(errno)); - } - else - { - m_nSemsuspid = 0; - } - } - if (this->m_nSemrespid) - { - semunData.val = 0; - if (0 != semctl(m_nSemrespid, 0, IPC_RMID, semunData)) - { - ERROR("semctl(Semrespid) failed and set errno to %d (%s)\n", errno, strerror(errno)); - } - else - { - m_nSemrespid = 0; - } - } } -#endif // USE_SYSV_SEMAPHORES From 6310b7b69165392f826bc6d738dff48969091b50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:04:10 +0000 Subject: [PATCH 03/15] Remove additional dead code: SetSuspendedForShutdown and DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - Removed SetSuspendedForShutdown/GetSuspendedForShutdown and m_fSuspendedForShutdown (only used in debug trace) - Removed DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX define and always use pthread mutex path - Removed spinlock implementation (SPINLOCKInit, SPINLOCKAcquire, SPINLOCKRelease, SPINLOCKTryAcquire) - Simplified thread suspension to always use pthread mutexes on all platforms Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/config.h.in | 1 - src/coreclr/pal/src/configure.cmake | 7 -- .../pal/src/include/pal/threadsusp.hpp | 37 +------ src/coreclr/pal/src/thread/process.cpp | 5 +- src/coreclr/pal/src/thread/threadsusp.cpp | 102 +++--------------- 5 files changed, 16 insertions(+), 136 deletions(-) diff --git a/src/coreclr/pal/src/config.h.in b/src/coreclr/pal/src/config.h.in index 6f95934232627f..342045da832de8 100644 --- a/src/coreclr/pal/src/config.h.in +++ b/src/coreclr/pal/src/config.h.in @@ -99,7 +99,6 @@ #define PAL_THREAD_PRIORITY_MAX 0 #cmakedefine01 HAVE__NSGETENVIRON -#cmakedefine01 DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX #cmakedefine PAL_PTRACE(cmd, pid, addr, data) @PAL_PTRACE@ #cmakedefine01 SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING #cmakedefine01 ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake index 4ae982d355172f..3876f96feca3b9 100644 --- a/src/coreclr/pal/src/configure.cmake +++ b/src/coreclr/pal/src/configure.cmake @@ -652,12 +652,10 @@ int main(int argc, char **argv) if(CLR_CMAKE_TARGET_APPLE) set(HAVE__NSGETENVIRON 1) - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 1) set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))") set(HAVE_SCHED_OTHER_ASSIGNABLE 1) elseif(CLR_CMAKE_TARGET_FREEBSD) - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))") if (CLR_CMAKE_HOST_ARCH_AMD64) set(BSD_REGS_STYLE "((reg).r_##rr)") @@ -668,21 +666,17 @@ elseif(CLR_CMAKE_TARGET_FREEBSD) endif() set(HAVE_SCHED_OTHER_ASSIGNABLE 1) elseif(CLR_CMAKE_TARGET_NETBSD) - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(PAL_PTRACE "ptrace((cmd), (pid), (void*)(addr), (data))") set(BSD_REGS_STYLE "((reg).regs[_REG_##RR])") set(HAVE_SCHED_OTHER_ASSIGNABLE 0) elseif(CLR_CMAKE_TARGET_SUNOS) - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))") set(SET_SCHEDPARAM_NEEDS_PRIVS 1) elseif(CLR_CMAKE_TARGET_HAIKU) # Haiku does not have ptrace. - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(HAVE_SCHED_OTHER_ASSIGNABLE 1) elseif(CLR_CMAKE_TARGET_BROWSER) - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(HAVE_SCHED_OTHER_ASSIGNABLE 0) else() # Anything else is Linux # LTTNG is not available on Android, so don't error out @@ -690,7 +684,6 @@ else() # Anything else is Linux unset(HAVE_LTTNG_TRACEPOINT_H CACHE) message(FATAL_ERROR "Cannot find liblttng-ust-dev. Try installing liblttng-ust-dev (or the appropriate packages for your platform)") endif() - set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(PAL_PTRACE "ptrace((cmd), (pid), (void*)(addr), (data))") set(HAVE_SCHED_OTHER_ASSIGNABLE 1) endif(CLR_CMAKE_TARGET_APPLE) diff --git a/src/coreclr/pal/src/include/pal/threadsusp.hpp b/src/coreclr/pal/src/include/pal/threadsusp.hpp index 2844cb691fd872..4eab42ac8671b3 100644 --- a/src/coreclr/pal/src/include/pal/threadsusp.hpp +++ b/src/coreclr/pal/src/include/pal/threadsusp.hpp @@ -49,25 +49,19 @@ namespace CorUnix private: BOOL m_fPending; // TRUE if a suspension is pending on a thread (because the thread is in an unsafe region) BOOL m_fSelfsusp; // TRUE if thread is self suspending and while thread is self suspended - BOOL m_fSuspendedForShutdown; // TRUE once the thread is suspended during PAL cleanup int m_nBlockingPipe; // blocking pipe used for a process that was created suspended #ifdef _DEBUG Volatile m_lNumThreadsSuspendedByThisThread; // number of threads that this thread has suspended; used for suspension diagnostics #endif -#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - int m_nSpinlock; // thread's suspension spinlock, which is used to synchronize suspension and resumption attempts -#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX pthread_mutex_t m_ptmSuspmutex; // thread's suspension mutex, which is used to synchronize suspension and resumption attempts BOOL m_fSuspmutexInitialized; -#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX /* Most of the variables above are either accessed by a thread holding the appropriate suspension mutex(es) or are only accessed by their own threads (and thus don't require synchronization). - m_fPending, m_fSuspendedForShutdown, - m_fSuspendSignalSent, and m_fResumeSignalSent + m_fPending, m_fSuspendSignalSent, and m_fResumeSignalSent may be set by a different thread than the owner and thus require synchronization. @@ -105,15 +99,6 @@ namespace CorUnix CPalThread *pthrTarget ); -#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - LONG* - GetSuspensionSpinlock( - void - ) - { - return &m_nSpinlock; - } -#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX pthread_mutex_t* GetSuspensionMutex( void @@ -121,7 +106,6 @@ namespace CorUnix { return &m_ptmSuspmutex; } -#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX void SetSuspPending( @@ -174,14 +158,11 @@ namespace CorUnix CThreadSuspensionInfo() : m_fPending(FALSE) , m_fSelfsusp(FALSE) - , m_fSuspendedForShutdown(FALSE) , m_nBlockingPipe(-1) #ifdef _DEBUG , m_lNumThreadsSuspendedByThisThread(0) #endif // _DEBUG -#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX , m_fSuspmutexInitialized(FALSE) -#endif { InitializeSuspensionLock(); }; @@ -198,22 +179,6 @@ namespace CorUnix }; #endif // _DEBUG - void - SetSuspendedForShutdown( - BOOL fSuspendedForShutdown - ) - { - m_fSuspendedForShutdown = fSuspendedForShutdown; - }; - - BOOL - GetSuspendedForShutdown( - void - ) - { - return m_fSuspendedForShutdown; - }; - void AcquireSuspensionLock( CPalThread *pthrCurrent diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 4c4e55476db750..488f6618b60c75 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -3633,10 +3633,9 @@ void PROCDumpThreadList() pThread = pGThreadList; while (NULL != pThread) { - TRACE (" {pThr=0x%p tid=%#x lwpid=%#x state=%d finsusp=%d}\n", + TRACE (" {pThr=0x%p tid=%#x lwpid=%#x state=%d}\n", pThread, (int)pThread->GetThreadId(), (int)pThread->GetLwpId(), - (int)pThread->synchronizationInfo.GetThreadState(), - (int)pThread->suspensionInfo.GetSuspendedForShutdown()); + (int)pThread->synchronizationInfo.GetThreadState()); pThread = pThread->GetNext(); } diff --git a/src/coreclr/pal/src/thread/threadsusp.cpp b/src/coreclr/pal/src/thread/threadsusp.cpp index 0d64feeae12df8..e5413d8571b038 100644 --- a/src/coreclr/pal/src/thread/threadsusp.cpp +++ b/src/coreclr/pal/src/thread/threadsusp.cpp @@ -46,7 +46,7 @@ CONST BYTE WAKEUPCODE=0x2A; // #define USE_GLOBAL_LOCK_FOR_SUSPENSION // Uncomment this define to use the global suspension lock. /* The global suspension lock can be used in place of each thread having its own -suspension mutex or spinlock. The downside is that it restricts us to only +suspension mutex. The downside is that it restricts us to only performing one suspension or resumption in the PAL at a time. */ #ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION @@ -56,50 +56,6 @@ namespace } #endif -#define SYNCSPINLOCK_F_ASYMMETRIC 1 - -#define SPINLOCKInit(lock) (*(lock) = 0) - -namespace -{ - /* Basic spinlock implementation */ - void SPINLOCKAcquire (LONG * lock, unsigned int flags) - { - size_t loop_seed = 1, loop_count = 0; - - if (flags & SYNCSPINLOCK_F_ASYMMETRIC) - { - loop_seed = ((size_t)pthread_self() % 10) + 1; - } - while (InterlockedCompareExchange(lock, 1, 0)) - { - if (!(flags & SYNCSPINLOCK_F_ASYMMETRIC) || (++loop_count % loop_seed)) - { -#if PAL_IGNORE_NORMAL_THREAD_PRIORITY - struct timespec tsSleepTime; - tsSleepTime.tv_sec = 0; - tsSleepTime.tv_nsec = 1; - nanosleep(&tsSleepTime, NULL); -#else - sched_yield(); -#endif - } - } - - } - - void SPINLOCKRelease (LONG * lock) - { - VolatileStore(lock, 0); - } - - DWORD SPINLOCKTryAcquire (LONG * lock) - { - return InterlockedCompareExchange(lock, 1, 0); - // only returns 0 or 1. - } -} - /*++ Function: InternalSuspendNewThreadFromData @@ -382,7 +338,7 @@ CThreadSuspensionInfo::InternalResumeThreadFromData( TryAcquireSuspensionLock TryAcquireSuspensionLock is a utility function that tries to acquire a thread's -suspension mutex or spinlock. If it succeeds, the function returns TRUE. +suspension mutex. If it succeeds, the function returns TRUE. Otherwise, it returns FALSE. This function is used in AcquireSuspensionLocks. Note that the global lock cannot be acquired in this function since it makes no sense to do so. A thread holding the global lock is the only thread that @@ -394,17 +350,8 @@ CThreadSuspensionInfo::TryAcquireSuspensionLock( CPalThread* pthrTarget ) { - int iPthreadRet = 0; -#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX -{ - iPthreadRet = SPINLOCKTryAcquire(pthrTarget->suspensionInfo.GetSuspensionSpinlock()); -} -#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX -{ - iPthreadRet = pthread_mutex_trylock(pthrTarget->suspensionInfo.GetSuspensionMutex()); + int iPthreadRet = pthread_mutex_trylock(pthrTarget->suspensionInfo.GetSuspensionMutex()); _ASSERT_MSG(iPthreadRet == 0 || iPthreadRet == EBUSY, "pthread_mutex_trylock returned %d\n", iPthreadRet); -} -#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX // If iPthreadRet is 0, lock acquisition was successful. Otherwise, it failed. return (iPthreadRet == 0); @@ -430,17 +377,9 @@ CThreadSuspensionInfo::AcquireSuspensionLock( } #else // USE_GLOBAL_LOCK_FOR_SUSPENSION { - #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - { - SPINLOCKAcquire(&pthrCurrent->suspensionInfo.m_nSpinlock, 0); - } - #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - { - INDEBUG(int iPthreadError = ) - pthread_mutex_lock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex); - _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_lock returned %d\n", iPthreadError); - } - #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + INDEBUG(int iPthreadError = ) + pthread_mutex_lock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex); + _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_lock returned %d\n", iPthreadError); } #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION } @@ -449,8 +388,8 @@ CThreadSuspensionInfo::AcquireSuspensionLock( Function: ReleaseSuspensionLock -ReleaseSuspensionLock is a function that releases a thread's suspension mutex -or spinlock. If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, +ReleaseSuspensionLock is a function that releases a thread's suspension mutex. +If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it will release the global lock. --*/ void @@ -464,17 +403,9 @@ CThreadSuspensionInfo::ReleaseSuspensionLock( } #else // USE_GLOBAL_LOCK_FOR_SUSPENSION { - #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - { - SPINLOCKRelease(&pthrCurrent->suspensionInfo.m_nSpinlock); - } - #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - { - INDEBUG(int iPthreadError = ) - pthread_mutex_unlock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex); - _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_unlock returned %d\n", iPthreadError); - } - #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX + INDEBUG(int iPthreadError = ) + pthread_mutex_unlock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex); + _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_unlock returned %d\n", iPthreadError); } #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION } @@ -595,16 +526,12 @@ CThreadSuspensionInfo::ReleaseSuspensionLocks( Function: InitializeSuspensionLock -InitializeSuspensionLock initializes a thread's suspension spinlock -or suspension mutex. It is called from the CThreadSuspensionInfo -constructor. +InitializeSuspensionLock initializes a thread's suspension mutex. +It is called from the CThreadSuspensionInfo constructor. --*/ VOID CThreadSuspensionInfo::InitializeSuspensionLock() { -#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX - SPINLOCKInit(&m_nSpinlock); -#else int iError = pthread_mutex_init(&m_ptmSuspmutex, NULL); if (0 != iError ) { @@ -612,7 +539,6 @@ CThreadSuspensionInfo::InitializeSuspensionLock() return; } m_fSuspmutexInitialized = TRUE; -#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX } /*++ @@ -629,12 +555,10 @@ CThreadSuspensionInfo::InitializePreCreate() CThreadSuspensionInfo::~CThreadSuspensionInfo() { -#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX if (m_fSuspmutexInitialized) { INDEBUG(int iError = ) pthread_mutex_destroy(&m_ptmSuspmutex); _ASSERT_MSG(0 == iError, "pthread_mutex_destroy returned %d (%s)\n", iError, strerror(iError)); } -#endif } From c1d6be2028e3b086e1b0b5573198bd0faf08e0f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:39:56 +0000 Subject: [PATCH 04/15] Remove MAX_TRACKED_CRITSECS dead code - Removed unused MAX_TRACKED_CRITSECS define from threadsusp.hpp Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/include/pal/threadsusp.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/pal/src/include/pal/threadsusp.hpp b/src/coreclr/pal/src/include/pal/threadsusp.hpp index 4eab42ac8671b3..72e9a2265273df 100644 --- a/src/coreclr/pal/src/include/pal/threadsusp.hpp +++ b/src/coreclr/pal/src/include/pal/threadsusp.hpp @@ -33,10 +33,6 @@ Module Name: namespace CorUnix { -#ifdef _DEBUG -#define MAX_TRACKED_CRITSECS 8 -#endif - PAL_ERROR InternalResumeThread( CPalThread *pthrResumer, From a9ec879adee9136ae7313f14a6374fd55476d13e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 17:05:10 +0000 Subject: [PATCH 05/15] Remove additional dead code: m_fPending, m_lNumThreadsSuspendedByThisThread, USE_GLOBAL_LOCK_FOR_SUSPENSION - Removed m_fPending member variable and SetSuspPending/GetSuspPending methods (never called) - Removed m_lNumThreadsSuspendedByThisThread debug variable and related methods (never called) - Removed USE_GLOBAL_LOCK_FOR_SUSPENSION conditional compilation (never defined) - Simplified suspension lock code by removing all dead conditional branches Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../pal/src/include/pal/threadsusp.hpp | 65 +------------------ src/coreclr/pal/src/thread/threadsusp.cpp | 45 +------------ 2 files changed, 3 insertions(+), 107 deletions(-) diff --git a/src/coreclr/pal/src/include/pal/threadsusp.hpp b/src/coreclr/pal/src/include/pal/threadsusp.hpp index 72e9a2265273df..e02d2a2f13b1ce 100644 --- a/src/coreclr/pal/src/include/pal/threadsusp.hpp +++ b/src/coreclr/pal/src/include/pal/threadsusp.hpp @@ -43,12 +43,8 @@ namespace CorUnix class CThreadSuspensionInfo : public CThreadInfoInitializer { private: - BOOL m_fPending; // TRUE if a suspension is pending on a thread (because the thread is in an unsafe region) BOOL m_fSelfsusp; // TRUE if thread is self suspending and while thread is self suspended int m_nBlockingPipe; // blocking pipe used for a process that was created suspended -#ifdef _DEBUG - Volatile m_lNumThreadsSuspendedByThisThread; // number of threads that this thread has suspended; used for suspension diagnostics -#endif pthread_mutex_t m_ptmSuspmutex; // thread's suspension mutex, which is used to synchronize suspension and resumption attempts BOOL m_fSuspmutexInitialized; @@ -57,31 +53,8 @@ namespace CorUnix accessed by their own threads (and thus don't require synchronization). - m_fPending, m_fSuspendSignalSent, and m_fResumeSignalSent - may be set by a different thread than the owner and thus - require synchronization. - m_fSelfsusp is set to TRUE only by its own thread but may be later - accessed by other threads. - - m_lNumThreadsSuspendedByThisThread is accessed by its owning - thread and therefore does not require synchronization. */ - -#ifdef _DEBUG - VOID - IncrNumThreadsSuspendedByThisThread( - ) - { - InterlockedIncrement(&m_lNumThreadsSuspendedByThisThread); - }; - - VOID - DecrNumThreadsSuspendedByThisThread( - ) - { - InterlockedDecrement(&m_lNumThreadsSuspendedByThisThread); - }; -#endif + accessed by other threads. */ VOID AcquireSuspensionLocks( @@ -103,22 +76,6 @@ namespace CorUnix return &m_ptmSuspmutex; } - void - SetSuspPending( - BOOL fPending - ) - { - m_fPending = fPending; - }; - - BOOL - GetSuspPending( - void - ) - { - return m_fPending; - }; - void SetSelfSusp( BOOL fSelfsusp @@ -152,12 +109,8 @@ namespace CorUnix virtual PAL_ERROR InitializePreCreate(); CThreadSuspensionInfo() - : m_fPending(FALSE) - , m_fSelfsusp(FALSE) + : m_fSelfsusp(FALSE) , m_nBlockingPipe(-1) -#ifdef _DEBUG - , m_lNumThreadsSuspendedByThisThread(0) -#endif // _DEBUG , m_fSuspmutexInitialized(FALSE) { InitializeSuspensionLock(); @@ -165,16 +118,6 @@ namespace CorUnix virtual ~CThreadSuspensionInfo(); -#ifdef _DEBUG - LONG - GetNumThreadsSuspendedByThisThread( - void - ) - { - return m_lNumThreadsSuspendedByThisThread; - }; -#endif // _DEBUG - void AcquireSuspensionLock( CPalThread *pthrCurrent @@ -211,9 +154,5 @@ namespace CorUnix extern const BYTE WAKEUPCODE; // use for pipe reads during self suspend. #endif // __cplusplus -#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION -extern LONG g_ssSuspensionLock; -#endif - #endif // _PAL_THREADSUSP_HPP diff --git a/src/coreclr/pal/src/thread/threadsusp.cpp b/src/coreclr/pal/src/thread/threadsusp.cpp index e5413d8571b038..8136d24c4ab741 100644 --- a/src/coreclr/pal/src/thread/threadsusp.cpp +++ b/src/coreclr/pal/src/thread/threadsusp.cpp @@ -44,18 +44,6 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); in suspended state in order to resume it. */ CONST BYTE WAKEUPCODE=0x2A; -// #define USE_GLOBAL_LOCK_FOR_SUSPENSION // Uncomment this define to use the global suspension lock. -/* The global suspension lock can be used in place of each thread having its own -suspension mutex. The downside is that it restricts us to only -performing one suspension or resumption in the PAL at a time. */ -#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION - -namespace -{ - LONG g_ssSuspensionLock = 0; -} -#endif - /*++ Function: InternalSuspendNewThreadFromData @@ -361,8 +349,7 @@ CThreadSuspensionInfo::TryAcquireSuspensionLock( Function: AcquireSuspensionLock -AcquireSuspensionLock acquires a thread's suspension mutex or spinlock. -If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it will acquire the global lock. +AcquireSuspensionLock acquires a thread's suspension mutex. A thread in this function blocks until it acquires its lock, unlike in TryAcquireSuspensionLock. --*/ @@ -370,45 +357,27 @@ void CThreadSuspensionInfo::AcquireSuspensionLock( CPalThread* pthrCurrent ) -{ -#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION -{ - SPINLOCKAcquire(&g_ssSuspensionLock, 0); -} -#else // USE_GLOBAL_LOCK_FOR_SUSPENSION { INDEBUG(int iPthreadError = ) pthread_mutex_lock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex); _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_lock returned %d\n", iPthreadError); } -#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION -} /*++ Function: ReleaseSuspensionLock ReleaseSuspensionLock is a function that releases a thread's suspension mutex. -If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, -it will release the global lock. --*/ void CThreadSuspensionInfo::ReleaseSuspensionLock( CPalThread* pthrCurrent ) -{ -#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION -{ - SPINLOCKRelease(&g_ssSuspensionLock); -} -#else // USE_GLOBAL_LOCK_FOR_SUSPENSION { INDEBUG(int iPthreadError = ) pthread_mutex_unlock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex); _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_unlock returned %d\n", iPthreadError); } -#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION -} /*++ Function: @@ -440,9 +409,6 @@ mutex first. This prevents you from being suspended while holding the target's mutex. Then, attempt to acquire the target's mutex. If the mutex cannot be acquired, release your own and try again. This all or nothing approach is the safest and avoids nasty race conditions. - -If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, the calling thread -will acquire the global lock when possible. --*/ VOID CThreadSuspensionInfo::AcquireSuspensionLocks( @@ -452,9 +418,6 @@ CThreadSuspensionInfo::AcquireSuspensionLocks( { BOOL fReacquire = FALSE; -#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION - AcquireSuspensionLock(pthrSuspender); -#else // USE_GLOBAL_LOCK_FOR_SUSPENSION do { fReacquire = FALSE; @@ -467,7 +430,6 @@ CThreadSuspensionInfo::AcquireSuspensionLocks( sched_yield(); } } while (fReacquire); -#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION // Whenever the native implementation for the wait subsystem's thread // blocking requires a lock as protection (as pthread conditions do with @@ -503,7 +465,6 @@ ReleaseSuspensionLocks releases both thread's suspension mutexes. Note that the locks are released in the opposite order they're acquired. This prevents a suspending or resuming thread from being suspended while holding the target's lock. -If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it simply releases the global lock. --*/ VOID CThreadSuspensionInfo::ReleaseSuspensionLocks( @@ -514,12 +475,8 @@ CThreadSuspensionInfo::ReleaseSuspensionLocks( // See comment in AcquireSuspensionLocks pthrTarget->ReleaseNativeWaitLock(); -#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION - ReleaseSuspensionLock(pthrSuspender); -#else // USE_GLOBAL_LOCK_FOR_SUSPENSION ReleaseSuspensionLock(pthrTarget); ReleaseSuspensionLock(pthrSuspender); -#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION } /*++ From 715f8ea55714a8d4b5484c3956bb1add5a5a11e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 18:40:36 +0000 Subject: [PATCH 06/15] Remove PROCGetNumberOfThreads dead code - Removed unused PROCGetNumberOfThreads function from process.cpp - Removed PROCGetNumberOfThreads declaration from procprivate.hpp Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/thread/process.cpp | 21 --------------------- src/coreclr/pal/src/thread/procprivate.hpp | 9 --------- 2 files changed, 30 deletions(-) diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 488f6618b60c75..60b3f617493544 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -3285,27 +3285,6 @@ CorUnix::PROCRemoveThread( } -/*++ -Function: - PROCGetNumberOfThreads - -Abstract - Return the number of threads in the thread list. - -Parameter - void - -Return - the number of threads. ---*/ -INT -CorUnix::PROCGetNumberOfThreads( - VOID) -{ - return g_dwThreadCount; -} - - /*++ Function: PROCProcessLock diff --git a/src/coreclr/pal/src/thread/procprivate.hpp b/src/coreclr/pal/src/thread/procprivate.hpp index 4f3af27243e3b6..6922ebf3f1f228 100644 --- a/src/coreclr/pal/src/thread/procprivate.hpp +++ b/src/coreclr/pal/src/thread/procprivate.hpp @@ -47,15 +47,6 @@ namespace CorUnix --*/ void PROCRemoveThread(CPalThread *pCurrentThread, CPalThread *pTargetThread); - /*++ - Function: - PROCGetNumberOfThreads - - Abstract - Return the number of threads in the thread list. - --*/ - INT PROCGetNumberOfThreads(void); - /*++ Function: From ce5cc143b39afbeb971089eba602e1398ea08398 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:21:56 +0000 Subject: [PATCH 07/15] Remove pGThreadList and related thread list maintenance code - Removed pGThreadList global variable (only used in debug-only PROCDumpThreadList) - Removed PROCAddThread function and its calls - Removed PROCRemoveThread function and its calls - Removed PROCDumpThreadList debug function - Removed declarations from procprivate.hpp and pal.cpp Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/init/pal.cpp | 10 -- src/coreclr/pal/src/init/sxs.cpp | 2 - src/coreclr/pal/src/thread/process.cpp | 127 +-------------------- src/coreclr/pal/src/thread/procprivate.hpp | 21 ---- src/coreclr/pal/src/thread/thread.cpp | 9 +- 5 files changed, 2 insertions(+), 167 deletions(-) diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index a1d5006a220050..6e0c9ead4dd5a1 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -119,10 +119,6 @@ static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv); static LPWSTR INIT_GetCurrentEXEPath(); static BOOL INIT_SharedFilesPath(void); -#ifdef _DEBUG -extern void PROCDumpThreadList(void); -#endif - /*++ Function: PAL_Initialize @@ -425,8 +421,6 @@ Initialize( goto CLEANUP1a; } - PROCAddThread(pThread, pThread); - // // It's now safe to access our thread data // @@ -817,10 +811,6 @@ PALCommonCleanup() // Let the synchronization manager know we're about to shutdown // CPalSynchMgrController::PrepareForShutdown(); - -#ifdef _DEBUG - PROCDumpThreadList(); -#endif } } diff --git a/src/coreclr/pal/src/init/sxs.cpp b/src/coreclr/pal/src/init/sxs.cpp index 8c55aa99c223dc..7ff673156a4dce 100644 --- a/src/coreclr/pal/src/init/sxs.cpp +++ b/src/coreclr/pal/src/init/sxs.cpp @@ -89,8 +89,6 @@ AllocatePalThread(CPalThread **ppThread) // possibly release it. (void)g_pObjectManager->RevokeHandle(pThread, hThread); - PROCAddThread(pThread, pThread); - // Unmask the activation signal so that GC can suspend this thread UnmaskActivationSignal(); diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 60b3f617493544..b69626814e5587 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -146,9 +146,8 @@ IPalObject* CorUnix::g_pobjProcess; minipal_mutex g_csProcess; // -// List and count of active threads +// The count of active threads // -CPalThread* CorUnix::pGThreadList; DWORD g_dwThreadCount; // @@ -2942,7 +2941,6 @@ CorUnix::InitializeProcessData( PAL_ERROR palError = NO_ERROR; bool fLockInitialized = FALSE; - pGThreadList = NULL; g_dwThreadCount = 0; minipal_mutex_init(&g_csProcess); @@ -3186,105 +3184,6 @@ PROCCleanupInitialProcess(VOID) } -/*++ -Function: - PROCAddThread - -Abstract - Add a thread to the thread list of the current process - -Parameter - pThread: Thread object - ---*/ -VOID -CorUnix::PROCAddThread( - CPalThread *pCurrentThread, - CPalThread *pTargetThread - ) -{ - /* protect the access of the thread list with critical section for - mutithreading access */ - minipal_mutex_enter(&g_csProcess); - - pTargetThread->SetNext(pGThreadList); - pGThreadList = pTargetThread; - g_dwThreadCount += 1; - - TRACE("Thread 0x%p (id %#x) added to the process thread list\n", - pTargetThread, pTargetThread->GetThreadId()); - - minipal_mutex_leave(&g_csProcess); -} - - -/*++ -Function: - PROCRemoveThread - -Abstract - Remove a thread form the thread list of the current process - -Parameter - CPalThread *pThread : thread object to remove - -(no return value) ---*/ -VOID -CorUnix::PROCRemoveThread( - CPalThread *pCurrentThread, - CPalThread *pTargetThread - ) -{ - CPalThread *curThread, *prevThread; - - /* protect the access of the thread list with critical section for - mutithreading access */ - minipal_mutex_enter(&g_csProcess); - - curThread = pGThreadList; - - /* if thread list is empty */ - if (curThread == NULL) - { - ASSERT("Thread list is empty.\n"); - goto EXIT; - } - - /* do we remove the first thread? */ - if (curThread == pTargetThread) - { - pGThreadList = curThread->GetNext(); - TRACE("Thread 0x%p (id %#x) removed from the process thread list\n", - pTargetThread, pTargetThread->GetThreadId()); - goto EXIT; - } - - prevThread = curThread; - curThread = curThread->GetNext(); - /* find the thread to remove */ - while (curThread != NULL) - { - if (curThread == pTargetThread) - { - /* found, fix the chain list */ - prevThread->SetNext(curThread->GetNext()); - g_dwThreadCount -= 1; - TRACE("Thread %p removed from the process thread list\n", pTargetThread); - goto EXIT; - } - - prevThread = curThread; - curThread = curThread->GetNext(); - } - - WARN("Thread %p not removed (it wasn't found in the list)\n", pTargetThread); - -EXIT: - minipal_mutex_leave(&g_csProcess); -} - - /*++ Function: PROCProcessLock @@ -3600,30 +3499,6 @@ bool GetApplicationContainerFolder(PathCharString& buffer, const char *applicati } #endif // __APPLE__ -#ifdef _DEBUG -void PROCDumpThreadList() -{ - CPalThread *pThread; - - PROCProcessLock(); - - TRACE ("Threads:{\n"); - - pThread = pGThreadList; - while (NULL != pThread) - { - TRACE (" {pThr=0x%p tid=%#x lwpid=%#x state=%d}\n", - pThread, (int)pThread->GetThreadId(), (int)pThread->GetLwpId(), - (int)pThread->synchronizationInfo.GetThreadState()); - - pThread = pThread->GetNext(); - } - TRACE ("Threads:}\n"); - - PROCProcessUnlock(); -} -#endif - /* Internal function definitions **********************************************/ /*++ diff --git a/src/coreclr/pal/src/thread/procprivate.hpp b/src/coreclr/pal/src/thread/procprivate.hpp index 6922ebf3f1f228..f59f1d33158fb8 100644 --- a/src/coreclr/pal/src/thread/procprivate.hpp +++ b/src/coreclr/pal/src/thread/procprivate.hpp @@ -27,27 +27,6 @@ Revision History: namespace CorUnix { - /*++ - Function: - PROCAddThread - - Abstract - Add a thread to the thread list of the current process - --*/ - void PROCAddThread(CPalThread *pCurrentThread, CPalThread *pTargetThread); - - extern CPalThread *pGThreadList; - - /*++ - Function: - PROCRemoveThread - - Abstract - Remove a thread form the thread list of the current process - --*/ - void PROCRemoveThread(CPalThread *pCurrentThread, CPalThread *pTargetThread); - - /*++ Function: TerminateCurrentProcessNoExit diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index 632baafa4308ec..fc46c5df9b0942 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -597,7 +597,6 @@ CorUnix::InternalCreateThread( PROCProcessLock(); fHoldingProcessLock = TRUE; - PROCAddThread(pThread, pNewThread); fThreadDataAddedToProcessList = TRUE; // @@ -675,10 +674,6 @@ CorUnix::InternalCreateThread( // resources here // - if (fThreadDataAddedToProcessList) - { - PROCRemoveThread(pThread, pNewThread); - } // // Once we remove the thread from the process list, we can call // PROCProcessUnlock. @@ -789,12 +784,10 @@ CorUnix::InternalEndCurrentThread( pThread->GetThreadObject()->ReleaseReference(pThread); - /* Remove thread for the thread list of the process + /* Remove thread from the thread list of the process (don't do if this is the last thread -> gets handled by TerminateProcess->PROCCleanupProcess->PROCTerminateOtherThreads) */ - PROCRemoveThread(pThread, pThread); - // Ensure that EH is disabled on the current thread SEHDisable(pThread); From 6bcf290814000a22b989e21250ab5845c0eec9b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:46:28 +0000 Subject: [PATCH 08/15] Remove g_dwThreadCount dead code - Removed unused g_dwThreadCount global variable - This variable was only incremented/decremented in the removed PROCAddThread/PROCRemoveThread functions Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/thread/process.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index b69626814e5587..4deeff6a3678dc 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -145,11 +145,6 @@ IPalObject* CorUnix::g_pobjProcess; // minipal_mutex g_csProcess; -// -// The count of active threads -// -DWORD g_dwThreadCount; - // // The command line and app name for the process // @@ -2941,8 +2936,6 @@ CorUnix::InitializeProcessData( PAL_ERROR palError = NO_ERROR; bool fLockInitialized = FALSE; - g_dwThreadCount = 0; - minipal_mutex_init(&g_csProcess); fLockInitialized = TRUE; From 8472065c64e90be9ec77c78fa193433029814b32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 20:12:42 +0000 Subject: [PATCH 09/15] Remove fThreadDataAddedToProcessList and stale comment - Removed unused fThreadDataAddedToProcessList variable (set but never read) - Removed stale comment about removing thread from process list Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/thread/thread.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index fc46c5df9b0942..7f707f062790d1 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -438,7 +438,6 @@ CorUnix::InternalCreateThread( CPalThread *pNewThread = NULL; CObjectAttributes oa; bool fAttributesInitialized = FALSE; - bool fThreadDataAddedToProcessList = FALSE; HANDLE hNewThread = NULL; pthread_t pthread; @@ -597,8 +596,6 @@ CorUnix::InternalCreateThread( PROCProcessLock(); fHoldingProcessLock = TRUE; - fThreadDataAddedToProcessList = TRUE; - // // Spawn the new pthread // @@ -784,10 +781,6 @@ CorUnix::InternalEndCurrentThread( pThread->GetThreadObject()->ReleaseReference(pThread); - /* Remove thread from the thread list of the process - (don't do if this is the last thread -> gets handled by - TerminateProcess->PROCCleanupProcess->PROCTerminateOtherThreads) */ - // Ensure that EH is disabled on the current thread SEHDisable(pThread); From cf8e1cf8aa110d26724b6dc8bbdfa0494313f699 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:40:56 +0000 Subject: [PATCH 10/15] Remove g_csProcess and simplify PROCProcessLock/Unlock - Removed g_csProcess global mutex variable - Simplified InitializeProcessData to return NO_ERROR directly - Simplified PROCCleanupInitialProcess by removing mutex operations - Converted PROCProcessLock and PROCProcessUnlock to no-ops (kept for compatibility) Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/thread/process.cpp | 48 +++----------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 4deeff6a3678dc..b160731e69b705 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -140,10 +140,8 @@ CAllowedObjectTypes aotProcess(otiProcess); IPalObject* CorUnix::g_pobjProcess; // -// Critical section that protects process data (e.g., the -// list of active threads)/ +// Critical section that protects process data // -minipal_mutex g_csProcess; // // The command line and app name for the process @@ -2933,21 +2931,7 @@ CorUnix::InitializeProcessData( void ) { - PAL_ERROR palError = NO_ERROR; - bool fLockInitialized = FALSE; - - minipal_mutex_init(&g_csProcess); - fLockInitialized = TRUE; - - if (NO_ERROR != palError) - { - if (fLockInitialized) - { - minipal_mutex_destroy(&g_csProcess); - } - } - - return palError; + return NO_ERROR; } /*++ @@ -3160,16 +3144,12 @@ PROCCleanupInitialProcess(VOID) { CPalThread *pThread = InternalGetCurrentThread(); - minipal_mutex_enter(&g_csProcess); - /* Free the application directory */ free(g_lpwstrAppDir); /* Free the stored command line */ free(g_lpwstrCmdLine); - minipal_mutex_leave(&g_csProcess); - // // Object manager shutdown will handle freeing the underlying // thread and process data @@ -3182,22 +3162,12 @@ PROCCleanupInitialProcess(VOID) PROCProcessLock Abstract - Enter the critical section associated to the current process - -Parameter - void - -Return - void + No-op function kept for compatibility --*/ VOID PROCProcessLock( VOID) { - CPalThread * pThread = - (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL); - - minipal_mutex_enter(&g_csProcess); } @@ -3206,22 +3176,12 @@ PROCProcessLock( PROCProcessUnlock Abstract - Leave the critical section associated to the current process - -Parameter - void - -Return - void + No-op function kept for compatibility --*/ VOID PROCProcessUnlock( VOID) { - CPalThread * pThread = - (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL); - - minipal_mutex_leave(&g_csProcess); } /*++ Function: From b5640a9a3764c3c74fe4aa6ecc581eb6c9546d32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 23:33:56 +0000 Subject: [PATCH 11/15] Remove stale critical section comment Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/thread/process.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index b160731e69b705..02da9b5cd3b207 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -139,10 +139,6 @@ CAllowedObjectTypes aotProcess(otiProcess); // IPalObject* CorUnix::g_pobjProcess; -// -// Critical section that protects process data -// - // // The command line and app name for the process // From c4eb3b28e4f9761104d64ae55cc4b48bfadf2e42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 23:58:23 +0000 Subject: [PATCH 12/15] Remove dead code: PROCProcessLock and PROCProcessUnlock functions - Remove PROCProcessLock and PROCProcessUnlock function definitions from process.cpp - Remove function declarations from process.h - Remove all usages in thread.cpp including fHoldingProcessLock variable - These were no-op functions that no longer provide any synchronization Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/pal/src/include/pal/process.h | 19 -------------- src/coreclr/pal/src/thread/process.cpp | 26 ------------------ src/coreclr/pal/src/thread/thread.cpp | 32 ----------------------- 3 files changed, 77 deletions(-) diff --git a/src/coreclr/pal/src/include/pal/process.h b/src/coreclr/pal/src/include/pal/process.h index 45529a1edff900..fa2d24df05c418 100644 --- a/src/coreclr/pal/src/include/pal/process.h +++ b/src/coreclr/pal/src/include/pal/process.h @@ -95,25 +95,6 @@ Return --*/ VOID PROCCleanupInitialProcess(VOID); -/*++ -Function: - PROCProcessLock - -Abstract - Enter the critical section associated to the current process ---*/ -VOID PROCProcessLock(VOID); - - -/*++ -Function: - PROCProcessUnlock - -Abstract - Leave the critical section associated to the current process ---*/ -VOID PROCProcessUnlock(VOID); - /*++ Function PROCAbortInitialize() diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 02da9b5cd3b207..a081209a1b457f 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -3153,32 +3153,6 @@ PROCCleanupInitialProcess(VOID) } -/*++ -Function: - PROCProcessLock - -Abstract - No-op function kept for compatibility ---*/ -VOID -PROCProcessLock( - VOID) -{ -} - - -/*++ -Function: - PROCProcessUnlock - -Abstract - No-op function kept for compatibility ---*/ -VOID -PROCProcessUnlock( - VOID) -{ -} /*++ Function: TerminateCurrentProcessNoExit diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index 7f707f062790d1..c17a3e75484150 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -445,7 +445,6 @@ CorUnix::InternalCreateThread( #if PTHREAD_CREATE_MODIFIES_ERRNO int storedErrno; #endif // PTHREAD_CREATE_MODIFIES_ERRNO - BOOL fHoldingProcessLock = FALSE; int iError = 0; size_t alignedStackSize; @@ -585,17 +584,6 @@ CorUnix::InternalCreateThread( // Add the thread to the process list // - // - // We use the process lock to ensure that we're not interrupted - // during the creation process. After adding the CPalThread reference - // to the process list, we want to make sure the actual thread has been - // started. Otherwise, there's a window where the thread can be found - // in the process list but doesn't yet exist in the system. - // - - PROCProcessLock(); - fHoldingProcessLock = TRUE; - // // Spawn the new pthread // @@ -645,14 +633,6 @@ CorUnix::InternalCreateThread( goto EXIT; } - // - // If we're here, then we've locked the process list and both pthread_create - // and WaitForStartStatus succeeded. Thus, we can now unlock the process list. - // Since palError == NO_ERROR, we won't call this again in the exit block. - // - PROCProcessUnlock(); - fHoldingProcessLock = FALSE; - EXIT: if (fAttributesInitialized) @@ -670,20 +650,8 @@ CorUnix::InternalCreateThread( // occurred in the new thread's entry routine. Free up the associated // resources here // - - // - // Once we remove the thread from the process list, we can call - // PROCProcessUnlock. - // - if (fHoldingProcessLock) - { - PROCProcessUnlock(); - } - fHoldingProcessLock = FALSE; } - _ASSERT_MSG(!fHoldingProcessLock, "Exiting InternalCreateThread while still holding the process critical section.\n"); - return palError; } From e4790aed64d06971eca552e26c82b91398b5e311 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 5 Feb 2026 18:09:49 -0800 Subject: [PATCH 13/15] Feedback --- eng/native/tryrun.browser.cmake | 6 ---- eng/native/tryrun.cmake | 6 +--- eng/native/tryrun_ios_tvos.cmake | 2 -- src/coreclr/pal/src/config.h.in | 2 -- src/coreclr/pal/src/configure.cmake | 48 +-------------------------- src/coreclr/pal/src/thread/thread.cpp | 24 -------------- 6 files changed, 2 insertions(+), 86 deletions(-) diff --git a/eng/native/tryrun.browser.cmake b/eng/native/tryrun.browser.cmake index 15ec4d234974b0..71b3f48baad1d1 100644 --- a/eng/native/tryrun.browser.cmake +++ b/eng/native/tryrun.browser.cmake @@ -378,13 +378,7 @@ set(HAVE_YIELD_SYSCALL "" CACHE INTERNAL "") set(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_COMPILED TRUE CACHE INTERNAL "") set_cache_value(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE 1) set(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS "" CACHE INTERNAL "") -set(PTHREAD_CREATE_MODIFIES_ERRNO_COMPILED TRUE CACHE INTERNAL "") -set_cache_value(PTHREAD_CREATE_MODIFIES_ERRNO_EXITCODE 1) -set(PTHREAD_CREATE_MODIFIES_ERRNO "" CACHE INTERNAL "") set(PTHREAD_RWLOCK_T 32 CACHE INTERNAL "") set(REALPATH_SUPPORTS_NONEXISTENT_FILES_COMPILED TRUE CACHE INTERNAL "") set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) set(REALPATH_SUPPORTS_NONEXISTENT_FILES "" CACHE INTERNAL "") -set(SEM_INIT_MODIFIES_ERRNO_COMPILED TRUE CACHE INTERNAL "") -set_cache_value(SEM_INIT_MODIFIES_ERRNO_EXITCODE 1) -set(SEM_INIT_MODIFIES_ERRNO "" CACHE INTERNAL "") diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index ed879865a21daa..57e5f0827b8db9 100644 --- a/eng/native/tryrun.cmake +++ b/eng/native/tryrun.cmake @@ -68,9 +68,7 @@ if(DARWIN AND NOT DEFINED ANDROID_BUILD) set_cache_value(HAVE_WORKING_GETTIMEOFDAY_EXITCODE 0) set_cache_value(MMAP_ANON_IGNORES_PROTECTION_EXITCODE 1) set_cache_value(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE 1) - set_cache_value(PTHREAD_CREATE_MODIFIES_ERRNO_EXITCODE 1) set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) - set_cache_value(SEM_INIT_MODIFIES_ERRNO_EXITCODE 1) set_cache_value(HAVE_SHM_OPEN_THAT_WORKS_WELL_ENOUGH_WITH_MMAP_EXITCODE 1) else() message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only arm64 or x64 is supported for OSX cross build!") @@ -89,10 +87,8 @@ else() set_cache_value(HAVE_WORKING_CLOCK_GETTIME_EXITCODE 0) set_cache_value(HAVE_WORKING_GETTIMEOFDAY_EXITCODE 0) set_cache_value(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE 1) - set_cache_value(PTHREAD_CREATE_MODIFIES_ERRNO_EXITCODE 1) set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) - set_cache_value(SEM_INIT_MODIFIES_ERRNO_EXITCODE 1) - + if(ALPINE_LINUX) set_cache_value(HAVE_SHM_OPEN_THAT_WORKS_WELL_ENOUGH_WITH_MMAP_EXITCODE 1) else() diff --git a/eng/native/tryrun_ios_tvos.cmake b/eng/native/tryrun_ios_tvos.cmake index bfeb06c78e84ad..7b98f6dcd055ef 100644 --- a/eng/native/tryrun_ios_tvos.cmake +++ b/eng/native/tryrun_ios_tvos.cmake @@ -24,7 +24,5 @@ set_cache_value(HAVE_WORKING_CLOCK_GETTIME_EXITCODE 0) set_cache_value(HAVE_WORKING_GETTIMEOFDAY_EXITCODE 0) set_cache_value(MMAP_ANON_IGNORES_PROTECTION_EXITCODE 1) set_cache_value(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE 1) -set_cache_value(PTHREAD_CREATE_MODIFIES_ERRNO_EXITCODE 1) set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) -set_cache_value(SEM_INIT_MODIFIES_ERRNO_EXITCODE 1) set_cache_value(HAVE_SHM_OPEN_THAT_WORKS_WELL_ENOUGH_WITH_MMAP_EXITCODE 1) diff --git a/src/coreclr/pal/src/config.h.in b/src/coreclr/pal/src/config.h.in index 342045da832de8..49795de0a3dc41 100644 --- a/src/coreclr/pal/src/config.h.in +++ b/src/coreclr/pal/src/config.h.in @@ -90,8 +90,6 @@ #cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK #cmakedefine01 MMAP_ANON_IGNORES_PROTECTION #cmakedefine01 ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS -#cmakedefine01 PTHREAD_CREATE_MODIFIES_ERRNO -#cmakedefine01 SEM_INIT_MODIFIES_ERRNO #cmakedefine01 HAVE_PROCFS_CTL #cmakedefine01 HAVE_PROCFS_STAT diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake index 3876f96feca3b9..3bae23f79ac427 100644 --- a/src/coreclr/pal/src/configure.cmake +++ b/src/coreclr/pal/src/configure.cmake @@ -497,52 +497,6 @@ int main(void) exit(ret != 1); }" ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS) -set(CMAKE_REQUIRED_LIBRARIES pthread) -check_cxx_source_runs(" -#include -#include -#include - -void *start_routine(void *param) { return NULL; } - -int main() { - int result; - pthread_t tid; - - errno = 0; - result = pthread_create(&tid, NULL, start_routine, NULL); - if (result != 0) { - exit(1); - } - if (errno != 0) { - exit(0); - } - exit(1); -}" PTHREAD_CREATE_MODIFIES_ERRNO) -set(CMAKE_REQUIRED_LIBRARIES) -set(CMAKE_REQUIRED_LIBRARIES pthread) -check_cxx_source_runs(" -#include -#include -#include - -int main() { - int result; - sem_t sema; - - errno = 50; - result = sem_init(&sema, 0, 0); - if (result != 0) - { - exit(1); - } - if (errno != 50) - { - exit(0); - } - exit(1); -}" SEM_INIT_MODIFIES_ERRNO) -set(CMAKE_REQUIRED_LIBRARIES) check_cxx_source_runs(" #include #include @@ -566,7 +520,7 @@ int main(void) { } exit(0); }" HAVE_PROCFS_CTL) -set(CMAKE_REQUIRED_LIBRARIES) + check_cxx_source_runs(" #include #include diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index c17a3e75484150..9f3bd6e66297c3 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -442,9 +442,6 @@ CorUnix::InternalCreateThread( pthread_t pthread; pthread_attr_t pthreadAttr; -#if PTHREAD_CREATE_MODIFIES_ERRNO - int storedErrno; -#endif // PTHREAD_CREATE_MODIFIES_ERRNO int iError = 0; size_t alignedStackSize; @@ -588,20 +585,8 @@ CorUnix::InternalCreateThread( // Spawn the new pthread // -#if PTHREAD_CREATE_MODIFIES_ERRNO - storedErrno = errno; -#endif // PTHREAD_CREATE_MODIFIES_ERRNO - iError = pthread_create(&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread); -#if PTHREAD_CREATE_MODIFIES_ERRNO - if (iError == 0) - { - // Restore errno if pthread_create succeeded. - errno = storedErrno; - } -#endif // PTHREAD_CREATE_MODIFIES_ERRNO - if (0 != iError) { ERROR("pthread_create failed, error is %d (%s)\n", iError, strerror(iError)); @@ -643,15 +628,6 @@ CorUnix::InternalCreateThread( } } - if (NO_ERROR != palError) - { - // - // We either were not able to create the new thread, or a failure - // occurred in the new thread's entry routine. Free up the associated - // resources here - // - } - return palError; } From 613e79fc977c57b3d54872c9460cdf30a391ff1f Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 5 Feb 2026 18:22:27 -0800 Subject: [PATCH 14/15] Update eng/native/tryrun.cmake Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- eng/native/tryrun.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index 57e5f0827b8db9..32ce86cc0fae94 100644 --- a/eng/native/tryrun.cmake +++ b/eng/native/tryrun.cmake @@ -88,7 +88,6 @@ else() set_cache_value(HAVE_WORKING_GETTIMEOFDAY_EXITCODE 0) set_cache_value(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE 1) set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) - if(ALPINE_LINUX) set_cache_value(HAVE_SHM_OPEN_THAT_WORKS_WELL_ENOUGH_WITH_MMAP_EXITCODE 1) else() From 128d0622d5a1a19130614afd7634b74ba4e27a4b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 5 Feb 2026 18:27:04 -0800 Subject: [PATCH 15/15] More --- src/coreclr/pal/src/include/pal/procobj.hpp | 5 ----- src/coreclr/pal/src/init/pal.cpp | 11 ----------- src/coreclr/pal/src/thread/process.cpp | 11 ----------- 3 files changed, 27 deletions(-) diff --git a/src/coreclr/pal/src/include/pal/procobj.hpp b/src/coreclr/pal/src/include/pal/procobj.hpp index 12245042648418..80f9aa327a1058 100644 --- a/src/coreclr/pal/src/include/pal/procobj.hpp +++ b/src/coreclr/pal/src/include/pal/procobj.hpp @@ -88,11 +88,6 @@ namespace CorUnix LPPROCESS_INFORMATION lpProcessInformation ); - PAL_ERROR - InitializeProcessData( - void - ); - PAL_ERROR InitializeProcessCommandLine( LPWSTR lpwstrCmdLine, diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index 6e0c9ead4dd5a1..b14b31c96007f1 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -388,17 +388,6 @@ Initialize( // we use large numbers of threads or have many open files. } - // - // Initialize global process data - // - - palError = InitializeProcessData(); - if (NO_ERROR != palError) - { - ERROR("Unable to initialize process data\n"); - goto CLEANUP1; - } - #if HAVE_MACH_EXCEPTIONS // Mach exception port needs to be set up before the thread // data or threads are set up. diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index a081209a1b457f..5cd4a18b074175 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -2922,14 +2922,6 @@ PROCGetProcessIDFromHandle( return dwProcessId; } -PAL_ERROR -CorUnix::InitializeProcessData( - void - ) -{ - return NO_ERROR; -} - /*++ Function InitializeProcessCommandLine @@ -3138,8 +3130,6 @@ Return VOID PROCCleanupInitialProcess(VOID) { - CPalThread *pThread = InternalGetCurrentThread(); - /* Free the application directory */ free(g_lpwstrAppDir); @@ -3150,7 +3140,6 @@ PROCCleanupInitialProcess(VOID) // Object manager shutdown will handle freeing the underlying // thread and process data // - } /*++