From 653367263c06ce820c18ab7836d01e0bf0f51e55 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 21 Aug 2026 17:51:25 +0000 Subject: [PATCH 1/9] Remove CoreCLR PAL semaphore support Add a minipal read-write lock and use it for metadata synchronization. Remove the PAL semaphore implementation, exports, and tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dlls/mscordac/mscordac_unixexports.src | 2 - src/coreclr/inc/corhost.h | 3 - src/coreclr/inc/corpriv.h | 7 +- src/coreclr/inc/metadata.h | 6 +- src/coreclr/inc/utsem.h | 53 -- src/coreclr/inc/winwrap.h | 3 - src/coreclr/md/compiler/mdutil.cpp | 39 +- src/coreclr/md/compiler/mdutil.h | 4 +- src/coreclr/md/compiler/regmeta.cpp | 41 +- src/coreclr/md/compiler/regmeta.h | 15 +- src/coreclr/md/compiler/stdafx.h | 2 - src/coreclr/md/enc/mdinternalrw.cpp | 44 +- src/coreclr/md/enc/metamodelrw.cpp | 5 +- src/coreclr/md/enc/rwutil.cpp | 200 +++++-- src/coreclr/md/enc/stdafx.h | 2 - src/coreclr/md/inc/mdinternalrw.h | 18 +- src/coreclr/md/inc/metamodelrw.h | 15 +- src/coreclr/md/inc/rwutil.h | 55 +- src/coreclr/md/runtime/mdinternalro.h | 4 +- src/coreclr/pal/inc/pal.h | 32 -- src/coreclr/pal/inc/pal_error.h | 2 - src/coreclr/pal/src/CMakeLists.txt | 1 - src/coreclr/pal/src/include/pal/corunix.hpp | 2 - src/coreclr/pal/src/include/pal/semaphore.hpp | 64 --- src/coreclr/pal/src/misc/errorstrings.cpp | 1 - src/coreclr/pal/src/synchmgr/wait.cpp | 5 +- src/coreclr/pal/src/synchobj/semaphore.cpp | 488 ----------------- src/coreclr/pal/tests/palsuite/CMakeLists.txt | 6 - .../pal/tests/palsuite/compilableTests.txt | 6 - .../pal/tests/palsuite/paltestlist.txt | 5 - .../palsuite/paltestlist_to_be_reviewed.txt | 1 - .../test1/CreateSemaphore.cpp | 320 ----------- .../test2/CreateSemaphore.cpp | 314 ----------- .../test3/createsemaphore.cpp | 205 ------- .../DuplicateHandle/test10/test10.cpp | 240 --------- .../WFSOSemaphoreTest/WFSOSemaphoreTest.cpp | 184 ------- .../threading/releasesemaphore/test1/test.cpp | 67 --- src/coreclr/utilcode/CMakeLists.txt | 1 - src/coreclr/utilcode/utsem.cpp | 504 ------------------ src/coreclr/vm/gccover.cpp | 1 - src/native/minipal/CMakeLists.txt | 1 + src/native/minipal/configure.cmake | 9 + src/native/minipal/minipalconfig.h.in | 1 + src/native/minipal/rwlock.c | 91 ++++ src/native/minipal/rwlock.h | 49 ++ 45 files changed, 452 insertions(+), 2666 deletions(-) delete mode 100644 src/coreclr/inc/utsem.h delete mode 100644 src/coreclr/pal/src/include/pal/semaphore.hpp delete mode 100644 src/coreclr/pal/src/synchobj/semaphore.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/releasesemaphore/test1/test.cpp delete mode 100644 src/coreclr/utilcode/utsem.cpp create mode 100644 src/native/minipal/rwlock.c create mode 100644 src/native/minipal/rwlock.h diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index 479c850b781f4b..895a13c032264a 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -62,7 +62,6 @@ nativeStringResourceTable_mscorrc #CreateFileW #CreateEventW #CreateEventExW -#CreateSemaphoreExW #CreateThread #CloseHandle #DebugBreak @@ -98,7 +97,6 @@ nativeStringResourceTable_mscorrc #RaiseException #RaiseFailFastException #ReadFile -#ReleaseSemaphore #ResetEvent #ResumeThread #SearchPathW diff --git a/src/coreclr/inc/corhost.h b/src/coreclr/inc/corhost.h index bebeeba9ac8523..957369214e6fac 100644 --- a/src/coreclr/inc/corhost.h +++ b/src/coreclr/inc/corhost.h @@ -17,9 +17,6 @@ #include "windows.h" // worth to include before mscoree.h so we are guaranteed to pick few definitions -#ifdef CreateSemaphore -#undef CreateSemaphore -#endif #include "mscoree.h" diff --git a/src/coreclr/inc/corpriv.h b/src/coreclr/inc/corpriv.h index 0339f3b7e49851..5df28e8d8ba851 100644 --- a/src/coreclr/inc/corpriv.h +++ b/src/coreclr/inc/corpriv.h @@ -13,9 +13,6 @@ #include "corimage.h" #include "metadata.h" - -class UTSemReadWrite; - // Creation function to get IMetaDataDispenser(Ex) interface. STDAPI CreateMetaDataDispenser( REFIID riid, @@ -112,8 +109,8 @@ DECLARE_INTERFACE_(IMetaDataHelper, IUnknown) STDMETHOD_(IUnknown *, GetCachedInternalInterface)(BOOL fWithLock) PURE; // S_OK or error STDMETHOD(SetCachedInternalInterface)(IUnknown * pUnk) PURE; // S_OK or error - STDMETHOD_(UTSemReadWrite*, GetReaderWriterLock)() PURE; // return the reader writer lock - STDMETHOD(SetReaderWriterLock)(UTSemReadWrite * pSem) PURE; + STDMETHOD_(minipal_rwlock*, GetReaderWriterLock)() PURE; // return the reader writer lock + STDMETHOD(SetReaderWriterLock)(minipal_rwlock * pLock) PURE; }; // IMetaDataHelper diff --git a/src/coreclr/inc/metadata.h b/src/coreclr/inc/metadata.h index 19083c932a35c1..0ccd84eca08ab9 100644 --- a/src/coreclr/inc/metadata.h +++ b/src/coreclr/inc/metadata.h @@ -14,10 +14,10 @@ #define _METADATA_H_ #include "ex.h" +#include class IMetaModelCommon; class MDInternalRW; -class UTSemReadWrite; inline int IsGlobalMethodParentTk(mdTypeDef td) { @@ -950,9 +950,9 @@ DECLARE_INTERFACE_(IMDInternalImport, IUnknown) STDMETHOD_(IUnknown *, GetCachedPublicInterface)(BOOL fWithLock) PURE; // return the cached public interface __checkReturn STDMETHOD(SetCachedPublicInterface)(IUnknown *pUnk) PURE; // no return value - STDMETHOD_(UTSemReadWrite*, GetReaderWriterLock)() PURE; // return the reader writer lock + STDMETHOD_(minipal_rwlock*, GetReaderWriterLock)() PURE; // return the reader writer lock __checkReturn - STDMETHOD(SetReaderWriterLock)(UTSemReadWrite * pSem) PURE; + STDMETHOD(SetReaderWriterLock)(minipal_rwlock * pLock) PURE; STDMETHOD_(mdModule, GetModuleFromScope)() PURE; // [OUT] Put mdModule token here. diff --git a/src/coreclr/inc/utsem.h b/src/coreclr/inc/utsem.h deleted file mode 100644 index a33cc0535d3411..00000000000000 --- a/src/coreclr/inc/utsem.h +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - - -/* ---------------------------------------------------------------------------- - ----------------------------------------------------------------------------- */ -#ifndef __UTSEM_H__ -#define __UTSEM_H__ - - -// ------------------------------------------------------------- -// INCLUDES -// ------------------------------------------------------------- -#include "utilcode.h" - -/* ---------------------------------------------------------------------------- -@class UTSemReadWrite - - An instance of class UTSemReadWrite provides multi-read XOR single-write - (a.k.a. shared vs. exclusive) lock capabilities, with protection against - writer starvation. - - A thread MUST NOT call any of the Lock methods if it already holds a Lock. - (Doing so may result in a deadlock.) - - ----------------------------------------------------------------------------- */ -class UTSemReadWrite -{ -public: - UTSemReadWrite(); // Constructor - ~UTSemReadWrite(); // Destructor - - HRESULT Init(); - - HRESULT LockRead(); // Lock the object for reading - HRESULT LockWrite(); // Lock the object for writing - void UnlockRead(); // Unlock the object for reading - void UnlockWrite(); // Unlock the object for writing - -#ifdef _DEBUG - BOOL Debug_IsLockedForRead(); - BOOL Debug_IsLockedForWrite(); -#endif //_DEBUG - -private: - Volatile m_dwFlag; // internal state, see implementation - HANDLE m_hReadWaiterSemaphore; // semaphore for awakening read waiters - HANDLE m_hWriteWaiterEvent; // event for awakening write waiters -}; // class UTSemReadWrite - -#endif // __UTSEM_H__ diff --git a/src/coreclr/inc/winwrap.h b/src/coreclr/inc/winwrap.h index 2e8946aa50205f..1d16e5ff300ed5 100644 --- a/src/coreclr/inc/winwrap.h +++ b/src/coreclr/inc/winwrap.h @@ -25,9 +25,6 @@ #include "palclr.h" -#undef CreateSemaphore -#define CreateSemaphore(_secattr, _count, _maxcount, _name) CreateSemaphoreExW((_secattr), (_count), (_maxcount), (_name), 0, MAXIMUM_ALLOWED | SYNCHRONIZE | SEMAPHORE_MODIFY_STATE) - #undef GetFileVersionInfo #define GetFileVersionInfo(_filename, _handle, _len, _data) GetFileVersionInfoEx(0, (_filename), (_handle), (_len), (_data)) #undef GetFileVersionInfoSize diff --git a/src/coreclr/md/compiler/mdutil.cpp b/src/coreclr/md/compiler/mdutil.cpp index 03f4d1a429569e..ae79fca0369d43 100644 --- a/src/coreclr/md/compiler/mdutil.cpp +++ b/src/coreclr/md/compiler/mdutil.cpp @@ -22,7 +22,7 @@ #if defined(FEATURE_METADATA_IN_VM) LOADEDMODULES * LOADEDMODULES::s_pLoadedModules = NULL; -UTSemReadWrite * LOADEDMODULES::m_pSemReadWrite = NULL; +minipal_rwlock * LOADEDMODULES::m_pReadWriteLock = NULL; //--------------------------------------------------------------------------------------- // @@ -37,14 +37,15 @@ LOADEDMODULES::InitializeStatics() { // Initialize global read-write lock { - NewHolder pSemReadWrite = new (nothrow) UTSemReadWrite(); - IfNullGo(pSemReadWrite); - IfFailGo(pSemReadWrite->Init()); + minipal_rwlock *pReadWriteLock = NULL; + IfFailGo(CreateMDReadWriteLock(&pReadWriteLock)); - if (InterlockedCompareExchangeT(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL) + if (InterlockedCompareExchangeT(&m_pReadWriteLock, pReadWriteLock, NULL) == NULL) { // We won the initialization race - pSemReadWrite.SuppressRelease(); + pReadWriteLock = NULL; } + + DestroyMDReadWriteLock(pReadWriteLock); } // Initialize the global instance @@ -53,7 +54,8 @@ LOADEDMODULES::InitializeStatics() IfNullGo(pLoadedModules); { - LOCKWRITE(); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + IfFailGo(lockHolder.LockWrite()); if (VolatileLoad(&s_pLoadedModules) == NULL) { @@ -78,7 +80,8 @@ HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta * pRegMeta) IfFailGo(InitializeStatics()); { - LOCKWRITE(); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + IfFailGo(lockHolder.LockWrite()); ppRegMeta = s_pLoadedModules->Append(); IfNullGo(ppRegMeta); @@ -110,7 +113,8 @@ BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta) IfFailGo(InitializeStatics()); { - LOCKWRITE(); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + IfFailGo(lockHolder.LockWrite()); // Search for this module in list of loaded modules. int count = s_pLoadedModules->Count(); @@ -174,7 +178,8 @@ BOOL LOADEDMODULES::IsEntryInList( IfFailGo(InitializeStatics()); { - LOCKREAD(); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + IfFailGo(lockHolder.LockRead()); // Loop through each loaded modules int count = s_pLoadedModules->Count(); @@ -219,7 +224,8 @@ LOADEDMODULES::ResolveTypeRefWithLoadedModules( IfFailGo(InitializeStatics()); { - LOCKREAD(); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + IfFailGo(lockHolder.LockRead()); // Get the Nesting hierarchy. IfFailGo(ImportHelper::GetNesterHierarchy( @@ -236,11 +242,12 @@ LOADEDMODULES::ResolveTypeRefWithLoadedModules( { // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller. - // The code:UTSemReadWrite will block ReadLock even for thread holding already the read lock if - // some other thread is waiting for WriteLock on the same lock. That would cause dead-lock if we - // try to lock for read again here. - CMDSemReadWrite cSemRegMeta((pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock()); - IfFailGo(cSemRegMeta.LockRead()); + // The read-write lock may block a recursive read acquisition while a writer is waiting. + // Avoid taking the TypeRef RegMeta lock again because the caller already holds it for reading. + CMDReadWriteLock regMetaLock( + (pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock() + COMMA_INDEBUG(pRegMeta->GetMiniMd())); + IfFailGo(regMetaLock.LockRead()); hr = ImportHelper::FindNestedTypeDef( pRegMeta->GetMiniMd(), diff --git a/src/coreclr/md/compiler/mdutil.h b/src/coreclr/md/compiler/mdutil.h index a66a2125c4400d..41df9aeaa0007d 100644 --- a/src/coreclr/md/compiler/mdutil.h +++ b/src/coreclr/md/compiler/mdutil.h @@ -38,8 +38,6 @@ class RegMeta; // this list. // //********************************************************************* -class UTSemReadWrite; - class LOADEDMODULES : public CDynArray { private: @@ -50,7 +48,7 @@ class LOADEDMODULES : public CDynArray public: // Named for locking macros - see code:LOCKREAD - static UTSemReadWrite * m_pSemReadWrite; + static minipal_rwlock * m_pReadWriteLock; static HRESULT AddModuleToLoadedList(RegMeta *pRegMeta); static BOOL RemoveModuleFromLoadedList(RegMeta *pRegMeta); // true if found and removed. diff --git a/src/coreclr/md/compiler/regmeta.cpp b/src/coreclr/md/compiler/regmeta.cpp index 07823d66df9b29..4db11c23da9c8b 100644 --- a/src/coreclr/md/compiler/regmeta.cpp +++ b/src/coreclr/md/compiler/regmeta.cpp @@ -40,8 +40,8 @@ RegMeta::RegMeta() : #ifdef FEATURE_METADATA_INTERNAL_APIS m_pInternalImport(NULL), #endif - m_pSemReadWrite(NULL), - m_fOwnSem(false), + m_pReadWriteLock(NULL), + m_fOwnLock(false), m_bRemap(false), m_bSaveOptimized(false), m_hasOptimizedRefToDef(false), @@ -95,7 +95,7 @@ RegMeta::~RegMeta() { // Do nothing on error } m_pInternalImport = NULL; - m_fOwnSem = false; + m_fOwnLock = false; } #endif //FEATURE_METADATA_INTERNAL_APIS @@ -108,8 +108,8 @@ RegMeta::~RegMeta() m_pFreeThreadedMarshaler = NULL; } - if (m_pSemReadWrite && m_fOwnSem) - delete m_pSemReadWrite; + if (m_pReadWriteLock && m_fOwnLock) + DestroyMDReadWriteLock(m_pReadWriteLock); // If this RegMeta is a wrapper on an external StgDB, release it. if (IsOfExternalStgDB(m_OpenFlags)) @@ -246,12 +246,10 @@ RegMeta::CreateNewMD() if (IsThreadSafetyOn()) { - m_pSemReadWrite = new (nothrow) UTSemReadWrite(); - IfNullGo(m_pSemReadWrite); - IfFailGo(m_pSemReadWrite->Init()); - m_fOwnSem = true; + IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); + m_fOwnLock = true; - INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + INDEBUG(m_pStgdb->m_MiniMd.Debug_EnableLockCheck();) } ErrExit: @@ -292,12 +290,10 @@ RegMeta::CreateNewPortablePdbMD() if (IsThreadSafetyOn()) { - m_pSemReadWrite = new (nothrow) UTSemReadWrite(); - IfNullGo(m_pSemReadWrite); - IfFailGo(m_pSemReadWrite->Init()); - m_fOwnSem = true; + IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); + m_fOwnLock = true; - INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + INDEBUG(m_pStgdb->m_MiniMd.Debug_EnableLockCheck();) } ErrExit: @@ -349,12 +345,10 @@ HRESULT RegMeta::OpenExistingMD( if (IsThreadSafetyOn()) { - m_pSemReadWrite = new (nothrow) UTSemReadWrite(); - IfNullGo(m_pSemReadWrite); - IfFailGo(m_pSemReadWrite->Init()); - m_fOwnSem = true; + IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); + m_fOwnLock = true; - INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + INDEBUG(m_pStgdb->m_MiniMd.Debug_EnableLockCheck();) } if (!IsOfReOpen(dwOpenFlags)) @@ -447,7 +441,7 @@ HRESULT RegMeta::SetCachedInternalInterface(IUnknown *pUnk) { // Internal interface is going away before the public interface. Take ownership on the // reader writer lock. - m_fOwnSem = true; + m_fOwnLock = true; m_pInternalImport = NULL; } return hr; @@ -1336,6 +1330,7 @@ HRESULT RegMeta::ReOpenWithMemory( // of the APIs were ever called then we can safely delete. CLiteWeightStgdbRW* pStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb; + INDEBUG(lockHolder.Debug_DetachMiniMd(&pStgdb->m_MiniMd);) delete pStgdb; } @@ -1420,7 +1415,7 @@ HRESULT RegMeta::GetIMDInternalImport( if (this->IsThreadSafetyOn()) { _ASSERTE( this->GetReaderWriterLock() ); - IfFailGo(this->GetReaderWriterLock()->LockWrite()); + IfFailGo(AcquireMDWriteLock(this->GetReaderWriterLock() COMMA_INDEBUG(this->GetMiniMd()))); isLockedForWrite = true; } @@ -1449,7 +1444,7 @@ HRESULT RegMeta::GetIMDInternalImport( ErrExit: if (isLockedForWrite == true) - this->GetReaderWriterLock()->UnlockWrite(); + ReleaseMDWriteLock(this->GetReaderWriterLock() COMMA_INDEBUG(this->GetMiniMd())); if (pIUnkInternal) pIUnkInternal->Release(); if (pInternalRW) diff --git a/src/coreclr/md/compiler/regmeta.h b/src/coreclr/md/compiler/regmeta.h index 9623f2f2954188..274ff3c3544401 100644 --- a/src/coreclr/md/compiler/regmeta.h +++ b/src/coreclr/md/compiler/regmeta.h @@ -16,7 +16,6 @@ #include #include "../inc/mdlog.h" -#include "utsem.h" #include "rwutil.h" #include "sigparser.h" @@ -1302,14 +1301,14 @@ class RegMeta : STDMETHODIMP_(IUnknown *) GetCachedInternalInterface(BOOL fWithLock); // S_OK or error STDMETHODIMP SetCachedInternalInterface(IUnknown *pUnk); // S_OK or error - STDMETHODIMP SetReaderWriterLock(UTSemReadWrite * pSem) + STDMETHODIMP SetReaderWriterLock(minipal_rwlock * pLock) { - _ASSERTE(m_pSemReadWrite == NULL); - m_pSemReadWrite = pSem; - INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + _ASSERTE(m_pReadWriteLock == NULL); + m_pReadWriteLock = pLock; + INDEBUG(if (pLock != nullptr) { m_pStgdb->m_MiniMd.Debug_EnableLockCheck(); }) return NOERROR; } - STDMETHODIMP_(UTSemReadWrite *) GetReaderWriterLock() { return m_pSemReadWrite; } + STDMETHODIMP_(minipal_rwlock *) GetReaderWriterLock() { return m_pReadWriteLock; } #ifndef FEATURE_METADATA_EMIT // This method is also part of IMetaDataEmit interface, do not declare it twice @@ -1996,8 +1995,8 @@ class RegMeta : IMDInternalImport *m_pInternalImport; #endif //FEATURE_METADATA_INTERNAL_APIS - UTSemReadWrite *m_pSemReadWrite; - unsigned m_fOwnSem : 1; + minipal_rwlock *m_pReadWriteLock; + unsigned m_fOwnLock : 1; unsigned m_bRemap : 1; // If true, there is a token mapper. unsigned m_bSaveOptimized : 1; // If true, save optimization has been done. unsigned m_hasOptimizedRefToDef : 1; // true if we have performed ref to def optimization diff --git a/src/coreclr/md/compiler/stdafx.h b/src/coreclr/md/compiler/stdafx.h index b8ae250e008cda..7d07206745caff 100644 --- a/src/coreclr/md/compiler/stdafx.h +++ b/src/coreclr/md/compiler/stdafx.h @@ -24,8 +24,6 @@ #include "nsutilpriv.h" -#include "utsem.h" - using std::min; using std::max; diff --git a/src/coreclr/md/enc/mdinternalrw.cpp b/src/coreclr/md/enc/mdinternalrw.cpp index 5a85397e440050..2cd527da1fdc9c 100644 --- a/src/coreclr/md/enc/mdinternalrw.cpp +++ b/src/coreclr/md/enc/mdinternalrw.cpp @@ -61,8 +61,8 @@ HRESULT TranslateSigHelper( // S_OK or error. IMetaModelCommon *pCommonAssemImport = pAssemImport ? pAssemImport->GetMetaModelCommon() : NULL; - CMDSemReadWrite cSem(pEmitRM->m_pSemReadWrite); - IfFailGo(cSem.LockWrite()); + CMDReadWriteLock lockHolder(pEmitRM->m_pReadWriteLock COMMA_INDEBUG(pMiniMdEmit)); + IfFailGo(lockHolder.LockWrite()); hr = ImportHelper::MergeUpdateTokenInSig( pMiniMdAssemEmit, // The assembly emit scope. @@ -264,7 +264,9 @@ STDAPI GetMDPublicInterfaceFromInternal( // grab the write lock when we are creating the corresponding regmeta for the public interface _ASSERTE( pInternalImport->GetReaderWriterLock() != NULL ); isLockedForWrite = true; - IfFailGo(pInternalImport->GetReaderWriterLock()->LockWrite()); + IfFailGo(AcquireMDWriteLock( + pInternalImport->GetReaderWriterLock() + COMMA_INDEBUG(static_cast(pInternalImport->GetMetaModelCommon())))); // check again. Maybe someone else beat us to setting the public interface while we are waiting // for the write lock. Don't need to grab the read lock since we already have the write lock. @@ -294,7 +296,9 @@ STDAPI GetMDPublicInterfaceFromInternal( ErrExit: if (isLockedForWrite) - pInternalImport->GetReaderWriterLock()->UnlockWrite(); + ReleaseMDWriteLock( + pInternalImport->GetReaderWriterLock() + COMMA_INDEBUG(static_cast(pInternalImport->GetMetaModelCommon()))); if (FAILED(hr)) { @@ -351,8 +355,8 @@ MDInternalRW::MDInternalRW() m_pUnk(NULL), m_pUserUnk(NULL), m_pIMetaDataHelper(NULL), - m_pSemReadWrite(NULL), - m_fOwnSem(false) + m_pReadWriteLock(NULL), + m_fOwnLock(false) { } // MDInternalRW::MDInternalRW @@ -382,14 +386,14 @@ MDInternalRW::~MDInternalRW() m_pIMetaDataHelper->SetCachedInternalInterface(NULL); m_pIMetaDataHelper = NULL; - m_fOwnSem = false; + m_fOwnLock = false; } UNLOCKWRITE(); } - if (m_pSemReadWrite && m_fOwnSem) - delete m_pSemReadWrite; + if (m_pReadWriteLock && m_fOwnLock) + DestroyMDReadWriteLock(m_pReadWriteLock); if ( m_pStgdb && m_fOwnStgdb ) { @@ -429,7 +433,7 @@ HRESULT MDInternalRW::SetCachedPublicInterface(IUnknown * pUnk) { // public object is going away before the internal object. If we don't own the // reader writer lock, just take over the ownership. - m_fOwnSem = true; + m_fOwnLock = true; m_pIMetaDataHelper = NULL; } return hr; @@ -466,7 +470,7 @@ IUnknown * MDInternalRW::GetCachedPublicInterface(BOOL fWithLock) //***************************************************************************** // Get the Reader-Writer lock //***************************************************************************** -UTSemReadWrite * MDInternalRW::GetReaderWriterLock() +minipal_rwlock * MDInternalRW::GetReaderWriterLock() { return getReaderWriterLock(); } // MDInternalRW::GetReaderWriterLock @@ -532,11 +536,9 @@ HRESULT MDInternalRW::Init( pStgdb = new (nothrow) CLiteWeightStgdbRW; IfNullGo(pStgdb); - m_pSemReadWrite = new (nothrow) UTSemReadWrite; - IfNullGo(m_pSemReadWrite); - IfFailGo(m_pSemReadWrite->Init()); - m_fOwnSem = true; - INDEBUG(pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); + m_fOwnLock = true; + INDEBUG(pStgdb->m_MiniMd.Debug_EnableLockCheck();) IfFailGo(pStgdb->InitOnMem(cbData, (BYTE*)pData, bReadOnly)); IfFailGo(pStgdb->m_MiniMd.SetOption(&optVal)); @@ -562,7 +564,7 @@ HRESULT MDInternalRW::InitWithStgdb( IUnknown *pUnk, // The IUnknow that owns the life time for the existing stgdb CLiteWeightStgdbRW *pStgdb) // existing lightweight stgdb { - // m_fOwnSem should be false because this is the case where we create the internal interface given a public + // m_fOwnLock should be false because this is the case where we create the internal interface given a public // interface. m_tdModule = COR_GLOBAL_PARENT_TOKEN; @@ -593,11 +595,9 @@ HRESULT MDInternalRW::InitWithRO( pStgdb = new (nothrow) CLiteWeightStgdbRW; IfNullGo(pStgdb); - m_pSemReadWrite = new (nothrow) UTSemReadWrite; - IfNullGo(m_pSemReadWrite); - IfFailGo(m_pSemReadWrite->Init()); - m_fOwnSem = true; - INDEBUG(pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); + m_fOwnLock = true; + INDEBUG(pStgdb->m_MiniMd.Debug_EnableLockCheck();) IfFailGo(pStgdb->m_MiniMd.InitOnRO(&pRO->m_LiteWeightStgdb.m_MiniMd, bReadOnly)); IfFailGo(pStgdb->m_MiniMd.SetOption(&optVal)); diff --git a/src/coreclr/md/enc/metamodelrw.cpp b/src/coreclr/md/enc/metamodelrw.cpp index be814089a2cd14..efd7aec6ba059d 100644 --- a/src/coreclr/md/enc/metamodelrw.cpp +++ b/src/coreclr/md/enc/metamodelrw.cpp @@ -766,7 +766,8 @@ CMiniMdRW::CMiniMdRW() // If assert fires, change define for AUTO_GROW_CODED_TOKEN_PADDING. _ASSERTE(CMiniMdRW::m_cb[iMax] == AUTO_GROW_CODED_TOKEN_PADDING); } - dbg_m_pLock = NULL; + dbg_m_fLockEnabled = false; + dbg_m_fIsLockedForWrite.Store(false); #endif //_DEBUG } // CMiniMdRW::CMiniMdRW @@ -6997,7 +6998,7 @@ void CMiniMdRW::Debug_CheckIsLockedForWrite() { // If this assert fires, then we are trying to modify MetaData that is not locked for write - _ASSERTE((dbg_m_pLock == NULL) || dbg_m_pLock->Debug_IsLockedForWrite()); + _ASSERTE(!dbg_m_fLockEnabled || dbg_m_fIsLockedForWrite.Load()); } #endif //_DEBUG diff --git a/src/coreclr/md/enc/rwutil.cpp b/src/coreclr/md/enc/rwutil.cpp index 36c326adc4d7ee..c2c569eb284b8b 100644 --- a/src/coreclr/md/enc/rwutil.cpp +++ b/src/coreclr/md/enc/rwutil.cpp @@ -11,9 +11,125 @@ #include "stdafx.h" #include "metadata.h" #include "rwutil.h" -#include "utsem.h" +#include "contract.h" #include "../inc/mdlog.h" +#if !defined(SELF_NO_HOST) && !defined(DACCESS_COMPILE) && !defined(DBI_COMPILE) && defined(TARGET_X86) && !defined(TARGET_UNIX) +void IncCantStopCount(); +void DecCantStopCount(); +#else +#define IncCantStopCount() +#define DecCantStopCount() +#endif + +HRESULT CreateMDReadWriteLock(minipal_rwlock **ppLock) +{ + minipal_rwlock *pLock = new (nothrow) minipal_rwlock; + IfNullRet(pLock); + + if (!minipal_rwlock_init(pLock)) + { + delete pLock; + return E_OUTOFMEMORY; + } + + *ppLock = pLock; + return S_OK; +} + +void DestroyMDReadWriteLock(minipal_rwlock *pLock) +{ + if (pLock != NULL) + { + minipal_rwlock_destroy(pLock); + delete pLock; + } +} + +HRESULT AcquireMDReadLock(minipal_rwlock *pLock) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + CAN_TAKE_LOCK; + } + CONTRACTL_END; + + IncCantStopCount(); + + if (!minipal_rwlock_enter_read(pLock)) + { + DecCantStopCount(); + return E_FAIL; + } + + EE_LOCK_TAKEN(pLock); + return S_OK; +} + +HRESULT AcquireMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + CAN_TAKE_LOCK; + } + CONTRACTL_END; + + IncCantStopCount(); + + if (!minipal_rwlock_enter_write(pLock)) + { + DecCantStopCount(); + return E_FAIL; + } + +#ifdef _DEBUG + if (pMiniMd != nullptr) + { + pMiniMd->Debug_SetIsLockedForWrite(true); + } +#endif // _DEBUG + EE_LOCK_TAKEN(pLock); + return S_OK; +} + +void ReleaseMDReadLock(minipal_rwlock *pLock) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + minipal_rwlock_leave_read(pLock); + DecCantStopCount(); + EE_LOCK_RELEASED(pLock); +} + +void ReleaseMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + +#ifdef _DEBUG + if (pMiniMd != nullptr) + { + pMiniMd->Debug_SetIsLockedForWrite(false); + } +#endif // _DEBUG + minipal_rwlock_leave_write(pLock); + DecCantStopCount(); + EE_LOCK_RELEASED(pLock); +} + //***************************************************************************** // Helper methods //***************************************************************************** @@ -1153,13 +1269,15 @@ HRESULT TokenRemapManager::ClearAndEnsureCapacity( // Constructor // //********************************************************************************************************* -CMDSemReadWrite::CMDSemReadWrite( - UTSemReadWrite * pSem) +CMDReadWriteLock::CMDReadWriteLock( + minipal_rwlock * pLock + COMMA_INDEBUG(CMiniMdRW *pMiniMd)) { m_fLockedForRead = false; m_fLockedForWrite = false; - m_pSem = pSem; -} // CMDSemReadWrite::CMDSemReadWrite + m_pLock = pLock; + INDEBUG(m_pMiniMd = pMiniMd;) +} // CMDReadWriteLock::CMDReadWriteLock @@ -1168,68 +1286,68 @@ CMDSemReadWrite::CMDSemReadWrite( // Destructor // //********************************************************************************************************* -CMDSemReadWrite::~CMDSemReadWrite() +CMDReadWriteLock::~CMDReadWriteLock() { _ASSERTE(!m_fLockedForRead || !m_fLockedForWrite); - if (m_pSem == NULL) + if (m_pLock == NULL) { return; } if (m_fLockedForRead) { - LOG((LF_METADATA, LL_EVERYTHING, "UnlockRead called from CSemReadWrite::~CSemReadWrite \n")); - m_pSem->UnlockRead(); + LOG((LF_METADATA, LL_EVERYTHING, "ReleaseMDReadLock called from CMDReadWriteLock::~CMDReadWriteLock\n")); + ReleaseMDReadLock(m_pLock); } if (m_fLockedForWrite) { - LOG((LF_METADATA, LL_EVERYTHING, "UnlockWrite called from CSemReadWrite::~CSemReadWrite \n")); - m_pSem->UnlockWrite(); + LOG((LF_METADATA, LL_EVERYTHING, "ReleaseMDWriteLock called from CMDReadWriteLock::~CMDReadWriteLock\n")); + ReleaseMDWriteLock(m_pLock COMMA_INDEBUG(m_pMiniMd)); } -} // CMDSemReadWrite::~CMDSemReadWrite +} // CMDReadWriteLock::~CMDReadWriteLock //********************************************************************************************************* // -// Used to obtain the read lock +// Used to obtain the write lock // //********************************************************************************************************* -HRESULT CMDSemReadWrite::LockRead() +HRESULT CMDReadWriteLock::LockRead() { HRESULT hr = S_OK; _ASSERTE(!m_fLockedForRead && !m_fLockedForWrite); - if (m_pSem == NULL) + if (m_pLock == NULL) { INDEBUG(m_fLockedForRead = true); return hr; } - LOG((LF_METADATA, LL_EVERYTHING, "LockRead called from CSemReadWrite::LockRead \n")); - IfFailRet(m_pSem->LockRead()); + LOG((LF_METADATA, LL_EVERYTHING, "AcquireMDReadLock called from CMDReadWriteLock::LockRead\n")); + IfFailRet(AcquireMDReadLock(m_pLock)); m_fLockedForRead = true; return hr; -} // CMDSemReadWrite::LockRead +} // CMDReadWriteLock::LockRead //********************************************************************************************************* // // Used to obtain the read lock // //********************************************************************************************************* -HRESULT CMDSemReadWrite::LockWrite() +HRESULT CMDReadWriteLock::LockWrite() { HRESULT hr = S_OK; _ASSERTE(!m_fLockedForRead && !m_fLockedForWrite); - if (m_pSem == NULL) + if (m_pLock == NULL) { INDEBUG(m_fLockedForWrite = true); return hr; } - LOG((LF_METADATA, LL_EVERYTHING, "LockWrite called from CSemReadWrite::LockWrite \n")); - IfFailRet(m_pSem->LockWrite()); + LOG((LF_METADATA, LL_EVERYTHING, "AcquireMDWriteLock called from CMDReadWriteLock::LockWrite\n")); + IfFailRet(AcquireMDWriteLock(m_pLock COMMA_INDEBUG(m_pMiniMd))); m_fLockedForWrite = true; return hr; @@ -1240,13 +1358,13 @@ HRESULT CMDSemReadWrite::LockWrite() // Convert a read lock to a write lock // //********************************************************************************************************* -HRESULT CMDSemReadWrite::ConvertReadLockToWriteLock() +HRESULT CMDReadWriteLock::ConvertReadLockToWriteLock() { _ASSERTE(!m_fLockedForWrite); HRESULT hr = S_OK; - if (m_pSem == NULL) + if (m_pLock == NULL) { INDEBUG(m_fLockedForRead = false); INDEBUG(m_fLockedForWrite = true); @@ -1255,16 +1373,16 @@ HRESULT CMDSemReadWrite::ConvertReadLockToWriteLock() if (m_fLockedForRead) { - LOG((LF_METADATA, LL_EVERYTHING, "UnlockRead called from CSemReadWrite::ConvertReadLockToWriteLock \n")); - m_pSem->UnlockRead(); + LOG((LF_METADATA, LL_EVERYTHING, "ReleaseMDReadLock called from CMDReadWriteLock::ConvertReadLockToWriteLock\n")); + ReleaseMDReadLock(m_pLock); m_fLockedForRead = false; } - LOG((LF_METADATA, LL_EVERYTHING, "LockWrite called from CSemReadWrite::ConvertReadLockToWriteLock\n")); - IfFailRet(m_pSem->LockWrite()); + LOG((LF_METADATA, LL_EVERYTHING, "AcquireMDWriteLock called from CMDReadWriteLock::ConvertReadLockToWriteLock\n")); + IfFailRet(AcquireMDWriteLock(m_pLock COMMA_INDEBUG(m_pMiniMd))); m_fLockedForWrite = true; return hr; -} // CMDSemReadWrite::ConvertReadLockToWriteLock +} // CMDReadWriteLock::ConvertReadLockToWriteLock //********************************************************************************************************* @@ -1272,19 +1390,33 @@ HRESULT CMDSemReadWrite::ConvertReadLockToWriteLock() // Unlocking for write // //********************************************************************************************************* -void CMDSemReadWrite::UnlockWrite() +void CMDReadWriteLock::UnlockWrite() { _ASSERTE(!m_fLockedForRead); - if (m_pSem == NULL) + if (m_pLock == NULL) { INDEBUG(m_fLockedForWrite = false); return; } if (m_fLockedForWrite) { - LOG((LF_METADATA, LL_EVERYTHING, "UnlockWrite called from CSemReadWrite::UnlockWrite \n")); - m_pSem->UnlockWrite(); + LOG((LF_METADATA, LL_EVERYTHING, "ReleaseMDWriteLock called from CMDReadWriteLock::UnlockWrite\n")); + ReleaseMDWriteLock(m_pLock COMMA_INDEBUG(m_pMiniMd)); m_fLockedForWrite = false; } -} // CMDSemReadWrite::UnlockWrite +} // CMDReadWriteLock::UnlockWrite + +#ifdef _DEBUG +void CMDReadWriteLock::Debug_DetachMiniMd(CMiniMdRW *pMiniMd) +{ + _ASSERTE(m_fLockedForWrite); + _ASSERTE(m_pMiniMd == pMiniMd); + + if (m_pLock != NULL) + { + m_pMiniMd->Debug_SetIsLockedForWrite(false); + } + m_pMiniMd = nullptr; +} +#endif // _DEBUG diff --git a/src/coreclr/md/enc/stdafx.h b/src/coreclr/md/enc/stdafx.h index 10d1cf0f32d69a..4f06e7da24687f 100644 --- a/src/coreclr/md/enc/stdafx.h +++ b/src/coreclr/md/enc/stdafx.h @@ -25,8 +25,6 @@ #include "mdcommon.h" -#include "utsem.h" - using std::min; using std::max; diff --git a/src/coreclr/md/inc/mdinternalrw.h b/src/coreclr/md/inc/mdinternalrw.h index c45c4df97e66db..beaeec372a1eca 100644 --- a/src/coreclr/md/inc/mdinternalrw.h +++ b/src/coreclr/md/inc/mdinternalrw.h @@ -15,8 +15,6 @@ #include "../inc/mdlog.h" -class UTSemReadWrite; - class MDInternalRW : public IMDInternalImportENC, public IMDCommon { public: @@ -701,13 +699,13 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon STDMETHODIMP_(IUnknown *) GetCachedPublicInterface(BOOL fWithLock); // return the cached public interface __checkReturn STDMETHODIMP SetCachedPublicInterface(IUnknown *pUnk); // return hresult - STDMETHODIMP_(UTSemReadWrite*) GetReaderWriterLock(); // return the reader writer lock + STDMETHODIMP_(minipal_rwlock*) GetReaderWriterLock(); // return the reader writer lock __checkReturn - STDMETHODIMP SetReaderWriterLock(UTSemReadWrite *pSem) + STDMETHODIMP SetReaderWriterLock(minipal_rwlock *pLock) { - _ASSERTE(m_pSemReadWrite == NULL); - m_pSemReadWrite = pSem; - INDEBUG(m_pStgdb->m_MiniMd.Debug_SetLock(m_pSemReadWrite);) + _ASSERTE(m_pReadWriteLock == NULL); + m_pReadWriteLock = pLock; + INDEBUG(if (pLock != nullptr) { m_pStgdb->m_MiniMd.Debug_EnableLockCheck(); }) return NOERROR; } @@ -750,7 +748,7 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon FORCEINLINE CLiteWeightStgdbRW* GetMiniStgdb() { return m_pStgdb; } - FORCEINLINE UTSemReadWrite *getReaderWriterLock() { return m_pSemReadWrite; } + FORCEINLINE minipal_rwlock *getReaderWriterLock() { return m_pReadWriteLock; } CLiteWeightStgdbRW *m_pStgdb; @@ -762,8 +760,8 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon IUnknown *m_pUnk; IUnknown *m_pUserUnk; // Release at shutdown. IMetaDataHelper *m_pIMetaDataHelper;// pointer to cached public interface - UTSemReadWrite *m_pSemReadWrite; // read write lock for multi-threading. - bool m_fOwnSem; // Does MDInternalRW own this read write lock object? + minipal_rwlock *m_pReadWriteLock; // read write lock for multi-threading. + bool m_fOwnLock; // Does MDInternalRW own this read write lock object? public: STDMETHODIMP_(DWORD) GetMetadataStreamVersion() diff --git a/src/coreclr/md/inc/metamodelrw.h b/src/coreclr/md/inc/metamodelrw.h index 5bd3adc0bcb142..34e2627ec1861f 100644 --- a/src/coreclr/md/inc/metamodelrw.h +++ b/src/coreclr/md/inc/metamodelrw.h @@ -199,7 +199,6 @@ typedef CMetaDataHashBase CLookUpHash; class MDTOKENMAP; class MDInternalRW; -class UTSemReadWrite; template class CLiteWeightStgdb; class DacDbiInterfaceImpl; @@ -1232,15 +1231,23 @@ class CMiniMdRW : public CMiniMdTemplate #ifdef _DEBUG protected: - UTSemReadWrite * dbg_m_pLock; + bool dbg_m_fLockEnabled; + Volatile dbg_m_fIsLockedForWrite; public: // Checks that MetaData is locked for write operation (if thread-safety is enabled and the lock exists) void Debug_CheckIsLockedForWrite(); - void Debug_SetLock(UTSemReadWrite * pLock) + void Debug_EnableLockCheck() { - dbg_m_pLock = pLock; + dbg_m_fLockEnabled = true; + } + + void Debug_SetIsLockedForWrite(bool isLockedForWrite) + { + _ASSERTE(dbg_m_fLockEnabled); + _ASSERTE(dbg_m_fIsLockedForWrite.Load() != isLockedForWrite); + dbg_m_fIsLockedForWrite.Store(isLockedForWrite); } #endif //_DEBUG diff --git a/src/coreclr/md/inc/rwutil.h b/src/coreclr/md/inc/rwutil.h index f6ee02817fb2b7..0290e85b5bcf23 100644 --- a/src/coreclr/md/inc/rwutil.h +++ b/src/coreclr/md/inc/rwutil.h @@ -11,7 +11,16 @@ #ifndef __RWUtil__h__ #define __RWUtil__h__ -class UTSemReadWrite; +#include + +class CMiniMdRW; + +HRESULT CreateMDReadWriteLock(minipal_rwlock **ppLock); +void DestroyMDReadWriteLock(minipal_rwlock *pLock); +HRESULT AcquireMDReadLock(minipal_rwlock *pLock); +HRESULT AcquireMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)); +void ReleaseMDReadLock(minipal_rwlock *pLock); +void ReleaseMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)); #define UTF8STR(wszInput, szOutput) \ do { \ @@ -300,45 +309,49 @@ struct OptionValue //********************************************************************* // -// Helper class to ensure calling UTSemReadWrite correctly. -// The destructor will call the correct UnlockRead or UnlockWrite depends what lock it is holding. +// Helper class to ensure the metadata read-write lock is released correctly. +// The destructor releases whichever lock mode it holds. // User should use macro defined in below instead of calling functions on this class directly. // They are LOCKREAD(), LOCKWRITE(), and CONVERT_READ_TO_WRITE_LOCK. // //********************************************************************* -class CMDSemReadWrite +class CMDReadWriteLock { public: - CMDSemReadWrite(UTSemReadWrite *pSem); - ~CMDSemReadWrite(); + CMDReadWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)); + ~CMDReadWriteLock(); HRESULT LockRead(); HRESULT LockWrite(); void UnlockWrite(); HRESULT ConvertReadLockToWriteLock(); +#ifdef _DEBUG + void Debug_DetachMiniMd(CMiniMdRW *pMiniMd); +#endif // _DEBUG private: bool m_fLockedForRead; bool m_fLockedForWrite; - UTSemReadWrite *m_pSem; + minipal_rwlock *m_pLock; + INDEBUG(CMiniMdRW *m_pMiniMd;) }; -#define LOCKREADIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\ - IfFailRet(cSem.LockRead()); -#define LOCKWRITEIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\ - IfFailRet(cSem.LockWrite()); +#define LOCKREADIFFAILRET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ + IfFailRet(lockHolder.LockRead()); +#define LOCKWRITEIFFAILRET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ + IfFailRet(lockHolder.LockWrite()); -#define LOCKREADNORET() CMDSemReadWrite cSem(m_pSemReadWrite);\ - hr = cSem.LockRead(); -#define LOCKWRITENORET() CMDSemReadWrite cSem(m_pSemReadWrite);\ - hr = cSem.LockWrite(); +#define LOCKREADNORET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ + hr = lockHolder.LockRead(); +#define LOCKWRITENORET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ + hr = lockHolder.LockWrite(); -#define LOCKREAD() CMDSemReadWrite cSem(m_pSemReadWrite);\ - IfFailGo(cSem.LockRead()); -#define LOCKWRITE() CMDSemReadWrite cSem(m_pSemReadWrite);\ - IfFailGo(cSem.LockWrite()); +#define LOCKREAD() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ + IfFailGo(lockHolder.LockRead()); +#define LOCKWRITE() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ + IfFailGo(lockHolder.LockWrite()); -#define UNLOCKWRITE() cSem.UnlockWrite(); -#define CONVERT_READ_TO_WRITE_LOCK() IfFailGo(cSem.ConvertReadLockToWriteLock()); +#define UNLOCKWRITE() lockHolder.UnlockWrite(); +#define CONVERT_READ_TO_WRITE_LOCK() IfFailGo(lockHolder.ConvertReadLockToWriteLock()); #endif // __RWUtil__h__ diff --git a/src/coreclr/md/runtime/mdinternalro.h b/src/coreclr/md/runtime/mdinternalro.h index 5f7f8e9e01a7d6..1df15736f147be 100644 --- a/src/coreclr/md/runtime/mdinternalro.h +++ b/src/coreclr/md/runtime/mdinternalro.h @@ -693,9 +693,9 @@ class MDInternalRO : public IMDInternalImport, IMDCommon STDMETHODIMP_(IUnknown *) GetCachedPublicInterface(BOOL fWithLock) { return NULL;} // return the cached public interface __checkReturn STDMETHODIMP SetCachedPublicInterface(IUnknown *pUnk) { return E_FAIL;} ;// return hresult - STDMETHODIMP_(UTSemReadWrite*) GetReaderWriterLock() {return NULL;} // return the reader writer lock + STDMETHODIMP_(minipal_rwlock*) GetReaderWriterLock() {return NULL;} // return the reader writer lock __checkReturn - STDMETHODIMP SetReaderWriterLock(UTSemReadWrite *pSem) { return NOERROR; } + STDMETHODIMP SetReaderWriterLock(minipal_rwlock *pLock) { return NOERROR; } STDMETHODIMP_(mdModule) GetModuleFromScope(void); // Find a paticular method and pass in the signature comparison routine. Very diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index 0ff5b7435ecab0..a4f4e64848bd47 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -582,35 +582,6 @@ GetTempPathA( #define GetTempPath GetTempPathA #endif -PALIMPORT -HANDLE -PALAPI -CreateSemaphoreExW( - IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, - IN LONG lInitialCount, - IN LONG lMaximumCount, - IN LPCWSTR lpName, - IN /*_Reserved_*/ DWORD dwFlags, - IN DWORD dwDesiredAccess); - -PALIMPORT -HANDLE -PALAPI -OpenSemaphoreW( - IN DWORD dwDesiredAccess, - IN BOOL bInheritHandle, - IN LPCWSTR lpName); - -#define CreateSemaphoreEx CreateSemaphoreExW - -PALIMPORT -BOOL -PALAPI -ReleaseSemaphore( - IN HANDLE hSemaphore, - IN LONG lReleaseCount, - OUT LPLONG lpPreviousCount); - PALIMPORT HANDLE PALAPI @@ -2680,9 +2651,6 @@ typedef struct _RUNTIME_FUNCTION { #define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE) #define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS -#define SEMAPHORE_MODIFY_STATE (0x0002) -#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3) - PALIMPORT VOID PALAPI diff --git a/src/coreclr/pal/inc/pal_error.h b/src/coreclr/pal/inc/pal_error.h index b03f9cefa129f5..39466d5e577b82 100644 --- a/src/coreclr/pal/inc/pal_error.h +++ b/src/coreclr/pal/inc/pal_error.h @@ -52,14 +52,12 @@ #define ERROR_CANNOT_MAKE 82L #define ERROR_INVALID_PARAMETER 87L #define ERROR_NET_WRITE_FAULT 88L -#define ERROR_TOO_MANY_SEMAPHORES 100L #define ERROR_DRIVE_LOCKED 108L #define ERROR_BROKEN_PIPE 109L #define ERROR_OPEN_FAILED 110L #define ERROR_BUFFER_OVERFLOW 111L #define ERROR_DISK_FULL 112L #define ERROR_CALL_NOT_IMPLEMENTED 120L -#define ERROR_SEM_TIMEOUT 121L #define ERROR_INSUFFICIENT_BUFFER 122L #define ERROR_INVALID_NAME 123L #define ERROR_MOD_NOT_FOUND 126L diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index 545ba6550f4187..42ba78af10f4c5 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -197,7 +197,6 @@ set(SOURCES safecrt/wcsncpy_s.cpp safecrt/wmakepath_s.cpp synchobj/event.cpp - synchobj/semaphore.cpp synchmgr/synchcontrollers.cpp synchmgr/synchmanager.cpp synchmgr/wait.cpp diff --git a/src/coreclr/pal/src/include/pal/corunix.hpp b/src/coreclr/pal/src/include/pal/corunix.hpp index 82ab89a1626e59..cddda4626fa0aa 100644 --- a/src/coreclr/pal/src/include/pal/corunix.hpp +++ b/src/coreclr/pal/src/include/pal/corunix.hpp @@ -159,7 +159,6 @@ namespace CorUnix { otiAutoResetEvent = 0, otiManualResetEvent, - otiSemaphore, otiFile, otiFileMapping, otiSocket, @@ -979,4 +978,3 @@ namespace CorUnix } #endif // _CORUNIX_H - diff --git a/src/coreclr/pal/src/include/pal/semaphore.hpp b/src/coreclr/pal/src/include/pal/semaphore.hpp deleted file mode 100644 index a2b9663bc7c5d8..00000000000000 --- a/src/coreclr/pal/src/include/pal/semaphore.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - semaphore.hpp - -Abstract: - - Semaphore object structure definition. - - - ---*/ - -#ifndef _PAL_SEMAPHORE_H_ -#define _PAL_SEMAPHORE_H_ - -#include "corunix.hpp" - -namespace CorUnix -{ - extern CObjectType otSemaphore; - - typedef struct - { - LONG lMaximumCount; - } SemaphoreImmutableData; - - PAL_ERROR - InternalCreateSemaphore( - CPalThread *pThread, - LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, - LONG lInitialCount, - LONG lMaximumCount, - LPCWSTR lpName, - HANDLE *phSemaphore - ); - - PAL_ERROR - InternalReleaseSemaphore( - CPalThread *pThread, - HANDLE hSemaphore, - LONG lReleaseCount, - LPLONG lpPreviousCount - ); - -} - -#endif //_PAL_SEMAPHORE_H_ - - - - - - - - - - diff --git a/src/coreclr/pal/src/misc/errorstrings.cpp b/src/coreclr/pal/src/misc/errorstrings.cpp index fbf9a3f4c1c953..636464f36abf50 100644 --- a/src/coreclr/pal/src/misc/errorstrings.cpp +++ b/src/coreclr/pal/src/misc/errorstrings.cpp @@ -72,7 +72,6 @@ ErrorString palErrorStrings[] = { ERROR_BUFFER_OVERFLOW, W("The file name is too long.\n") }, { ERROR_DISK_FULL, W("There is not enough space on the disk.\n") }, { ERROR_CALL_NOT_IMPLEMENTED, W("This function is not supported on this system.\n") }, - { ERROR_SEM_TIMEOUT, W("The semaphore timeout period has expired.\n") }, { ERROR_INSUFFICIENT_BUFFER, W("The data area passed to a system call is too small.\n") }, { ERROR_INVALID_NAME, W("The filename, directory name, or volume label syntax is incorrect.\n") }, { ERROR_MOD_NOT_FOUND, W("The specified module or one of its dependencies could not be found.\n") }, diff --git a/src/coreclr/pal/src/synchmgr/wait.cpp b/src/coreclr/pal/src/synchmgr/wait.cpp index dab1f05c1a4f4d..0821e496f7d87e 100644 --- a/src/coreclr/pal/src/synchmgr/wait.cpp +++ b/src/coreclr/pal/src/synchmgr/wait.cpp @@ -24,7 +24,6 @@ Revision History: #include "pal/synchobjects.hpp" #include "pal/handlemgr.hpp" #include "pal/event.hpp" -#include "pal/semaphore.hpp" #include "pal/dbgmsg.h" #include @@ -38,7 +37,6 @@ static PalObjectTypeId sg_rgWaitObjectsIds[] = { otiAutoResetEvent, otiManualResetEvent, - otiSemaphore, otiThread }; static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds, @@ -47,8 +45,7 @@ static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds, static PalObjectTypeId sg_rgSignalableObjectIds[] = { otiAutoResetEvent, - otiManualResetEvent, - otiSemaphore + otiManualResetEvent }; static CAllowedObjectTypes sg_aotSignalableObject(sg_rgSignalableObjectIds, ARRAY_SIZE(sg_rgSignalableObjectIds)); diff --git a/src/coreclr/pal/src/synchobj/semaphore.cpp b/src/coreclr/pal/src/synchobj/semaphore.cpp deleted file mode 100644 index c16cb9a4677d6b..00000000000000 --- a/src/coreclr/pal/src/synchobj/semaphore.cpp +++ /dev/null @@ -1,488 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*++ - - - -Module Name: - - semaphore.cpp - -Abstract: - - Implementation of the sempahore synchroniztion object as described in - the WIN32 API - -Revision History: - - - ---*/ - -#include "pal/semaphore.hpp" -#include "pal/thread.hpp" -#include "pal/dbgmsg.h" - -using namespace CorUnix; - -/* ------------------- Definitions ------------------------------*/ -SET_DEFAULT_DEBUG_CHANNEL(SYNC); - -CObjectType CorUnix::otSemaphore( - otiSemaphore, - NULL, // No cleanup routine - sizeof(SemaphoreImmutableData), - NULL, // No immutable data copy routine - NULL, // No immutable data cleanup routine - 0, // No process local data - NULL, // No process local data cleanup routine - CObjectType::WaitableObject, - CObjectType::ObjectCanBeUnsignaled, - CObjectType::ThreadReleaseAltersSignalCount - ); - -CAllowedObjectTypes aotSempahore(otiSemaphore); - -/*++ -Function: - CreateSemaphoreW - -Note: - lpSemaphoreAttributes currently ignored: - -- Win32 object security not supported - -- handles to semaphore objects are not inheritable - -Parameters: - See MSDN doc. ---*/ - -HANDLE CreateSemaphoreW( - IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, - IN LONG lInitialCount, - IN LONG lMaximumCount, - IN LPCWSTR lpName) -{ - HANDLE hSemaphore = NULL; - PAL_ERROR palError; - CPalThread *pthr = NULL; - - PERF_ENTRY(CreateSemaphoreW); - ENTRY("CreateSemaphoreW(lpSemaphoreAttributes=%p, lInitialCount=%d, " - "lMaximumCount=%d, lpName=%p (%S))\n", - lpSemaphoreAttributes, lInitialCount, lMaximumCount, - lpName, lpName?lpName:W16_NULLSTRING); - - pthr = InternalGetCurrentThread(); - - palError = InternalCreateSemaphore( - pthr, - lpSemaphoreAttributes, - lInitialCount, - lMaximumCount, - lpName, - &hSemaphore - ); - - // - // We always need to set last error, even on success: - // we need to protect ourselves from the situation - // where last error is set to ERROR_ALREADY_EXISTS on - // entry to the function - // - - pthr->SetLastError(palError); - - LOGEXIT("CreateSemaphoreW returns HANDLE %p\n", hSemaphore); - PERF_EXIT(CreateSemaphoreW); - return hSemaphore; -} - -/*++ -Function: -CreateSemaphoreExW - -Note: -lpSemaphoreAttributes currently ignored: --- Win32 object security not supported --- handles to semaphore objects are not inheritable - -Parameters: -See MSDN doc. ---*/ - -HANDLE -PALAPI -CreateSemaphoreExW( - IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, - IN LONG lInitialCount, - IN LONG lMaximumCount, - IN LPCWSTR lpName, - IN /*_Reserved_*/ DWORD dwFlags, - IN DWORD dwDesiredAccess) -{ - // dwFlags is reserved and unused - - return CreateSemaphoreW( - lpSemaphoreAttributes, - lInitialCount, - lMaximumCount, - lpName); -} - -/*++ -Function: - InternalCreateSemaphore - -Note: - lpSemaphoreAttributes currently ignored: - -- Win32 object security not supported - -- handles to semaphore objects are not inheritable - -Parameters - pthr -- thread data for calling thread - phEvent -- on success, receives the allocated semaphore handle - - See MSDN docs on CreateSemaphore for all other parameters. ---*/ - -PAL_ERROR -CorUnix::InternalCreateSemaphore( - CPalThread *pthr, - LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, - LONG lInitialCount, - LONG lMaximumCount, - LPCWSTR lpName, - HANDLE *phSemaphore - ) -{ - CObjectAttributes oa(lpName, lpSemaphoreAttributes); - PAL_ERROR palError = NO_ERROR; - IPalObject *pobjSemaphore = NULL; - IPalObject *pobjRegisteredSemaphore = NULL; - SemaphoreImmutableData *pSemaphoreData; - - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != phSemaphore); - - ENTRY("InternalCreateSemaphore(pthr=%p, lpSemaphoreAttributes=%p, " - "lInitialCount=%d, lMaximumCount=%d, lpName=%p, phSemaphore=%p)\n", - pthr, - lpSemaphoreAttributes, - lInitialCount, - lMaximumCount, - lpName, - phSemaphore - ); - - if (lpName != nullptr) - { - ASSERT("lpName: Cross-process named objects are not supported in PAL"); - palError = ERROR_NOT_SUPPORTED; - goto InternalCreateSemaphoreExit; - } - - if (lMaximumCount <= 0) - { - ERROR("lMaximumCount is invalid (%d)\n", lMaximumCount); - palError = ERROR_INVALID_PARAMETER; - goto InternalCreateSemaphoreExit; - } - - if ((lInitialCount < 0) || (lInitialCount > lMaximumCount)) - { - ERROR("lInitialCount is invalid (%d)\n", lInitialCount); - palError = ERROR_INVALID_PARAMETER; - goto InternalCreateSemaphoreExit; - } - - palError = g_pObjectManager->AllocateObject( - pthr, - &otSemaphore, - &oa, - &pobjSemaphore - ); - - if (NO_ERROR != palError) - { - goto InternalCreateSemaphoreExit; - } - - palError = pobjSemaphore->GetImmutableData(reinterpret_cast(&pSemaphoreData)); - - if (NO_ERROR != palError) - { - ASSERT("Error %d obtaining object data\n", palError); - goto InternalCreateSemaphoreExit; - } - - pSemaphoreData->lMaximumCount = lMaximumCount; - - if (0 != lInitialCount) - { - ISynchStateController *pssc; - - palError = pobjSemaphore->GetSynchStateController( - pthr, - &pssc - ); - - if (NO_ERROR == palError) - { - palError = pssc->SetSignalCount(lInitialCount); - pssc->ReleaseController(); - } - - if (NO_ERROR != palError) - { - ASSERT("Unable to set new semaphore state (%d)\n", palError); - goto InternalCreateSemaphoreExit; - } - } - - palError = g_pObjectManager->RegisterObject( - pthr, - pobjSemaphore, - &aotSempahore, - phSemaphore, - &pobjRegisteredSemaphore - ); - - // - // pobjSemaphore is invalidated by the call to RegisterObject, so NULL it - // out here to ensure that we don't try to release a reference on - // it down the line. - // - - pobjSemaphore = NULL; - -InternalCreateSemaphoreExit: - - if (NULL != pobjSemaphore) - { - pobjSemaphore->ReleaseReference(pthr); - } - - if (NULL != pobjRegisteredSemaphore) - { - pobjRegisteredSemaphore->ReleaseReference(pthr); - } - - LOGEXIT("InternalCreateSemaphore returns %d\n", palError); - - return palError; -} - - -/*++ -Function: - ReleaseSemaphore - -Parameters: - See MSDN doc. ---*/ - -BOOL -PALAPI -ReleaseSemaphore( - IN HANDLE hSemaphore, - IN LONG lReleaseCount, - OUT LPLONG lpPreviousCount) -{ - PAL_ERROR palError = NO_ERROR; - CPalThread *pthr = NULL; - - PERF_ENTRY(ReleaseSemaphore); - ENTRY("ReleaseSemaphore(hSemaphore=%p, lReleaseCount=%d, " - "lpPreviousCount=%p)\n", - hSemaphore, lReleaseCount, lpPreviousCount); - - pthr = InternalGetCurrentThread(); - - palError = InternalReleaseSemaphore( - pthr, - hSemaphore, - lReleaseCount, - lpPreviousCount - ); - - if (NO_ERROR != palError) - { - pthr->SetLastError(palError); - } - - LOGEXIT ("ReleaseSemaphore returns BOOL %d\n", (NO_ERROR == palError)); - PERF_EXIT(ReleaseSemaphore); - return (NO_ERROR == palError); -} - -/*++ -Function: - InternalReleaseSemaphore - -Parameters: - pthr -- thread data for calling thread - - See MSDN docs on ReleaseSemaphore for all other parameters ---*/ - -PAL_ERROR -CorUnix::InternalReleaseSemaphore( - CPalThread *pthr, - HANDLE hSemaphore, - LONG lReleaseCount, - LPLONG lpPreviousCount - ) -{ - PAL_ERROR palError = NO_ERROR; - IPalObject *pobjSemaphore = NULL; - ISynchStateController *pssc = NULL; - SemaphoreImmutableData *pSemaphoreData; - LONG lOldCount; - - _ASSERTE(NULL != pthr); - - ENTRY("InternalReleaseSempahore(pthr=%p, hSemaphore=%p, lReleaseCount=%d, " - "lpPreviousCount=%p)\n", - pthr, - hSemaphore, - lReleaseCount, - lpPreviousCount - ); - - if (0 >= lReleaseCount) - { - palError = ERROR_INVALID_PARAMETER; - goto InternalReleaseSemaphoreExit; - } - - palError = g_pObjectManager->ReferenceObjectByHandle( - pthr, - hSemaphore, - &aotSempahore, - &pobjSemaphore - ); - - if (NO_ERROR != palError) - { - ERROR("Unable to obtain object for handle %p (error %d)!\n", hSemaphore, palError); - goto InternalReleaseSemaphoreExit; - } - - palError = pobjSemaphore->GetImmutableData(reinterpret_cast(&pSemaphoreData)); - - if (NO_ERROR != palError) - { - ASSERT("Error %d obtaining object data\n", palError); - goto InternalReleaseSemaphoreExit; - } - - palError = pobjSemaphore->GetSynchStateController( - pthr, - &pssc - ); - - if (NO_ERROR != palError) - { - ASSERT("Error %d obtaining synch state controller\n", palError); - goto InternalReleaseSemaphoreExit; - } - - palError = pssc->GetSignalCount(&lOldCount); - - if (NO_ERROR != palError) - { - ASSERT("Error %d obtaining current signal count\n", palError); - goto InternalReleaseSemaphoreExit; - } - - _ASSERTE(lOldCount <= pSemaphoreData->lMaximumCount); - if (lReleaseCount > pSemaphoreData->lMaximumCount - lOldCount) - { - palError = ERROR_TOO_MANY_POSTS; - goto InternalReleaseSemaphoreExit; - } - - palError = pssc->IncrementSignalCount(lReleaseCount); - - if (NO_ERROR != palError) - { - ASSERT("Error %d incrementing signal count\n", palError); - goto InternalReleaseSemaphoreExit; - } - - if (NULL != lpPreviousCount) - { - *lpPreviousCount = lOldCount; - } - -InternalReleaseSemaphoreExit: - - if (NULL != pssc) - { - pssc->ReleaseController(); - } - - if (NULL != pobjSemaphore) - { - pobjSemaphore->ReleaseReference(pthr); - } - - LOGEXIT("InternalReleaseSemaphore returns %d\n", palError); - - return palError; -} - -// TODO: Implementation of OpenSemaphoreA() doesn't exist, do we need it? More generally, do we need the A versions at all? - -/*++ -Function: - OpenSemaphoreW - -Note: - dwDesiredAccess is currently ignored (no Win32 object security support) - bInheritHandle is currently ignored (handles to semaphore are not inheritable) - -Parameters: - See MSDN doc. ---*/ - -HANDLE -PALAPI -OpenSemaphoreW( - IN DWORD dwDesiredAccess, - IN BOOL bInheritHandle, - IN LPCWSTR lpName) -{ - HANDLE hSemaphore = NULL; - PAL_ERROR palError = NO_ERROR; - CPalThread *pthr = NULL; - - PERF_ENTRY(OpenSemaphoreW); - ENTRY("OpenSemaphoreW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n", - dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING); - - pthr = InternalGetCurrentThread(); - - /* validate parameters */ - if (lpName == nullptr) - { - ERROR("lpName is NULL\n"); - palError = ERROR_INVALID_PARAMETER; - } - else - { - ASSERT("lpName: Cross-process named objects are not supported in PAL"); - palError = ERROR_NOT_SUPPORTED; - } - - if (NO_ERROR != palError) - { - pthr->SetLastError(palError); - } - - LOGEXIT("OpenSemaphoreW returns HANDLE %p\n", hSemaphore); - PERF_EXIT(OpenSemaphoreW); - - return hSemaphore; -} diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index b52e743d5e3ddd..0171e0b11fdf4b 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -343,14 +343,10 @@ add_executable_clr(paltests # pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/reg_unreg_libraryw_neg.cpp samples/test1/test.cpp samples/test2/test.cpp - threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.cpp - threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.cpp - threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.cpp threading/CreateThread/test1/test1.cpp threading/CreateThread/test2/test2.cpp threading/CreateThread/test3/test3.cpp threading/DuplicateHandle/test1/test1.cpp - threading/DuplicateHandle/test10/test10.cpp threading/DuplicateHandle/test12/test12.cpp threading/DuplicateHandle/test2/test2.cpp threading/DuplicateHandle/test3/test3.cpp @@ -370,7 +366,6 @@ add_executable_clr(paltests threading/OpenEventW/test2/test2.cpp threading/OpenEventW/test5/test5.cpp threading/QueryThreadCycleTime/test1/test1.cpp - threading/releasesemaphore/test1/test.cpp threading/ResetEvent/test1/test1.cpp threading/ResetEvent/test2/test2.cpp threading/ResetEvent/test3/test3.cpp @@ -388,7 +383,6 @@ add_executable_clr(paltests threading/ThreadPriority/test1/ThreadPriority.cpp threading/WaitForMultipleObjectsEx/test1/test1.cpp threading/WaitForSingleObject/test1/test1.cpp - threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.cpp threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.cpp threading/YieldProcessor/test1/test1.cpp ) diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index 558daa57a5f36d..b4409280d39c68 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -266,14 +266,10 @@ pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/paltest_pal_registerl pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/paltest_reg_unreg_libraryw_neg samples/test1/paltest_samples_test1 samples/test2/paltest_samples_test2 -threading/CreateSemaphoreW_ReleaseSemaphore/test1/paltest_createsemaphorew_releasesemaphore_test1 -threading/CreateSemaphoreW_ReleaseSemaphore/test2/paltest_createsemaphorew_releasesemaphore_test2 -threading/CreateSemaphoreW_ReleaseSemaphore/test3/paltest_createsemaphorew_releasesemaphore_test3 threading/CreateThread/test1/paltest_createthread_test1 threading/CreateThread/test2/paltest_createthread_test2 threading/CreateThread/test3/paltest_createthread_test3 threading/DuplicateHandle/test1/paltest_duplicatehandle_test1 -threading/DuplicateHandle/test10/paltest_duplicatehandle_test10 threading/DuplicateHandle/test12/paltest_duplicatehandle_test12 threading/DuplicateHandle/test2/paltest_duplicatehandle_test2 threading/DuplicateHandle/test3/paltest_duplicatehandle_test3 @@ -293,7 +289,6 @@ threading/OpenEventW/test1/paltest_openeventw_test1 threading/OpenEventW/test2/paltest_openeventw_test2 threading/OpenEventW/test5/paltest_openeventw_test5 threading/QueryThreadCycleTime/test1/paltest_querythreadcycletime_test1 -threading/releasesemaphore/test1/paltest_releasesemaphore_test1 threading/ResetEvent/test1/paltest_resetevent_test1 threading/ResetEvent/test2/paltest_resetevent_test2 threading/ResetEvent/test3/paltest_resetevent_test3 @@ -311,6 +306,5 @@ threading/TerminateProcess/test1/paltest_terminateprocess_test1 threading/ThreadPriority/test1/paltest_threadpriority_test1 threading/WaitForMultipleObjectsEx/test1/paltest_waitformultipleobjectsex_test1 threading/WaitForSingleObject/test1/paltest_waitforsingleobject_test1 -threading/WaitForSingleObject/WFSOSemaphoreTest/paltest_waitforsingleobject_wfsosemaphoretest threading/WaitForSingleObject/WFSOThreadTest/paltest_waitforsingleobject_wfsothreadtest threading/YieldProcessor/test1/paltest_yieldprocessor_test1 diff --git a/src/coreclr/pal/tests/palsuite/paltestlist.txt b/src/coreclr/pal/tests/palsuite/paltestlist.txt index ffc7d0d00b7173..3689d8dc2e690c 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist.txt @@ -237,11 +237,8 @@ miscellaneous/SetLastError/test1/paltest_setlasterror_test1 pal_specific/PAL_Initialize_Terminate/test1/paltest_pal_initialize_terminate_test1 pal_specific/PAL_Initialize_Terminate/test2/paltest_pal_initialize_terminate_test2 samples/test1/paltest_samples_test1 -threading/CreateSemaphoreW_ReleaseSemaphore/test1/paltest_createsemaphorew_releasesemaphore_test1 -threading/CreateSemaphoreW_ReleaseSemaphore/test2/paltest_createsemaphorew_releasesemaphore_test2 threading/CreateThread/test1/paltest_createthread_test1 threading/CreateThread/test3/paltest_createthread_test3 -threading/DuplicateHandle/test10/paltest_duplicatehandle_test10 threading/DuplicateHandle/test2/paltest_duplicatehandle_test2 threading/DuplicateHandle/test7/paltest_duplicatehandle_test7 threading/DuplicateHandle/test8/paltest_duplicatehandle_test8 @@ -253,7 +250,6 @@ threading/GetCurrentProcessId/test1/paltest_getcurrentprocessid_test1 threading/GetCurrentThread/test1/paltest_getcurrentthread_test1 threading/GetCurrentThread/test2/paltest_getcurrentthread_test2 threading/QueryThreadCycleTime/test1/paltest_querythreadcycletime_test1 -threading/releasesemaphore/test1/paltest_releasesemaphore_test1 threading/ResetEvent/test1/paltest_resetevent_test1 threading/ResetEvent/test2/paltest_resetevent_test2 threading/ResetEvent/test3/paltest_resetevent_test3 @@ -267,6 +263,5 @@ threading/SwitchToThread/test1/paltest_switchtothread_test1 threading/ThreadPriority/test1/paltest_threadpriority_test1 threading/WaitForMultipleObjectsEx/test1/paltest_waitformultipleobjectsex_test1 threading/WaitForSingleObject/test1/paltest_waitforsingleobject_test1 -threading/WaitForSingleObject/WFSOSemaphoreTest/paltest_waitforsingleobject_wfsosemaphoretest threading/WaitForSingleObject/WFSOThreadTest/paltest_waitforsingleobject_wfsothreadtest threading/YieldProcessor/test1/paltest_yieldprocessor_test1 diff --git a/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt b/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt index 9a4bd36028a636..8d4b296eb0d844 100644 --- a/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt +++ b/src/coreclr/pal/tests/palsuite/paltestlist_to_be_reviewed.txt @@ -66,7 +66,6 @@ miscellaneous/IsBadWritePtr/test3/paltest_isbadwriteptr_test3 pal_specific/PAL_get_stdout/test1/paltest_pal_get_stdout_test1 pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/paltest_pal_registerlibraryw_unregisterlibraryw_test1 samples/test2/paltest_samples_test2 -threading/CreateSemaphoreW_ReleaseSemaphore/test3/paltest_createsemaphorew_releasesemaphore_test3 threading/CreateThread/test2/paltest_createthread_test2 threading/DuplicateHandle/test1/paltest_duplicatehandle_test1 threading/DuplicateHandle/test12/paltest_duplicatehandle_test12 diff --git a/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.cpp b/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.cpp deleted file mode 100644 index ba98229594ed0a..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.cpp +++ /dev/null @@ -1,320 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source: CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c -** -** Purpose: Test Semaphore operation using classic IPC problem: -** "Producer-Consumer Problem". -** -** Dependencies: CreateThread -** ReleaseSemaphore -** WaitForSingleObject -** Sleep -** fflush -** - -** -**=========================================================*/ - -#define UNICODE -#include - -#define PRODUCTION_TOTAL 26 - -#define _BUF_SIZE 10 - -DWORD dwThreadId; /* consumer thread identifier */ - -HANDLE hThread; /* handle to consumer thread */ - -HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */ - -HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */ - -HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */ - -typedef struct Buffer -{ - short readIndex; - short writeIndex; - CHAR message[_BUF_SIZE]; - -} BufferStructure; - -CHAR producerItems[PRODUCTION_TOTAL + 1]; - -CHAR consumerItems[PRODUCTION_TOTAL + 1]; - -/* - * Read next message from the Buffer into provided pointer. - * Returns: 0 on failure, 1 on success. - */ -int -readBuf(BufferStructure *Buffer, char *c) -{ - if( Buffer -> writeIndex == Buffer -> readIndex ) - { - return 0; - } - *c = Buffer -> message[Buffer -> readIndex++]; - Buffer -> readIndex %= _BUF_SIZE; - return 1; -} - -/* - * Write message generated by the producer to Buffer. - * Returns: 0 on failure, 1 on success. - */ -int -writeBuf(BufferStructure *Buffer, CHAR c) -{ - if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) == - (Buffer -> readIndex) ) - { - return 0; - } - Buffer -> message[Buffer -> writeIndex++] = c; - Buffer -> writeIndex %= _BUF_SIZE; - return 1; -} - -/* - * Atomic decrement of semaphore value. - */ -VOID -down(HANDLE hSemaphore) -{ - switch ( (WaitForSingleObject ( - hSemaphore, - 10000))) /* Wait 10 seconds */ - { - case WAIT_OBJECT_0: /* - * Semaphore was signaled. OK to access - * semaphore. - */ - break; - case WAIT_FAILED: /* WaitForSingleObject function failed */ - Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n" - "GetLastError returned %d\nFailing Test.\n",GetLastError()); - break; - default: - Fail("WaitForSingleObject call returned an unexpected value.\n" - "Failing Test.\n"); - break; - } - -} - -/* - * Atomic increment of semaphore value. - */ -VOID -up(HANDLE hSemaphore) -{ - if (!ReleaseSemaphore ( - hSemaphore, - 1, - NULL) - ) - { - Fail("ReleaseSemaphore call failed. GetLastError returned %d\n", - GetLastError()); - } -} - -/* - * Sleep 500 milleseconds. - */ -VOID -consumerSleep(VOID) -{ - Sleep(500); -} - -/* - * Sleep between 10 milleseconds. - */ -VOID -producerSleep(VOID) -{ - Sleep(10); -} - -/* - * Produce a message and write the message to Buffer. - */ -VOID -producer(BufferStructure *Buffer) -{ - - int n = 0; - char c; - - while (n < PRODUCTION_TOTAL) - { - c = 'A' + n ; /* Produce Item */ - - down(hSemaphoreE); - down(hSemaphoreM); - - if (writeBuf(Buffer, c)) - { - Trace("Producer produces %c.\n", c); - fflush(stdout); - producerItems[n++] = c; - } - - up(hSemaphoreM); - up(hSemaphoreF); - - producerSleep(); - } - - return; -} - -/* - * Read and "Consume" the messages in Buffer. - */ -DWORD -PALAPI -consumer( LPVOID lpParam ) -{ - int n = 0; - char c; - - consumerSleep(); - - while (n < PRODUCTION_TOTAL) - { - - down(hSemaphoreF); - down(hSemaphoreM); - - if (readBuf((BufferStructure*)lpParam, &c)) - { - Trace("\tConsumer consumes %c.\n", c); - fflush(stdout); - consumerItems[n++] = c; - } - - up(hSemaphoreM); - up(hSemaphoreE); - - consumerSleep(); - } - - return 0; -} - -PALTEST(threading_CreateSemaphoreW_ReleaseSemaphore_test1_paltest_createsemaphorew_releasesemaphore_test1, "threading/CreateSemaphoreW_ReleaseSemaphore/test1/paltest_createsemaphorew_releasesemaphore_test1") -{ - BufferStructure Buffer, *pBuffer; - - pBuffer = &Buffer; - - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - /* - * Create Semaphores - */ - hSemaphoreM = CreateSemaphoreExW ( - NULL, - 1, - 1, - NULL, - 0, - 0); - - if ( NULL == hSemaphoreM ) - { - Fail ( "hSemaphoreM = CreateSemaphoreExW () - returned NULL\n" - "Failing Test.\nGetLastError returned %d\n", GetLastError()); - } - - - hSemaphoreE = CreateSemaphoreExW ( - NULL, - _BUF_SIZE , - _BUF_SIZE , - NULL, - 0, - 0); - - if ( NULL == hSemaphoreE ) - { - Fail ( "hSemaphoreE = CreateSemaphoreExW () - returned NULL\n" - "Failing Test.\nGetLastError returned %d\n", GetLastError()); - } - - hSemaphoreF = CreateSemaphoreExW ( - NULL, - 0, - _BUF_SIZE , - NULL, - 0, - 0); - - if ( NULL == hSemaphoreF ) - { - Fail ( "hSemaphoreF = CreateSemaphoreExW () - returned NULL\n" - "Failing Test.\nGetLastError returned %d\n", GetLastError()); - } - - - /* - * Initialize Buffer - */ - pBuffer->writeIndex = pBuffer->readIndex = 0; - - /* - * Create Consumer - */ - hThread = CreateThread( - NULL, - 0, - consumer, - &Buffer, - 0, - &dwThreadId); - - if ( NULL == hThread ) - { - Fail ( "CreateThread() returned NULL. Failing test.\n" - "GetLastError returned %d\n", GetLastError()); - } - - /* - * Start producing - */ - producer(pBuffer); - - /* - * Wait for consumer to complete - */ - WaitForSingleObject (hThread, INFINITE); - - /* - * Compare items produced vs. items consumed - */ - if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) ) - { - Fail("The producerItems string %s\n and the consumerItems string " - "%s\ndo not match. This could be a problem with the strncmp()" - " function\n FailingTest\nGetLastError() returned %d\n", - producerItems, consumerItems, GetLastError()); - } - - Trace ("producerItems and consumerItems arrays match. All %d\nitems " - "were produced and consumed in order.\nTest passed.\n", - PRODUCTION_TOTAL); - - PAL_Terminate(); - return ( PASS ); - -} diff --git a/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.cpp b/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.cpp deleted file mode 100644 index f5601c4f782686..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source: CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c -** -** Purpose: Test Semaphore operation using classic IPC problem: -** "Producer-Consumer Problem". -** -** Dependencies: CreateThread -** ReleaseSemaphore -** WaitForSingleObject -** Sleep -** fflush -** - -** -**=========================================================*/ - -#define UNICODE -#include - -#define PRODUCTION_TOTAL 26 - -#define _BUF_SIZE 10 - -DWORD dwThreadId_CreateSemaphoreW_test2; /* consumer thread identifier */ - -HANDLE hThread_CreateSemaphoreW_test2; /* handle to consumer thread */ - -HANDLE hSemaphoreM_CreateSemaphoreW_test2; /* handle to mutual exclusion semaphore */ - -HANDLE hSemaphoreE_CreateSemaphoreW_test2; /* handle to semaphore that counts empty buffer slots */ - -HANDLE hSemaphoreF_CreateSemaphoreW_test2; /* handle to semaphore that counts full buffer slots */ - -typedef struct Buffer -{ - short readIndex; - short writeIndex; - CHAR message[_BUF_SIZE]; - -} BufferStructure; - -CHAR producerItems_CreateSemaphoreW_test2[PRODUCTION_TOTAL + 1]; - -CHAR consumerItems_CreateSemaphoreW_test2[PRODUCTION_TOTAL + 1]; - -/* - * Read next message from the Buffer into provided pointer. - * Returns: 0 on failure, 1 on success. - */ -int -readBuf_CreateSemaphoreW_test2(BufferStructure *Buffer, char *c) -{ - if( Buffer -> writeIndex == Buffer -> readIndex ) - { - return 0; - } - *c = Buffer -> message[Buffer -> readIndex++]; - Buffer -> readIndex %= _BUF_SIZE; - return 1; -} - -/* - * Write message generated by the producer to Buffer. - * Returns: 0 on failure, 1 on success. - */ -int -writeBuf_CreateSemaphoreW_test2(BufferStructure *Buffer, CHAR c) -{ - if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) == - (Buffer -> readIndex) ) - { - return 0; - } - Buffer -> message[Buffer -> writeIndex++] = c; - Buffer -> writeIndex %= _BUF_SIZE; - return 1; -} - -/* - * Atomic decrement of semaphore value. - */ -VOID -down_CreateSemaphoreW_test2(HANDLE hSemaphore) -{ - switch ( (WaitForSingleObject ( - hSemaphore, - 10000))) /* Wait 10 seconds */ - { - case WAIT_OBJECT_0: /* - * Semaphore was signaled. OK to access - * semaphore. - */ - break; - case WAIT_FAILED: /* WaitForSingleObject function failed */ - Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n" - "GetLastError returned %d\nFailing Test.\n",GetLastError()); - break; - default: - Fail("WaitForSingleObject call returned an unexpected value.\n" - "Failing Test.\n"); - break; - } - -} - -/* - * Atomic increment of semaphore value. - */ -VOID -up_CreateSemaphoreW_test2(HANDLE hSemaphore) -{ - if (!ReleaseSemaphore ( - hSemaphore, - 1, - NULL) - ) - { - Fail("ReleaseSemaphore call failed. GetLastError returned %d\n", - GetLastError()); - } -} - -/* - * Sleep 500 milleseconds. - */ -VOID -consumerSleep_CreateSemaphoreW_test2(VOID) -{ - Sleep(10); -} - -/* - * Sleep between 10 milleseconds. - */ -VOID -producerSleep_CreateSemaphoreW_test2(VOID) -{ - Sleep(500); -} - -/* - * Produce a message and write the message to Buffer. - */ -VOID -producer_CreateSemaphoreW_test2(BufferStructure *Buffer) -{ - - int n = 0; - char c; - - while (n < PRODUCTION_TOTAL) - { - c = 'A' + n ; /* Produce Item */ - - down_CreateSemaphoreW_test2(hSemaphoreE_CreateSemaphoreW_test2); - down_CreateSemaphoreW_test2(hSemaphoreM_CreateSemaphoreW_test2); - - if (writeBuf_CreateSemaphoreW_test2(Buffer, c)) - { - Trace("Producer produces %c.\n", c); - fflush(stdout); - producerItems_CreateSemaphoreW_test2[n++] = c; - } - - up_CreateSemaphoreW_test2(hSemaphoreM_CreateSemaphoreW_test2); - up_CreateSemaphoreW_test2(hSemaphoreF_CreateSemaphoreW_test2); - - producerSleep_CreateSemaphoreW_test2(); - } - - return; -} - -/* - * Read and "Consume" the messages in Buffer. - */ -DWORD -PALAPI -consumer_CreateSemaphoreW_test2( LPVOID lpParam ) -{ - int n = 0; - char c; - - consumerSleep_CreateSemaphoreW_test2(); - - while (n < PRODUCTION_TOTAL) - { - - down_CreateSemaphoreW_test2(hSemaphoreF_CreateSemaphoreW_test2); - down_CreateSemaphoreW_test2(hSemaphoreM_CreateSemaphoreW_test2); - - if (readBuf_CreateSemaphoreW_test2((BufferStructure*)lpParam, &c)) - { - Trace("\tConsumer consumes %c.\n", c); - fflush(stdout); - consumerItems_CreateSemaphoreW_test2[n++] = c; - } - - up_CreateSemaphoreW_test2(hSemaphoreM_CreateSemaphoreW_test2); - up_CreateSemaphoreW_test2(hSemaphoreE_CreateSemaphoreW_test2); - - consumerSleep_CreateSemaphoreW_test2(); - } - - return 0; -} - -PALTEST(threading_CreateSemaphoreW_ReleaseSemaphore_test2_paltest_createsemaphorew_releasesemaphore_test2, "threading/CreateSemaphoreW_ReleaseSemaphore/test2/paltest_createsemaphorew_releasesemaphore_test2") -{ - BufferStructure Buffer, *pBuffer; - - pBuffer = &Buffer; - - if(0 != (PAL_Initialize(argc, argv))) - { - return (FAIL); - } - - /* - * Create Semaphores - */ - hSemaphoreM_CreateSemaphoreW_test2 = CreateSemaphoreExW ( - NULL, - 1, - 1, - NULL, - 0, - 0); - - if ( NULL == hSemaphoreM_CreateSemaphoreW_test2 ) - { - Fail ( "hSemaphoreM_CreateSemaphoreW_test2 = CreateSemaphoreExW () - returned NULL\n" - "Failing Test.\n"); - } - - hSemaphoreE_CreateSemaphoreW_test2 = CreateSemaphoreExW ( - NULL, - _BUF_SIZE , - _BUF_SIZE , - NULL, - 0, - 0); - - if ( NULL == hSemaphoreE_CreateSemaphoreW_test2 ) - { - Fail ( "hSemaphoreE_CreateSemaphoreW_test2 = CreateSemaphoreExW () - returned NULL\n" - "Failing Test.\n"); - } - - hSemaphoreF_CreateSemaphoreW_test2 = CreateSemaphoreExW ( - NULL, - 0, - _BUF_SIZE , - NULL, - 0, - 0); - - if ( NULL == hSemaphoreF_CreateSemaphoreW_test2 ) - { - Fail ( "hSemaphoreF_CreateSemaphoreW_test2 = CreateSemaphoreExW () - returned NULL\n" - "Failing Test.\n"); - } - - /* - * Initialize Buffer - */ - pBuffer->writeIndex = pBuffer->readIndex = 0; - - /* - * Create Consumer - */ - hThread_CreateSemaphoreW_test2 = CreateThread( - NULL, - 0, - consumer_CreateSemaphoreW_test2, - &Buffer, - 0, - &dwThreadId_CreateSemaphoreW_test2); - - if ( NULL == hThread_CreateSemaphoreW_test2 ) - { - Fail ( "CreateThread() returned NULL. Failing test.\n"); - } - - /* - * Start producing - */ - producer_CreateSemaphoreW_test2(pBuffer); - - /* - * Wait for consumer to complete - */ - WaitForSingleObject (hThread_CreateSemaphoreW_test2, INFINITE); - - if ( 0 != strncmp (producerItems_CreateSemaphoreW_test2, consumerItems_CreateSemaphoreW_test2, PRODUCTION_TOTAL) ) - { - Fail("The producerItems_CreateSemaphoreW_test2 string %s\n and the consumerItems_CreateSemaphoreW_test2 string " - "%s\ndo not match. This could be a problem with the strncmp()" - " function\n FailingTest\nGetLastError() returned %d\n", - producerItems_CreateSemaphoreW_test2, consumerItems_CreateSemaphoreW_test2, GetLastError()); - } - - Trace ("producerItems_CreateSemaphoreW_test2 and consumerItems_CreateSemaphoreW_test2 arrays match. All %d\nitems " - "were produced and consumed in order.\nTest passed.\n", - PRODUCTION_TOTAL); - - PAL_Terminate(); - return ( PASS ); - -} diff --git a/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.cpp b/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.cpp deleted file mode 100644 index 3e3cec38732476..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================================ -** -** Source: createsemaphorew_releasesemaphore/test3/createsemaphore.c -** -** Purpose: Test attributes of CreateSemaphoreExW and ReleaseSemaphore. -** Ensure for CreateSemaphore that lInitialCount and lMaximumCount -** constraints are respected. Validate that CreateSemaphore rejects -** conditions where initial count and / or maximum count are negative -** and conditions where the initial count is greater than the maximum -** count. For ReleaseSemaphore validate that lpPreviousCount gets set -** to the previous semaphore count and lpPreviousCount can be NULL. -** Also establish ReleaseSemaphore fails when called in a semaphore -** with count equal to lMaximumCount. -** -** -**==========================================================================*/ - -#include - -struct testcase -{ - LPSECURITY_ATTRIBUTES lpSemaphoreAttributes; - LONG lInitialCount; - LONG lMaximumCount; - LPCWSTR lpName; - BOOL bNegativeTest; -}; - -struct testcase testCases_CreateSemaphoreW_ReleaseSemaphore_test3[] = -{ - {NULL, -1, 1, NULL, TRUE}, - {NULL, 1, -1, NULL, TRUE}, - {NULL, -1, -1, NULL, TRUE}, - {NULL, 2, 1, NULL, TRUE}, - {NULL, 1, 2, NULL, FALSE}, - {NULL, 0, 10, NULL, FALSE}, - {NULL, INT_MAX - 1, INT_MAX, NULL, FALSE}, - {NULL, INT_MAX, INT_MAX, NULL, FALSE} -}; - -HANDLE hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[sizeof(testCases_CreateSemaphoreW_ReleaseSemaphore_test3)/sizeof(struct testcase)]; - -BOOL cleanup_ReleaseSemaphore_test3(int index) -{ - int i; - BOOL bRet = TRUE; - for (i = 0; i < index; i++) - { - if (!CloseHandle(hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i])) - { - bRet = FALSE; - Trace("PALSUITE ERROR: CloseHandle(%p) call failed for index %d\n", - hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], i); - } - } - return(bRet); -} - -PALTEST(threading_CreateSemaphoreW_ReleaseSemaphore_test3_paltest_createsemaphorew_releasesemaphore_test3, "threading/CreateSemaphoreW_ReleaseSemaphore/test3/paltest_createsemaphorew_releasesemaphore_test3") -{ - int i; - int j; - - if(0 != (PAL_Initialize(argc, argv))) - { - return (FAIL); - } - /* create semaphores */ - testcase* testCases = testCases_CreateSemaphoreW_ReleaseSemaphore_test3; - - for (i = 0; i < sizeof(testCases_CreateSemaphoreW_ReleaseSemaphore_test3)/sizeof(struct testcase); i++) - { - hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i] = CreateSemaphoreExW (testCases[i].lpSemaphoreAttributes, - testCases[i].lInitialCount, - testCases[i].lMaximumCount, - testCases[i].lpName, - 0, - 0); - - if (NULL == hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i]) - { - if (!testCases[i].bNegativeTest) - { - Trace("PALSUITE ERROR: CreateSemaphoreExW('%p' '%ld' '%ld' " - "'%p' '0' '0') returned NULL at index %d.\nGetLastError " - "returned %d.\n", testCases[i].lpSemaphoreAttributes, - testCases[i].lInitialCount, testCases[i].lMaximumCount, - testCases[i].lpName, i, GetLastError()); - if (i > 0) - { - cleanup_ReleaseSemaphore_test3(i - 1); - } - Fail(""); - } - else - { - continue; - } - } - - /* increment semaphore count to lMaximumCount */ - for (j = testCases[i].lInitialCount; (ULONG)j <= (ULONG)testCases[i].lMaximumCount; - j++) - { - if (testCases[i].lMaximumCount == j) - { - /* Call ReleaseSemaphore once more to ensure ReleaseSemaphore - fails */ - if(ReleaseSemaphore(hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 1, NULL)) - { - Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " - "call returned %d\nwhen it should have returned " - "%d.\nThe semaphore's count was %d.\nGetLastError " - "returned %d.\n", hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 1, NULL, TRUE, - - FALSE, j, GetLastError()); - cleanup_ReleaseSemaphore_test3(i); - Fail(""); - } - } - else - { - int previous; - BOOL bRet = ReleaseSemaphore(hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 1, &previous); - DWORD dwError = GetLastError(); - - if(!bRet) - { - Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " - "call returned %d\nwhen it should have returned " - "%d.\nThe semaphore count was %d and it's " - "lMaxCount was %d.\nGetLastError returned %d.\n", - hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 1, &previous, bRet, TRUE, j, - testCases[i].lMaximumCount, dwError); - cleanup_ReleaseSemaphore_test3(i); - Fail(""); - } - if (previous != j) - { - Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " - "call set %p to %d instead of %d.\n The semaphore " - "count was %d and GetLastError returned %d.\n", - hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 1, &previous, &previous, previous, - j, j, dwError); - cleanup_ReleaseSemaphore_test3(i); - Fail(""); - } - } - } - - // Skip exhaustive decrement tests for too large an initial count - if(testCases[i].lInitialCount >= INT_MAX - 1) - { - continue; - } - - /* decrement semaphore count to 0 */ - for (j = testCases[i].lMaximumCount; j >= 0; j--) - { - DWORD dwRet = WaitForSingleObject(hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 0); - DWORD dwError = GetLastError(); - - if (0 == j) - { - /* WaitForSingleObject should report that the - semaphore is nonsignaled */ - if (WAIT_TIMEOUT != dwRet) - { - Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') " - "call returned %d\nwhen it should have returned " - "%d.\nThe semaphore's count was %d.\nGetLastError " - "returned %d.\n", hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 0, dwRet, - WAIT_TIMEOUT, j, dwError); - cleanup_ReleaseSemaphore_test3(i); - Fail(""); - } - } - else - { - /* WaitForSingleObject should report that the - semaphore is signaled */ - if (WAIT_OBJECT_0 != dwRet) - { - Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') " - "call returned %d\nwhen it should have returned " - "%d.\nThe semaphore's count was %d.\nGetLastError " - "returned %d.\n", hSemaphore_CreateSemaphoreW_ReleaseSemaphore_test3[i], 0, dwRet, - WAIT_OBJECT_0, j, dwError); - cleanup_ReleaseSemaphore_test3(i); - Fail(""); - } - } - } - } - PAL_Terminate(); - return (PASS); -} - - - - - diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.cpp deleted file mode 100644 index 2f1d27dec63240..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.cpp +++ /dev/null @@ -1,240 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*===================================================================== -** -** Source: test10.c (DuplicateHandle) -** -** Purpose: Tests the PAL implementation of the DuplicateHandle function. -** This tests the operation of a duplicated Semaphore handle -** -** -**===================================================================*/ - -#include - -enum wait_results -{ - WR_WAITING, - WR_GOT_MUTEX, - WR_TIMED_OUT, - WR_RELEASED -}; - - -volatile int t1_result_DuplicateHandle_test10=WR_WAITING; -volatile int t2_result_DuplicateHandle_test10=WR_WAITING; - - -DWORD PALAPI ThreadTest1_DuplicateHandle_test10(LPVOID lpParam) -{ - DWORD dwWait; - - dwWait = WaitForSingleObject((HANDLE)lpParam, 0); - if (dwWait == WAIT_OBJECT_0) - { - /* tell the main thread we got the mutex */ - t1_result_DuplicateHandle_test10=WR_GOT_MUTEX; - - /* wait for main thread to tell us to release the mutex */ - while(WR_GOT_MUTEX == t1_result_DuplicateHandle_test10) - Sleep(1); - ReleaseSemaphore((HANDLE)lpParam, 1, NULL); - - /* tell the main thread we released the mutex */ - t1_result_DuplicateHandle_test10 = WR_RELEASED; - } - else - { - t1_result_DuplicateHandle_test10 = WR_TIMED_OUT; - } - return 0; -} - -DWORD PALAPI ThreadTest2_DuplicateHandle_test10(LPVOID lpParam) -{ - DWORD dwWait; - - dwWait = WaitForSingleObject((HANDLE)lpParam, 0 ); - if (dwWait == WAIT_OBJECT_0) - { - ReleaseSemaphore((HANDLE)lpParam, 1, NULL); - t2_result_DuplicateHandle_test10 = WR_GOT_MUTEX; - } - else - { - t2_result_DuplicateHandle_test10 = WR_TIMED_OUT; - } - - return 0; -} - - -PALTEST(threading_DuplicateHandle_test10_paltest_duplicatehandle_test10, "threading/DuplicateHandle/test10/paltest_duplicatehandle_test10") -{ - - HANDLE hDupSemaphore; - HANDLE hSemaphore; - HANDLE hThread; - HANDLE hThread2; - BOOL bDupHandle=FALSE; - DWORD dwThreadId = 0; - - if ((PAL_Initialize(argc,argv)) != 0) - { - return(FAIL); - } - - hSemaphore = CreateSemaphoreExW( NULL, - 1, - 1, - NULL, - 0, - 0); - if (hSemaphore == NULL) - { - Fail("PALSUITE ERROR:%u: Unable to create mutex\n", - GetLastError()); - } - - /*Create Duplicate of the Semaphore above*/ - bDupHandle = DuplicateHandle(GetCurrentProcess(), - hSemaphore, - GetCurrentProcess(), - &hDupSemaphore, - GENERIC_READ|GENERIC_WRITE, - FALSE, - DUPLICATE_SAME_ACCESS); - if (!bDupHandle) - { - Trace("PALSUITE ERROR:%u: Created the duplicate handle to " - "closed event handle hSemaphore=0x%lx\n", - GetLastError(), - hSemaphore); - CloseHandle(hSemaphore); - Fail(""); - } - - /*Create a thread to test the Semaphore*/ - hThread = CreateThread(NULL, - 0, - &ThreadTest1_DuplicateHandle_test10, - hSemaphore, - 0, - &dwThreadId); - if (hThread == NULL) - { - Trace("PALSUITE ERROR:%u: unable to create thread\n", - GetLastError()); - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - Fail(""); - } - - /* wait until thread has taken the mutex */ - while (WR_WAITING == t1_result_DuplicateHandle_test10) - Sleep(1); - - if(WR_TIMED_OUT == t1_result_DuplicateHandle_test10) - { - Trace("PALSUITE ERROR: %u: thread couldn't acquire the semaphore\n", - GetLastError()); - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - CloseHandle(hThread); - Fail(""); - } - - /*Create a second thread to use the Semaphore's duplicate handle*/ - /*This thread should block since the Semaphore is owned by another - thread*/ - hThread2 = CreateThread(NULL, - 0, - &ThreadTest2_DuplicateHandle_test10, - hDupSemaphore, - 0, - &dwThreadId); - - if (hThread2 == NULL) - { - Trace("PALSUITE ERROR:%u: unable to create thread\n", - GetLastError()); - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - CloseHandle(hThread); - Fail(""); - } - - /* wait until thread has tried to take the mutex */ - while (WR_WAITING == t2_result_DuplicateHandle_test10) - Sleep(1); - - if (WR_TIMED_OUT != t2_result_DuplicateHandle_test10 ) - { - Trace("PALSUITE ERROR:%u: Able to take mutex %#x while its " - "duplicate %#x is held\n", GetLastError(), hDupSemaphore, - hSemaphore); - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - CloseHandle(hThread); - CloseHandle(hThread2); - Fail(""); - } - - /* reset second thread status */ - t2_result_DuplicateHandle_test10 = WR_WAITING; - - /* tell thread 1 to release the mutex */ - t1_result_DuplicateHandle_test10 = WR_WAITING; - - /* wait for thread 1 to release the mutex */ - while (WR_WAITING == t1_result_DuplicateHandle_test10) - Sleep(1); - - CloseHandle(hThread2); - - /*Re-Create the second thread to reuse the duplicated Semaphore*/ - /*Since the Semaphore has since been released, the thread should - put WR_GOT_MUTEX into t2_result */ - hThread2 = CreateThread(NULL, - 0, - &ThreadTest2_DuplicateHandle_test10, - hDupSemaphore, - 0, - &dwThreadId); - - if (hThread2 == NULL) - { - Trace("PALSUITE ERROR:%u: unable to create thread\n", - GetLastError()); - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - CloseHandle(hThread); - Fail(""); - } - - /* wait until thread has taken the semaphore */ - while (WR_WAITING == t2_result_DuplicateHandle_test10) - Sleep(1); - - if (WR_GOT_MUTEX != t2_result_DuplicateHandle_test10 ) - { - Trace("PALSUITE ERROR:%u: Unable to take semaphore %#x after its" - " duplicate %#x was released\n", GetLastError(), hDupSemaphore, - hSemaphore); - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - CloseHandle(hThread); - CloseHandle(hThread2); - Fail(""); - } - - /*Cleanup.*/ - CloseHandle(hSemaphore); - CloseHandle(hDupSemaphore); - CloseHandle(hThread); - CloseHandle(hThread2); - - PAL_Terminate(); - return (PASS); -} diff --git a/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.cpp b/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.cpp deleted file mode 100644 index d0103a4fd089dd..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source: WFSOMutexTest.c -** -** Purpose: Test for WaitForSingleObjectTest. -** Create Semaphore Object -** Create Two Threads, Each Threads does WFSO for the Semaphore Object -** Increments Counter -** Releases Semaphore -** Test Passes if the above operations are successful -** -** -** -**=========================================================*/ - - - -#include - - -#define NUMBER_OF_WORKER_THREADS 2 - - -//Declaring Variables -HANDLE hSemaphore_WFSOSemaphore = NULL; -unsigned int globalcounter_WFSOSemaphore =0; - -//Declaring Function Prototypes -DWORD PALAPI WFSOSemaphoreTest(LPVOID params); -void incrementCounter_WFSOSemaphore(void); - -PALTEST(threading_WaitForSingleObject_WFSOSemaphoreTest_paltest_waitforsingleobject_wfsosemaphoretest, "threading/WaitForSingleObject/WFSOSemaphoreTest/paltest_waitforsingleobject_wfsosemaphoretest") -{ - - //Declare local variables - int testReturnCode = PASS; - int i =0; - int cMax = 2; - - int returnCode = 0; - - // 2 dimensional array to hold thread handles for each worker thread - HANDLE hThread[NUMBER_OF_WORKER_THREADS]; - DWORD dwThreadId=0; - - //Initialize PAL - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - //Create Semaphore - hSemaphore_WFSOSemaphore = CreateSemaphoreExW( - NULL, // no security attributes - cMax, // initial count - cMax, // maximum count - NULL, // unnamed semaphore - 0, - 0); - - if (hSemaphore_WFSOSemaphore == NULL) - { - // Check for error. - Fail("Create Semaphore Failed, GetLastError: %d\n", GetLastError()); - } - - - - //Spawn 2 worker threads - for (i=0;i - - -PALTEST(threading_releasesemaphore_test1_paltest_releasesemaphore_test1, "threading/releasesemaphore/test1/paltest_releasesemaphore_test1") -{ - HANDLE hSemaphore; - if(0 != (PAL_Initialize(argc, argv))) - { - return (FAIL); - } - hSemaphore = CreateSemaphoreExW (NULL, 1, 2, NULL, 0, 0); - - if (NULL == hSemaphore) - { - Fail("PALSUITE ERROR: CreateSemaphoreExW ('%p' '%ld' '%ld' " - "'%p' '0' '0') returned NULL.\nGetLastError returned %d.\n", - NULL, 1, 2, NULL, GetLastError()); - } - - if(ReleaseSemaphore(hSemaphore, 0, NULL)) - { - Fail("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " - "call returned %d\nwhen it should have returned " - "%d.\nGetLastError returned %d.\n", - hSemaphore, 0, NULL, FALSE, TRUE, GetLastError()); - } - - if(ReleaseSemaphore(hSemaphore, -1, NULL)) - { - Fail("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " - "call returned %d\nwhen it should have returned " - "%d.\nGetLastError returned %d.\n", - hSemaphore, -1, NULL, TRUE, FALSE, GetLastError()); - } - - if(!CloseHandle(hSemaphore)) - { - Fail("PALSUITE ERROR: CloseHandle(%p) call failed. GetLastError " - "returned %d.\n", hSemaphore, GetLastError()); - } - - if(ReleaseSemaphore(hSemaphore, 1, NULL)) - { - Fail("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " - "call incremented semaphore %p count\nafter the handle " - "was closed by a call to CloseHandle.\n GetLastError returned " - "%d.\n", hSemaphore, -1, NULL, hSemaphore, GetLastError()); - } - - PAL_Terminate(); - return (PASS); -} diff --git a/src/coreclr/utilcode/CMakeLists.txt b/src/coreclr/utilcode/CMakeLists.txt index 61f026689619a6..31761162140ffb 100644 --- a/src/coreclr/utilcode/CMakeLists.txt +++ b/src/coreclr/utilcode/CMakeLists.txt @@ -16,7 +16,6 @@ set(UTILCODE_COMMON_SOURCES collections.cpp posterror.cpp clrhelpers.cpp - utsem.cpp check.cpp log.cpp arraylist.cpp diff --git a/src/coreclr/utilcode/utsem.cpp b/src/coreclr/utilcode/utsem.cpp deleted file mode 100644 index c916d0509bdec8..00000000000000 --- a/src/coreclr/utilcode/utsem.cpp +++ /dev/null @@ -1,504 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -/****************************************************************************** - FILE : UTSEM.CPP - - - - Purpose: Part of the utilities library for the VIPER project - - Abstract : Implements the UTSemReadWrite class. -------------------------------------------------------------------------------- -Revision History: - - -*******************************************************************************/ -#include "stdafx.h" -#include "clrhost.h" -#include "ex.h" - -#include -#include "contract.h" - -// Consider replacing this with a #ifdef INTEROP_DEBUGGING -#if !defined(SELF_NO_HOST) && defined(TARGET_X86) && !defined(TARGET_UNIX) -// For Interop debugging, the UTSemReadWrite class must inform the debugger -// that this thread can't be suspended currently. See vm\util.hpp for the -// implementation of these methods. -void IncCantStopCount(); -void DecCantStopCount(); -#else -#define IncCantStopCount() -#define DecCantStopCount() -#endif // !SELF_NO_HOST && TARGET_X86 - -/****************************************************************************** -Definitions of the bit fields in UTSemReadWrite::m_dwFlag: - -Warning: The code assume that READER_MASK is in the low-order bits of the DWORD. -******************************************************************************/ - -const ULONG READERS_MASK = 0x000003FF; // field that counts number of readers -const ULONG READERS_INCR = 0x00000001; // amount to add to increment number of readers - -// The following field is 2 bits long to make it easier to catch errors. -// (If the number of writers ever exceeds 1, we've got problems.) -const ULONG WRITERS_MASK = 0x00000C00; // field that counts number of writers -const ULONG WRITERS_INCR = 0x00000400; // amount to add to increment number of writers - -const ULONG READWAITERS_MASK = 0x003FF000; // field that counts number of threads waiting to read -const ULONG READWAITERS_INCR = 0x00001000; // amount to add to increment number of read waiters - -const ULONG WRITEWAITERS_MASK = 0xFFC00000; // field that counts number of threads waiting to write -const ULONG WRITEWAITERS_INCR = 0x00400000; // amount to add to increment number of write waiters - -// ====================================================================================== -// Spinning support - -// Copy of definition from file:..\VM\spinlock.h -#define CALLER_LIMITS_SPINNING 0 - -#if (defined(SELF_NO_HOST)) || (defined(TARGET_UNIX) && defined(DACCESS_COMPILE)) - -// When we do not have host, we just call OS - see file:..\VM\hosting.cpp#__SwitchToThread -BOOL __SwitchToThread(DWORD dwSleepMSec, DWORD dwSwitchCount) -{ - // This is just simple implementation that does not support full dwSwitchCount arg - _ASSERTE(dwSwitchCount == CALLER_LIMITS_SPINNING); - return SwitchToThread(); -} - -Volatile g_fInitializedGlobalSystemInfo = FALSE; - -// Global System Information -SYSTEM_INFO g_SystemInfo; - -// Configurable constants used across our spin locks -SpinConstants g_SpinConstants = { - 50, // dwInitialDuration - 40000, // dwMaximumDuration - ideally (20000 * max(2, numProc)) ... updated in code:InitializeSpinConstants_NoHost - 3, // dwBackoffFactor - 10, // dwRepetitions -}; - -inline void InitializeSpinConstants_NoHost() -{ - g_SpinConstants.dwMaximumDuration = max((DWORD)2, g_SystemInfo.dwNumberOfProcessors) * 20000; -} - -#else //!SELF_NO_HOST - -// Use VM/CrossGen functions and variables -BOOL __SwitchToThread (DWORD dwSleepMSec, DWORD dwSwitchCount); -extern SYSTEM_INFO g_SystemInfo; -extern SpinConstants g_SpinConstants; - -#endif //!SELF_NO_HOST - -/****************************************************************************** -Function : UTSemReadWrite::UTSemReadWrite - -Abstract: Constructor. -******************************************************************************/ -UTSemReadWrite::UTSemReadWrite() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - -#if defined(SELF_NO_HOST) - if (!g_fInitializedGlobalSystemInfo) - { - GetSystemInfo(&g_SystemInfo); - InitializeSpinConstants_NoHost(); - - g_fInitializedGlobalSystemInfo = TRUE; - } -#endif //SELF_NO_HOST - - m_dwFlag = 0; - m_hReadWaiterSemaphore = NULL; - m_hWriteWaiterEvent = NULL; -} - - -/****************************************************************************** -Function : UTSemReadWrite::~UTSemReadWrite - -Abstract: Destructor -******************************************************************************/ -UTSemReadWrite::~UTSemReadWrite() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - _ASSERTE_MSG((m_dwFlag == (ULONG)0), "Destroying a UTSemReadWrite while in use"); - - if (m_hReadWaiterSemaphore != NULL) - CloseHandle(m_hReadWaiterSemaphore); - - if (m_hWriteWaiterEvent != NULL) - CloseHandle(m_hWriteWaiterEvent); -} - -//======================================================================================= -// -// Initialize the lock (its semaphore and event) -// -HRESULT -UTSemReadWrite::Init() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - - _ASSERTE(m_hReadWaiterSemaphore == NULL); - _ASSERTE(m_hWriteWaiterEvent == NULL); - - m_hReadWaiterSemaphore = CreateSemaphore(NULL, 0, MAXLONG, NULL); - IfNullRet(m_hReadWaiterSemaphore); - - m_hWriteWaiterEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - IfNullRet(m_hWriteWaiterEvent); - - return S_OK; -} // UTSemReadWrite::Init - -/****************************************************************************** -Function : UTSemReadWrite::LockRead - -Abstract: Obtain a shared lock -******************************************************************************/ -HRESULT UTSemReadWrite::LockRead() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - CAN_TAKE_LOCK; - } - CONTRACTL_END; - - // Inform CLR that the debugger shouldn't suspend this thread while - // holding this lock. - IncCantStopCount(); - - // First do some spinning - for (DWORD iter = 0; iter < g_SpinConstants.dwRepetitions; iter++) - { - DWORD i = g_SpinConstants.dwInitialDuration; - - do - { - DWORD dwFlag = m_dwFlag; - - if (dwFlag < READERS_MASK) - { // There are just readers in the play, try to add one more - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag + READERS_INCR, dwFlag)) - { - goto ReadLockAcquired; - } - } - - if (g_SystemInfo.dwNumberOfProcessors <= 1) - { // We do not need to spin on a single processor - break; - } - - // Delay by approximately 2*i clock cycles (Pentium III). - YieldProcessorNormalizedForPreSkylakeCount(i); - - // exponential backoff: wait a factor longer in the next iteration - i *= g_SpinConstants.dwBackoffFactor; - } while (i < g_SpinConstants.dwMaximumDuration); - - __SwitchToThread(0, CALLER_LIMITS_SPINNING); - } - // Stop spinning - - // Start waiting - for (;;) - { - DWORD dwFlag = m_dwFlag; - - if (dwFlag < READERS_MASK) - { // There are just readers in the play, try to add one more - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag + READERS_INCR, dwFlag)) - { - break; - } - } - else if ((dwFlag & READERS_MASK) == READERS_MASK) - { // The number of readers has reached the maximum (0x3ff), wait 1s - ClrSleepEx(1000, FALSE); - } - else if ((dwFlag & READWAITERS_MASK) == READWAITERS_MASK) - { // The number of readers waiting on semaphore has reached the maximum (0x3ff), wait 1s - ClrSleepEx(1000, FALSE); - } - else - { // Try to add waiting reader and then wait for signal - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag + READWAITERS_INCR, dwFlag)) - { - WaitForSingleObjectEx(m_hReadWaiterSemaphore, INFINITE, FALSE); - break; - } - } - } - -ReadLockAcquired: - _ASSERTE ((m_dwFlag & READERS_MASK) != 0 && "reader count is zero after acquiring read lock"); - _ASSERTE ((m_dwFlag & WRITERS_MASK) == 0 && "writer count is nonzero after acquiring write lock"); - EE_LOCK_TAKEN(this); - - return S_OK; -} // UTSemReadWrite::LockRead - - - -/****************************************************************************** -Function : UTSemReadWrite::LockWrite - -Abstract: Obtain an exclusive lock -******************************************************************************/ -HRESULT UTSemReadWrite::LockWrite() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - CAN_TAKE_LOCK; - } - CONTRACTL_END; - - // Inform CLR that the debugger shouldn't suspend this thread while - // holding this lock. - IncCantStopCount(); - - // First do some spinning - for (DWORD iter = 0; iter < g_SpinConstants.dwRepetitions; iter++) - { - DWORD i = g_SpinConstants.dwInitialDuration; - - do - { - DWORD dwFlag = m_dwFlag; - - if (dwFlag == 0) - { // No readers/writers in play, try to add a writer - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, WRITERS_INCR, dwFlag)) - { - goto WriteLockAcquired; - } - } - - if (g_SystemInfo.dwNumberOfProcessors <= 1) - { // We do not need to spin on a single processor - break; - } - - // Delay by approximately 2*i clock cycles (Pentium III). - YieldProcessorNormalizedForPreSkylakeCount(i); - - // exponential backoff: wait a factor longer in the next iteration - i *= g_SpinConstants.dwBackoffFactor; - } while (i < g_SpinConstants.dwMaximumDuration); - - __SwitchToThread(0, CALLER_LIMITS_SPINNING); - } - // Stop spinning - - // Start waiting - for (;;) - { - DWORD dwFlag = m_dwFlag; - - if (dwFlag == 0) - { // No readers/writers in play, try to add a writer - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, WRITERS_INCR, dwFlag)) - { - break; - } - } - else if ((dwFlag & WRITEWAITERS_MASK) == WRITEWAITERS_MASK) - { // The number of writers waiting on semaphore has reached the maximum (0x3ff), wait 1s - ClrSleepEx(1000, FALSE); - } - else - { // Try to add waiting writer and then wait for signal - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag + WRITEWAITERS_INCR, dwFlag)) - { - WaitForSingleObjectEx(m_hWriteWaiterEvent, INFINITE, FALSE); - break; - } - } - - } - -WriteLockAcquired: - _ASSERTE ((m_dwFlag & READERS_MASK) == 0 && "reader count is nonzero after acquiring write lock"); - _ASSERTE ((m_dwFlag & WRITERS_MASK) == WRITERS_INCR && "writer count is not 1 after acquiring write lock"); - EE_LOCK_TAKEN(this); - - return S_OK; -} // UTSemReadWrite::LockWrite - - - -/****************************************************************************** -Function : UTSemReadWrite::UnlockRead - -Abstract: Release a shared lock -******************************************************************************/ -void UTSemReadWrite::UnlockRead() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - ULONG dwFlag; - - - _ASSERTE ((m_dwFlag & READERS_MASK) != 0 && "reader count is zero before releasing read lock"); - _ASSERTE ((m_dwFlag & WRITERS_MASK) == 0 && "writer count is nonzero before releasing read lock"); - - for (;;) - { - dwFlag = m_dwFlag; - - if (dwFlag == READERS_INCR) - { // we're the last reader, and nobody is waiting - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, (ULONG)0, dwFlag)) - { - break; - } - } - - else if ((dwFlag & READERS_MASK) > READERS_INCR) - { // we're not the last reader - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag - READERS_INCR, dwFlag)) - { - break; - } - } - - else - { - // here, there should be exactly 1 reader (us), and at least one waiting writer. - _ASSERTE ((dwFlag & READERS_MASK) == READERS_INCR && "UnlockRead consistency error 1"); - _ASSERTE ((dwFlag & WRITEWAITERS_MASK) != 0 && "UnlockRead consistency error 2"); - - // one or more writers is waiting, do one of them next - // (remove a reader (us), remove a write waiter, add a writer - if (dwFlag == - InterlockedCompareExchangeT( - &m_dwFlag, - dwFlag - READERS_INCR - WRITEWAITERS_INCR + WRITERS_INCR, - dwFlag)) - { - SetEvent(m_hWriteWaiterEvent); - break; - } - } - } - - DecCantStopCount(); - EE_LOCK_RELEASED(this); -} // UTSemReadWrite::UnlockRead - - -/****************************************************************************** -Function : UTSemReadWrite::UnlockWrite - -Abstract: Release an exclusive lock -******************************************************************************/ -void UTSemReadWrite::UnlockWrite() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - ULONG dwFlag; - ULONG count; - - _ASSERTE ((m_dwFlag & READERS_MASK) == 0 && "reader count is nonzero before releasing write lock"); - _ASSERTE ((m_dwFlag & WRITERS_MASK) == WRITERS_INCR && "writer count is not 1 before releasing write lock"); - - for (;;) - { - dwFlag = m_dwFlag; - - if (dwFlag == WRITERS_INCR) - { // nobody is waiting - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, (ULONG)0, dwFlag)) - { - break; - } - } - - else if ((dwFlag & READWAITERS_MASK) != 0) - { // one or more readers are waiting, do them all next - count = (dwFlag & READWAITERS_MASK) / READWAITERS_INCR; - // remove a writer (us), remove all read waiters, turn them into readers - if (dwFlag == - InterlockedCompareExchangeT( - &m_dwFlag, - dwFlag - WRITERS_INCR - count * READWAITERS_INCR + count * READERS_INCR, - dwFlag)) - { - ReleaseSemaphore(m_hReadWaiterSemaphore, count, NULL); - break; - } - } - - else - { // one or more writers is waiting, do one of them next - _ASSERTE ((dwFlag & WRITEWAITERS_MASK) != 0 && "UnlockWrite consistency error"); - // (remove a writer (us), remove a write waiter, add a writer - if (dwFlag == InterlockedCompareExchangeT (&m_dwFlag, dwFlag - WRITEWAITERS_INCR, dwFlag)) - { - SetEvent(m_hWriteWaiterEvent); - break; - } - } - } - - DecCantStopCount(); - EE_LOCK_RELEASED(this); -} // UTSemReadWrite::UnlockWrite - -#ifdef _DEBUG - -//======================================================================================= -BOOL -UTSemReadWrite::Debug_IsLockedForRead() -{ - return ((m_dwFlag & READERS_MASK) != 0); -} - -//======================================================================================= -BOOL -UTSemReadWrite::Debug_IsLockedForWrite() -{ - return ((m_dwFlag & WRITERS_MASK) != 0); -} - -#endif //_DEBUG - diff --git a/src/coreclr/vm/gccover.cpp b/src/coreclr/vm/gccover.cpp index 63f3440f5efbe8..3092d77359d81e 100644 --- a/src/coreclr/vm/gccover.cpp +++ b/src/coreclr/vm/gccover.cpp @@ -20,7 +20,6 @@ #pragma warning(disable:4663) #include "eeconfig.h" -#include "utsem.h" #include "gccover.h" #include "virtualcallstub.h" #include "threadsuspend.h" diff --git a/src/native/minipal/CMakeLists.txt b/src/native/minipal/CMakeLists.txt index 309495bc96e307..e853fcc1e9dc9e 100644 --- a/src/native/minipal/CMakeLists.txt +++ b/src/native/minipal/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES ospagesize.c guid.c random.c + rwlock.c debugger.c strings.c time.c diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index acf3892985996c..70b62aef39f9f8 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -1,6 +1,7 @@ include(CheckFunctionExists) include(CheckIncludeFiles) include(CheckLibraryExists) +include(CheckCSourceCompiles) include(CheckSymbolExists) check_include_files("windows.h;bcrypt.h" HAVE_BCRYPT_H) @@ -19,6 +20,14 @@ check_symbol_exists(getentropy "unistd.h" HAVE_GETENTROPY) check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC) check_symbol_exists(CLOCK_MONOTONIC_COARSE time.h HAVE_CLOCK_MONOTONIC_COARSE) check_symbol_exists(clock_gettime_nsec_np time.h HAVE_CLOCK_GETTIME_NSEC_NP) +check_c_source_compiles(" + #include + int main(void) + { + pthread_rwlockattr_t attributes; + return pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + }" + HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) if(CLR_CMAKE_HOST_UNIX) check_library_exists(pthread pthread_create "" HAVE_LIBPTHREAD) diff --git a/src/native/minipal/minipalconfig.h.in b/src/native/minipal/minipalconfig.h.in index de01c3ece7bfaf..84913a2975404e 100644 --- a/src/native/minipal/minipalconfig.h.in +++ b/src/native/minipal/minipalconfig.h.in @@ -17,5 +17,6 @@ #cmakedefine01 BIGENDIAN #cmakedefine01 HAVE_BCRYPT_H #cmakedefine01 HAVE_FSYNC +#cmakedefine01 HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP #endif diff --git a/src/native/minipal/rwlock.c b/src/native/minipal/rwlock.c new file mode 100644 index 00000000000000..964c420b190517 --- /dev/null +++ b/src/native/minipal/rwlock.c @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include "minipalconfig.h" +#include "rwlock.h" + +bool minipal_rwlock_init(minipal_rwlock* rwlock) +{ + assert(rwlock != NULL); +#ifdef HOST_WINDOWS + InitializeSRWLock(&rwlock->_impl); + return true; +#else +#if HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP + pthread_rwlockattr_t attributes; + int st = pthread_rwlockattr_init(&attributes); + if (st != 0) + return false; + + st = pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + if (st == 0) + st = pthread_rwlock_init(&rwlock->_impl, &attributes); + + pthread_rwlockattr_destroy(&attributes); + return st == 0; +#else + return pthread_rwlock_init(&rwlock->_impl, NULL) == 0; +#endif +#endif // HOST_WINDOWS +} + +void minipal_rwlock_destroy(minipal_rwlock* rwlock) +{ + assert(rwlock != NULL); +#ifndef HOST_WINDOWS + int st = pthread_rwlock_destroy(&rwlock->_impl); + assert(st == 0); + (void)st; +#endif // !HOST_WINDOWS +} + +bool minipal_rwlock_enter_read(minipal_rwlock* rwlock) +{ + assert(rwlock != NULL); +#ifdef HOST_WINDOWS + AcquireSRWLockShared(&rwlock->_impl); +#else + int st = pthread_rwlock_rdlock(&rwlock->_impl); + if (st != 0) + return false; +#endif // HOST_WINDOWS + return true; +} + +void minipal_rwlock_leave_read(minipal_rwlock* rwlock) +{ + assert(rwlock != NULL); +#ifdef HOST_WINDOWS + ReleaseSRWLockShared(&rwlock->_impl); +#else + int st = pthread_rwlock_unlock(&rwlock->_impl); + assert(st == 0); + (void)st; +#endif // HOST_WINDOWS +} + +bool minipal_rwlock_enter_write(minipal_rwlock* rwlock) +{ + assert(rwlock != NULL); +#ifdef HOST_WINDOWS + AcquireSRWLockExclusive(&rwlock->_impl); +#else + int st = pthread_rwlock_wrlock(&rwlock->_impl); + if (st != 0) + return false; +#endif // HOST_WINDOWS + return true; +} + +void minipal_rwlock_leave_write(minipal_rwlock* rwlock) +{ + assert(rwlock != NULL); +#ifdef HOST_WINDOWS + ReleaseSRWLockExclusive(&rwlock->_impl); +#else + int st = pthread_rwlock_unlock(&rwlock->_impl); + assert(st == 0); + (void)st; +#endif // HOST_WINDOWS +} diff --git a/src/native/minipal/rwlock.h b/src/native/minipal/rwlock.h new file mode 100644 index 00000000000000..b6abd0b6997506 --- /dev/null +++ b/src/native/minipal/rwlock.h @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef HAVE_MINIPAL_RWLOCK_H +#define HAVE_MINIPAL_RWLOCK_H + +#include + +#ifdef HOST_WINDOWS +#include +typedef SRWLOCK MINIPAL_RWLOCK_IMPL; +#else // !HOST_WINDOWS +#include +typedef pthread_rwlock_t MINIPAL_RWLOCK_IMPL; +#endif // HOST_WINDOWS + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +typedef struct _minipal_rwlock +{ + MINIPAL_RWLOCK_IMPL _impl; +} minipal_rwlock; + +// Initialize the read-write lock. +bool minipal_rwlock_init(minipal_rwlock* rwlock); + +// Destroy the read-write lock. +void minipal_rwlock_destroy(minipal_rwlock* rwlock); + +// Enter the read-write lock in shared mode. Blocks until the lock can be entered. +bool minipal_rwlock_enter_read(minipal_rwlock* rwlock); + +// Leave the read-write lock from shared mode. +void minipal_rwlock_leave_read(minipal_rwlock* rwlock); + +// Enter the read-write lock in exclusive mode. Blocks until the lock can be entered. +bool minipal_rwlock_enter_write(minipal_rwlock* rwlock); + +// Leave the read-write lock from exclusive mode. +void minipal_rwlock_leave_write(minipal_rwlock* rwlock); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // HAVE_MINIPAL_RWLOCK_H From d236622d68927fbc0c45668e440c4c6dbdaf61fb Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 21 Aug 2026 19:12:31 +0000 Subject: [PATCH 2/9] Address metadata lock review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/md/compiler/mdutil.cpp | 10 +++++----- src/coreclr/md/compiler/regmeta.cpp | 7 +++++-- src/coreclr/md/compiler/regmeta.h | 2 +- src/coreclr/md/enc/rwutil.cpp | 22 +++------------------- src/coreclr/md/inc/mdinternalrw.h | 2 +- src/coreclr/md/inc/rwutil.h | 12 ++++++------ src/native/minipal/configure.cmake | 7 ++++++- src/native/minipal/rwlock.c | 4 +--- 8 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/coreclr/md/compiler/mdutil.cpp b/src/coreclr/md/compiler/mdutil.cpp index ae79fca0369d43..d376c4a92df8ed 100644 --- a/src/coreclr/md/compiler/mdutil.cpp +++ b/src/coreclr/md/compiler/mdutil.cpp @@ -54,7 +54,7 @@ LOADEDMODULES::InitializeStatics() IfNullGo(pLoadedModules); { - CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(NULL)); IfFailGo(lockHolder.LockWrite()); if (VolatileLoad(&s_pLoadedModules) == NULL) @@ -80,7 +80,7 @@ HRESULT LOADEDMODULES::AddModuleToLoadedList(RegMeta * pRegMeta) IfFailGo(InitializeStatics()); { - CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(NULL)); IfFailGo(lockHolder.LockWrite()); ppRegMeta = s_pLoadedModules->Append(); @@ -113,7 +113,7 @@ BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta) IfFailGo(InitializeStatics()); { - CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(NULL)); IfFailGo(lockHolder.LockWrite()); // Search for this module in list of loaded modules. @@ -178,7 +178,7 @@ BOOL LOADEDMODULES::IsEntryInList( IfFailGo(InitializeStatics()); { - CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(NULL)); IfFailGo(lockHolder.LockRead()); // Loop through each loaded modules @@ -224,7 +224,7 @@ LOADEDMODULES::ResolveTypeRefWithLoadedModules( IfFailGo(InitializeStatics()); { - CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(nullptr)); + CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(NULL)); IfFailGo(lockHolder.LockRead()); // Get the Nesting hierarchy. diff --git a/src/coreclr/md/compiler/regmeta.cpp b/src/coreclr/md/compiler/regmeta.cpp index 4db11c23da9c8b..85038084f5a19e 100644 --- a/src/coreclr/md/compiler/regmeta.cpp +++ b/src/coreclr/md/compiler/regmeta.cpp @@ -345,8 +345,11 @@ HRESULT RegMeta::OpenExistingMD( if (IsThreadSafetyOn()) { - IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); - m_fOwnLock = true; + if (m_pReadWriteLock == NULL) + { + IfFailGo(CreateMDReadWriteLock(&m_pReadWriteLock)); + m_fOwnLock = true; + } INDEBUG(m_pStgdb->m_MiniMd.Debug_EnableLockCheck();) } diff --git a/src/coreclr/md/compiler/regmeta.h b/src/coreclr/md/compiler/regmeta.h index 274ff3c3544401..71d5597885acae 100644 --- a/src/coreclr/md/compiler/regmeta.h +++ b/src/coreclr/md/compiler/regmeta.h @@ -1305,7 +1305,7 @@ class RegMeta : { _ASSERTE(m_pReadWriteLock == NULL); m_pReadWriteLock = pLock; - INDEBUG(if (pLock != nullptr) { m_pStgdb->m_MiniMd.Debug_EnableLockCheck(); }) + INDEBUG(if (pLock != NULL) { m_pStgdb->m_MiniMd.Debug_EnableLockCheck(); }) return NOERROR; } STDMETHODIMP_(minipal_rwlock *) GetReaderWriterLock() { return m_pReadWriteLock; } diff --git a/src/coreclr/md/enc/rwutil.cpp b/src/coreclr/md/enc/rwutil.cpp index c2c569eb284b8b..560ccbc0933c7e 100644 --- a/src/coreclr/md/enc/rwutil.cpp +++ b/src/coreclr/md/enc/rwutil.cpp @@ -14,14 +14,6 @@ #include "contract.h" #include "../inc/mdlog.h" -#if !defined(SELF_NO_HOST) && !defined(DACCESS_COMPILE) && !defined(DBI_COMPILE) && defined(TARGET_X86) && !defined(TARGET_UNIX) -void IncCantStopCount(); -void DecCantStopCount(); -#else -#define IncCantStopCount() -#define DecCantStopCount() -#endif - HRESULT CreateMDReadWriteLock(minipal_rwlock **ppLock) { minipal_rwlock *pLock = new (nothrow) minipal_rwlock; @@ -56,11 +48,8 @@ HRESULT AcquireMDReadLock(minipal_rwlock *pLock) } CONTRACTL_END; - IncCantStopCount(); - if (!minipal_rwlock_enter_read(pLock)) { - DecCantStopCount(); return E_FAIL; } @@ -78,16 +67,13 @@ HRESULT AcquireMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniM } CONTRACTL_END; - IncCantStopCount(); - if (!minipal_rwlock_enter_write(pLock)) { - DecCantStopCount(); return E_FAIL; } #ifdef _DEBUG - if (pMiniMd != nullptr) + if (pMiniMd != NULL) { pMiniMd->Debug_SetIsLockedForWrite(true); } @@ -106,7 +92,6 @@ void ReleaseMDReadLock(minipal_rwlock *pLock) CONTRACTL_END; minipal_rwlock_leave_read(pLock); - DecCantStopCount(); EE_LOCK_RELEASED(pLock); } @@ -120,13 +105,12 @@ void ReleaseMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)) CONTRACTL_END; #ifdef _DEBUG - if (pMiniMd != nullptr) + if (pMiniMd != NULL) { pMiniMd->Debug_SetIsLockedForWrite(false); } #endif // _DEBUG minipal_rwlock_leave_write(pLock); - DecCantStopCount(); EE_LOCK_RELEASED(pLock); } @@ -1417,6 +1401,6 @@ void CMDReadWriteLock::Debug_DetachMiniMd(CMiniMdRW *pMiniMd) { m_pMiniMd->Debug_SetIsLockedForWrite(false); } - m_pMiniMd = nullptr; + m_pMiniMd = NULL; } #endif // _DEBUG diff --git a/src/coreclr/md/inc/mdinternalrw.h b/src/coreclr/md/inc/mdinternalrw.h index beaeec372a1eca..e50b04bc1e4310 100644 --- a/src/coreclr/md/inc/mdinternalrw.h +++ b/src/coreclr/md/inc/mdinternalrw.h @@ -705,7 +705,7 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon { _ASSERTE(m_pReadWriteLock == NULL); m_pReadWriteLock = pLock; - INDEBUG(if (pLock != nullptr) { m_pStgdb->m_MiniMd.Debug_EnableLockCheck(); }) + INDEBUG(if (pLock != NULL) { m_pStgdb->m_MiniMd.Debug_EnableLockCheck(); }) return NOERROR; } diff --git a/src/coreclr/md/inc/rwutil.h b/src/coreclr/md/inc/rwutil.h index 0290e85b5bcf23..e09aa19b11346d 100644 --- a/src/coreclr/md/inc/rwutil.h +++ b/src/coreclr/md/inc/rwutil.h @@ -335,19 +335,19 @@ class CMDReadWriteLock }; -#define LOCKREADIFFAILRET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ +#define LOCKREADIFFAILRET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : NULL));\ IfFailRet(lockHolder.LockRead()); -#define LOCKWRITEIFFAILRET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ +#define LOCKWRITEIFFAILRET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : NULL));\ IfFailRet(lockHolder.LockWrite()); -#define LOCKREADNORET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ +#define LOCKREADNORET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : NULL));\ hr = lockHolder.LockRead(); -#define LOCKWRITENORET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ +#define LOCKWRITENORET() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : NULL));\ hr = lockHolder.LockWrite(); -#define LOCKREAD() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ +#define LOCKREAD() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : NULL));\ IfFailGo(lockHolder.LockRead()); -#define LOCKWRITE() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : nullptr));\ +#define LOCKWRITE() CMDReadWriteLock lockHolder(m_pReadWriteLock COMMA_INDEBUG(m_pStgdb != NULL ? &m_pStgdb->m_MiniMd : NULL));\ IfFailGo(lockHolder.LockWrite()); #define UNLOCKWRITE() lockHolder.UnlockWrite(); diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index 70b62aef39f9f8..ae4d150980e65b 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -25,7 +25,12 @@ check_c_source_compiles(" int main(void) { pthread_rwlockattr_t attributes; - return pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + if (pthread_rwlockattr_init(&attributes) != 0) + return 1; + + int result = pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + pthread_rwlockattr_destroy(&attributes); + return result; }" HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) diff --git a/src/native/minipal/rwlock.c b/src/native/minipal/rwlock.c index 964c420b190517..5596b3f1858f01 100644 --- a/src/native/minipal/rwlock.c +++ b/src/native/minipal/rwlock.c @@ -11,8 +11,7 @@ bool minipal_rwlock_init(minipal_rwlock* rwlock) #ifdef HOST_WINDOWS InitializeSRWLock(&rwlock->_impl); return true; -#else -#if HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP +#elif HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP pthread_rwlockattr_t attributes; int st = pthread_rwlockattr_init(&attributes); if (st != 0) @@ -27,7 +26,6 @@ bool minipal_rwlock_init(minipal_rwlock* rwlock) #else return pthread_rwlock_init(&rwlock->_impl, NULL) == 0; #endif -#endif // HOST_WINDOWS } void minipal_rwlock_destroy(minipal_rwlock* rwlock) From 63d2806961d35829b7de1280c46ea6d5e0649c7e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 21 Aug 2026 22:35:08 +0000 Subject: [PATCH 3/9] Restore hostless Windows system info initialization Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/utilcode/util.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index f70b23b1fa5e49..23b50361e2d774 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -905,13 +905,33 @@ BOOL CPUGroupInfo::GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* } #endif // HOST_WINDOWS +#ifdef HOST_WINDOWS +#ifdef SELF_NO_HOST +static Volatile g_fInitializedGlobalSystemInfo = FALSE; +SYSTEM_INFO g_SystemInfo; + +static void InitializeGlobalSystemInfo() +{ + if (!g_fInitializedGlobalSystemInfo) + { + GetSystemInfo(&g_SystemInfo); + g_fInitializedGlobalSystemInfo = TRUE; + } +} +#else extern SYSTEM_INFO g_SystemInfo; +#endif // SELF_NO_HOST +#endif // HOST_WINDOWS int GetTotalProcessorCount() { LIMITED_METHOD_CONTRACT; #ifdef HOST_WINDOWS +#ifdef SELF_NO_HOST + InitializeGlobalSystemInfo(); +#endif // SELF_NO_HOST + if (CPUGroupInfo::CanEnableGCCPUGroups()) { return CPUGroupInfo::GetNumActiveProcessors(); From 87a8e2ea65a6fa7aa077301d7175d69b46df046b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 24 Aug 2026 16:56:36 +0000 Subject: [PATCH 4/9] Fix minipal pthread feature probe linking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/configure.cmake | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index ae4d150980e65b..6edfc4267c0dc6 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -20,20 +20,6 @@ check_symbol_exists(getentropy "unistd.h" HAVE_GETENTROPY) check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC) check_symbol_exists(CLOCK_MONOTONIC_COARSE time.h HAVE_CLOCK_MONOTONIC_COARSE) check_symbol_exists(clock_gettime_nsec_np time.h HAVE_CLOCK_GETTIME_NSEC_NP) -check_c_source_compiles(" - #include - int main(void) - { - pthread_rwlockattr_t attributes; - if (pthread_rwlockattr_init(&attributes) != 0) - return 1; - - int result = pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); - pthread_rwlockattr_destroy(&attributes); - return result; - }" - HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) - if(CLR_CMAKE_HOST_UNIX) check_library_exists(pthread pthread_create "" HAVE_LIBPTHREAD) check_library_exists(c pthread_create "" HAVE_PTHREAD_IN_LIBC) @@ -43,6 +29,23 @@ if(CLR_CMAKE_HOST_UNIX) set(PTHREAD_LIBRARY c) endif() if(PTHREAD_LIBRARY) + set(PREVIOUS_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${PTHREAD_LIBRARY}) + check_c_source_compiles(" + #include + int main(void) + { + pthread_rwlockattr_t attributes; + if (pthread_rwlockattr_init(&attributes) != 0) + return 1; + + int result = pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + pthread_rwlockattr_destroy(&attributes); + return result; + }" + HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + set(CMAKE_REQUIRED_LIBRARIES ${PREVIOUS_CMAKE_REQUIRED_LIBRARIES}) + check_library_exists(${PTHREAD_LIBRARY} pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK) endif() endif() From 0632cb48532cdbbcec502f5fe61bf22c361a215a Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 24 Aug 2026 12:00:00 -0700 Subject: [PATCH 5/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/utilcode/util.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 23b50361e2d774..4cc39e6a658f11 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -907,16 +907,18 @@ BOOL CPUGroupInfo::GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* #ifdef HOST_WINDOWS #ifdef SELF_NO_HOST -static Volatile g_fInitializedGlobalSystemInfo = FALSE; +static INIT_ONCE g_globalSystemInfoInitOnce = INIT_ONCE_STATIC_INIT; SYSTEM_INFO g_SystemInfo; +static BOOL CALLBACK InitializeGlobalSystemInfoOnce(PINIT_ONCE /*initOnce*/, PVOID /*parameter*/, PVOID* /*context*/) +{ + GetSystemInfo(&g_SystemInfo); + return TRUE; +} + static void InitializeGlobalSystemInfo() { - if (!g_fInitializedGlobalSystemInfo) - { - GetSystemInfo(&g_SystemInfo); - g_fInitializedGlobalSystemInfo = TRUE; - } + InitOnceExecuteOnce(&g_globalSystemInfoInitOnce, InitializeGlobalSystemInfoOnce, NULL, NULL); } #else extern SYSTEM_INFO g_SystemInfo; From 354cafa17d1ce3d2a2c4c4b00a01efc5d8a537ab Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 25 Aug 2026 20:26:25 +0000 Subject: [PATCH 6/9] Implement feedback --- src/coreclr/md/compiler/regmeta.cpp | 2 +- src/coreclr/md/enc/rwutil.cpp | 18 ++++++++++++++++-- src/coreclr/md/inc/rwutil.h | 2 +- src/coreclr/utilcode/util.cpp | 6 ++---- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/coreclr/md/compiler/regmeta.cpp b/src/coreclr/md/compiler/regmeta.cpp index 85038084f5a19e..f4f55457db25b0 100644 --- a/src/coreclr/md/compiler/regmeta.cpp +++ b/src/coreclr/md/compiler/regmeta.cpp @@ -1333,7 +1333,7 @@ HRESULT RegMeta::ReOpenWithMemory( // of the APIs were ever called then we can safely delete. CLiteWeightStgdbRW* pStgdb = m_pStgdbFreeList; m_pStgdbFreeList = m_pStgdbFreeList->m_pNextStgdb; - INDEBUG(lockHolder.Debug_DetachMiniMd(&pStgdb->m_MiniMd);) + INDEBUG(lockHolder.Debug_DetachMiniMd();) delete pStgdb; } diff --git a/src/coreclr/md/enc/rwutil.cpp b/src/coreclr/md/enc/rwutil.cpp index 560ccbc0933c7e..b531e295c6b88c 100644 --- a/src/coreclr/md/enc/rwutil.cpp +++ b/src/coreclr/md/enc/rwutil.cpp @@ -16,6 +16,13 @@ HRESULT CreateMDReadWriteLock(minipal_rwlock **ppLock) { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + minipal_rwlock *pLock = new (nothrow) minipal_rwlock; IfNullRet(pLock); @@ -31,6 +38,13 @@ HRESULT CreateMDReadWriteLock(minipal_rwlock **ppLock) void DestroyMDReadWriteLock(minipal_rwlock *pLock) { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + if (pLock != NULL) { minipal_rwlock_destroy(pLock); @@ -1392,10 +1406,10 @@ void CMDReadWriteLock::UnlockWrite() } // CMDReadWriteLock::UnlockWrite #ifdef _DEBUG -void CMDReadWriteLock::Debug_DetachMiniMd(CMiniMdRW *pMiniMd) +void CMDReadWriteLock::Debug_DetachMiniMd() { _ASSERTE(m_fLockedForWrite); - _ASSERTE(m_pMiniMd == pMiniMd); + _ASSERTE(m_pMiniMd != NULL); if (m_pLock != NULL) { diff --git a/src/coreclr/md/inc/rwutil.h b/src/coreclr/md/inc/rwutil.h index e09aa19b11346d..27c956b9e1a13f 100644 --- a/src/coreclr/md/inc/rwutil.h +++ b/src/coreclr/md/inc/rwutil.h @@ -325,7 +325,7 @@ class CMDReadWriteLock void UnlockWrite(); HRESULT ConvertReadLockToWriteLock(); #ifdef _DEBUG - void Debug_DetachMiniMd(CMiniMdRW *pMiniMd); + void Debug_DetachMiniMd(); #endif // _DEBUG private: bool m_fLockedForRead; diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp index 4cc39e6a658f11..85436887a7b006 100644 --- a/src/coreclr/utilcode/util.cpp +++ b/src/coreclr/utilcode/util.cpp @@ -905,8 +905,7 @@ BOOL CPUGroupInfo::GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* } #endif // HOST_WINDOWS -#ifdef HOST_WINDOWS -#ifdef SELF_NO_HOST +#if defined(HOST_WINDOWS) && defined(SELF_NO_HOST) static INIT_ONCE g_globalSystemInfoInitOnce = INIT_ONCE_STATIC_INIT; SYSTEM_INFO g_SystemInfo; @@ -922,8 +921,7 @@ static void InitializeGlobalSystemInfo() } #else extern SYSTEM_INFO g_SystemInfo; -#endif // SELF_NO_HOST -#endif // HOST_WINDOWS +#endif // SELF_NO_HOST && HOST_WINDOWS int GetTotalProcessorCount() { From a6f80f1c753a383cdfb54b66c5993958bb87835e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 26 Aug 2026 20:03:22 +0000 Subject: [PATCH 7/9] Address remaining lock review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/md/compiler/mdutil.cpp | 1 - src/coreclr/md/enc/mdinternalrw.cpp | 2 +- src/coreclr/md/enc/rwutil.cpp | 4 ++-- src/native/minipal/rwlock.c | 17 ++++++++++------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/coreclr/md/compiler/mdutil.cpp b/src/coreclr/md/compiler/mdutil.cpp index d376c4a92df8ed..e7098f12bd9e4a 100644 --- a/src/coreclr/md/compiler/mdutil.cpp +++ b/src/coreclr/md/compiler/mdutil.cpp @@ -243,7 +243,6 @@ LOADEDMODULES::ResolveTypeRefWithLoadedModules( { // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller. // The read-write lock may block a recursive read acquisition while a writer is waiting. - // Avoid taking the TypeRef RegMeta lock again because the caller already holds it for reading. CMDReadWriteLock regMetaLock( (pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock() COMMA_INDEBUG(pRegMeta->GetMiniMd())); diff --git a/src/coreclr/md/enc/mdinternalrw.cpp b/src/coreclr/md/enc/mdinternalrw.cpp index 2cd527da1fdc9c..450c7f18c9dde3 100644 --- a/src/coreclr/md/enc/mdinternalrw.cpp +++ b/src/coreclr/md/enc/mdinternalrw.cpp @@ -263,10 +263,10 @@ STDAPI GetMDPublicInterfaceFromInternal( // grab the write lock when we are creating the corresponding regmeta for the public interface _ASSERTE( pInternalImport->GetReaderWriterLock() != NULL ); - isLockedForWrite = true; IfFailGo(AcquireMDWriteLock( pInternalImport->GetReaderWriterLock() COMMA_INDEBUG(static_cast(pInternalImport->GetMetaModelCommon())))); + isLockedForWrite = true; // check again. Maybe someone else beat us to setting the public interface while we are waiting // for the write lock. Don't need to grab the read lock since we already have the write lock. diff --git a/src/coreclr/md/enc/rwutil.cpp b/src/coreclr/md/enc/rwutil.cpp index b531e295c6b88c..ad0df400c00594 100644 --- a/src/coreclr/md/enc/rwutil.cpp +++ b/src/coreclr/md/enc/rwutil.cpp @@ -1305,7 +1305,7 @@ CMDReadWriteLock::~CMDReadWriteLock() //********************************************************************************************************* // -// Used to obtain the write lock +// Used to obtain the read lock // //********************************************************************************************************* HRESULT CMDReadWriteLock::LockRead() @@ -1329,7 +1329,7 @@ HRESULT CMDReadWriteLock::LockRead() //********************************************************************************************************* // -// Used to obtain the read lock +// Used to obtain the write lock // //********************************************************************************************************* HRESULT CMDReadWriteLock::LockWrite() diff --git a/src/native/minipal/rwlock.c b/src/native/minipal/rwlock.c index 5596b3f1858f01..79b3fc02da00d4 100644 --- a/src/native/minipal/rwlock.c +++ b/src/native/minipal/rwlock.c @@ -14,15 +14,18 @@ bool minipal_rwlock_init(minipal_rwlock* rwlock) #elif HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP pthread_rwlockattr_t attributes; int st = pthread_rwlockattr_init(&attributes); - if (st != 0) - return false; - - st = pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); if (st == 0) - st = pthread_rwlock_init(&rwlock->_impl, &attributes); + { + st = pthread_rwlockattr_setkind_np(&attributes, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + if (st == 0) + st = pthread_rwlock_init(&rwlock->_impl, &attributes); - pthread_rwlockattr_destroy(&attributes); - return st == 0; + pthread_rwlockattr_destroy(&attributes); + if (st == 0) + return true; + } + + return pthread_rwlock_init(&rwlock->_impl, NULL) == 0; #else return pthread_rwlock_init(&rwlock->_impl, NULL) == 0; #endif From a4f7036a7b8f3ed05439654eff49646daa318b10 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 26 Aug 2026 22:41:33 +0000 Subject: [PATCH 8/9] Restore metadata CantStopCount tracking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/inc/clrhost.h | 32 ++++++++++++++++++++++++++++++++ src/coreclr/md/enc/rwutil.cpp | 26 ++++++++++++++++++++++++++ src/coreclr/vm/util.hpp | 32 -------------------------------- 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/coreclr/inc/clrhost.h b/src/coreclr/inc/clrhost.h index bfbb97e0a49c4c..e2eb8f04923ade 100644 --- a/src/coreclr/inc/clrhost.h +++ b/src/coreclr/inc/clrhost.h @@ -148,4 +148,36 @@ inline BOOL IsInCantAllocStressLogRegion() return t_CantAllocCount != 0; } +extern thread_local size_t t_CantStopCount; + +// For debugging, we can track arbitrary Can't-Stop regions. +// In V1.0, this was on the Thread object, but we need to track this for threads w/o a Thread object. +FORCEINLINE void IncCantStopCount() +{ + t_CantStopCount++; +} + +FORCEINLINE void DecCantStopCount() +{ + t_CantStopCount--; +} + +typedef StateHolder CantStopHolder; + +#ifdef _DEBUG +// For debug-only, this can be used w/ a holder to ensure that we're keeping our CS count balanced. +// We should never use this w/ control flow. +inline size_t GetCantStopCount() +{ + return t_CantStopCount; +} + +// At places where we know we're calling out to native code, we can assert that we're NOT in a CS region. +// This is _debug only since we only use it for asserts; not for real code-flow control in a retail build. +inline bool IsInCantStopRegion() +{ + return (GetCantStopCount() > 0); +} +#endif // _DEBUG + #endif diff --git a/src/coreclr/md/enc/rwutil.cpp b/src/coreclr/md/enc/rwutil.cpp index ad0df400c00594..20bdb830c91fbb 100644 --- a/src/coreclr/md/enc/rwutil.cpp +++ b/src/coreclr/md/enc/rwutil.cpp @@ -14,6 +14,10 @@ #include "contract.h" #include "../inc/mdlog.h" +#if defined(FEATURE_METADATA_IN_VM) && !defined(SELF_NO_HOST) && defined(TARGET_X86) && defined(TARGET_WINDOWS) +#define TRACK_METADATA_CANT_STOP_COUNT +#endif + HRESULT CreateMDReadWriteLock(minipal_rwlock **ppLock) { CONTRACTL @@ -62,8 +66,15 @@ HRESULT AcquireMDReadLock(minipal_rwlock *pLock) } CONTRACTL_END; +#ifdef TRACK_METADATA_CANT_STOP_COUNT + IncCantStopCount(); +#endif + if (!minipal_rwlock_enter_read(pLock)) { +#ifdef TRACK_METADATA_CANT_STOP_COUNT + DecCantStopCount(); +#endif return E_FAIL; } @@ -81,8 +92,15 @@ HRESULT AcquireMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniM } CONTRACTL_END; +#ifdef TRACK_METADATA_CANT_STOP_COUNT + IncCantStopCount(); +#endif + if (!minipal_rwlock_enter_write(pLock)) { +#ifdef TRACK_METADATA_CANT_STOP_COUNT + DecCantStopCount(); +#endif return E_FAIL; } @@ -106,6 +124,9 @@ void ReleaseMDReadLock(minipal_rwlock *pLock) CONTRACTL_END; minipal_rwlock_leave_read(pLock); +#ifdef TRACK_METADATA_CANT_STOP_COUNT + DecCantStopCount(); +#endif EE_LOCK_RELEASED(pLock); } @@ -125,9 +146,14 @@ void ReleaseMDWriteLock(minipal_rwlock *pLock COMMA_INDEBUG(CMiniMdRW *pMiniMd)) } #endif // _DEBUG minipal_rwlock_leave_write(pLock); +#ifdef TRACK_METADATA_CANT_STOP_COUNT + DecCantStopCount(); +#endif EE_LOCK_RELEASED(pLock); } +#undef TRACK_METADATA_CANT_STOP_COUNT + //***************************************************************************** // Helper methods //***************************************************************************** diff --git a/src/coreclr/vm/util.hpp b/src/coreclr/vm/util.hpp index bc2367dc627cfb..c01a9075b62259 100644 --- a/src/coreclr/vm/util.hpp +++ b/src/coreclr/vm/util.hpp @@ -495,38 +495,6 @@ struct NativeLibraryHandleTraits final using NativeLibraryHandleHolder = LifetimeHolder; -extern thread_local size_t t_CantStopCount; - -// For debugging, we can track arbitrary Can't-Stop regions. -// In V1.0, this was on the Thread object, but we need to track this for threads w/o a Thread object. -FORCEINLINE void IncCantStopCount() -{ - t_CantStopCount++; -} - -FORCEINLINE void DecCantStopCount() -{ - t_CantStopCount--; -} - -typedef StateHolder CantStopHolder; - -#ifdef _DEBUG -// For debug-only, this can be used w/ a holder to ensure that we're keeping our CS count balanced. -// We should never use this w/ control flow. -inline size_t GetCantStopCount() -{ - return t_CantStopCount; -} - -// At places where we know we're calling out to native code, we can assert that we're NOT in a CS region. -// This is _debug only since we only use it for asserts; not for real code-flow control in a retail build. -inline bool IsInCantStopRegion() -{ - return (GetCantStopCount() > 0); -} -#endif // _DEBUG - BOOL IsValidMethodCodeNotification(ULONG32 Notification); // Number of usable JIT notification entries. The allocated table has From bebfa0d073518ab86a332b599baf5b19efd5a0cf Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 28 Aug 2026 23:40:24 +0000 Subject: [PATCH 9/9] Fix pthread rwlock feature macro detection Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/minipal/configure.cmake | 3 +++ src/native/minipal/rwlock.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/native/minipal/configure.cmake b/src/native/minipal/configure.cmake index 6edfc4267c0dc6..8c9ed6e464a652 100644 --- a/src/native/minipal/configure.cmake +++ b/src/native/minipal/configure.cmake @@ -32,6 +32,9 @@ if(CLR_CMAKE_HOST_UNIX) set(PREVIOUS_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) list(APPEND CMAKE_REQUIRED_LIBRARIES ${PTHREAD_LIBRARY}) check_c_source_compiles(" + #if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE + #endif #include int main(void) { diff --git a/src/native/minipal/rwlock.c b/src/native/minipal/rwlock.c index 79b3fc02da00d4..35f2156eda4016 100644 --- a/src/native/minipal/rwlock.c +++ b/src/native/minipal/rwlock.c @@ -1,6 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if defined(__linux__) && !defined(_GNU_SOURCE) +// glibc hides pthread_rwlockattr_setkind_np in strict standards modes. +#define _GNU_SOURCE +#endif + #include #include "minipalconfig.h" #include "rwlock.h"