From 50a1b5f4fb1633b393158ebd5077009db388ea69 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Sat, 29 Aug 2026 18:52:24 +0000 Subject: [PATCH] Replace CoreCLR PAL wait subsystem Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/di/process.cpp | 117 +- src/coreclr/debug/di/rspriv.h | 2 + src/coreclr/debug/di/shimprocess.cpp | 21 +- src/coreclr/debug/ee/canary.cpp | 60 +- src/coreclr/debug/ee/canary.h | 6 +- src/coreclr/debug/ee/debugger.cpp | 75 +- src/coreclr/debug/ee/debugger.h | 2 +- src/coreclr/debug/ee/rcthread.cpp | 36 +- .../debug/shared/dbgtransportsession.cpp | 5 +- .../dlls/mscordac/mscordac_unixexports.src | 10 - src/coreclr/gc/CMakeLists.txt | 3 +- src/coreclr/gc/sample/CMakeLists.txt | 1 + src/coreclr/gc/windows/gcenv.windows.cpp | 3 +- src/coreclr/inc/clrhost.h | 2 - src/coreclr/minipal/Unix/CMakeLists.txt | 2 + src/coreclr/minipal/Windows/CMakeLists.txt | 1 + src/coreclr/nativeaot/Runtime/CMakeLists.txt | 3 + .../nativeaot/Runtime/FinalizerHelpers.cpp | 13 +- src/coreclr/nativeaot/Runtime/Pal.h | 10 +- src/coreclr/nativeaot/Runtime/event.cpp | 32 +- .../nativeaot/Runtime/eventpipe/ep-rt-aot.cpp | 2 +- .../nativeaot/Runtime/eventpipe/ep-rt-aot.h | 2 +- src/coreclr/nativeaot/Runtime/thread.cpp | 2 +- .../nativeaot/Runtime/unix/PalUnix.cpp | 314 ---- .../nativeaot/Runtime/windows/PalMinWin.cpp | 32 +- src/coreclr/pal/inc/pal.h | 89 - src/coreclr/pal/src/CMakeLists.txt | 4 - src/coreclr/pal/src/file/file.cpp | 5 +- src/coreclr/pal/src/include/pal/corunix.hpp | 403 +--- src/coreclr/pal/src/include/pal/event.hpp | 59 - .../pal/src/include/pal/synchcache.hpp | 392 ---- .../pal/src/include/pal/synchobjects.hpp | 168 -- src/coreclr/pal/src/include/pal/thread.hpp | 52 +- src/coreclr/pal/src/init/pal.cpp | 18 - src/coreclr/pal/src/map/map.cpp | 5 +- src/coreclr/pal/src/objmgr/listedobject.cpp | 299 --- src/coreclr/pal/src/objmgr/listedobject.hpp | 76 - .../pal/src/objmgr/listedobjectmanager.cpp | 126 +- .../pal/src/objmgr/listedobjectmanager.hpp | 10 - .../pal/src/synchmgr/synchcontrollers.cpp | 1084 ----------- src/coreclr/pal/src/synchmgr/synchmanager.cpp | 1642 ----------------- src/coreclr/pal/src/synchmgr/synchmanager.hpp | 675 ------- src/coreclr/pal/src/synchmgr/wait.cpp | 520 ------ src/coreclr/pal/src/synchobj/event.cpp | 463 ----- src/coreclr/pal/src/thread/thread.cpp | 52 +- src/coreclr/pal/src/thread/threadsusp.cpp | 29 +- src/coreclr/pal/tests/palsuite/CMakeLists.txt | 20 +- .../pal/tests/palsuite/common/palsuite.h | 16 + .../pal/tests/palsuite/compilableTests.txt | 18 +- .../InterlockedCompareExchange/test2/test.cpp | 16 +- .../test2/test.cpp | 11 +- .../InterlockedDecrement/test2/test.cpp | 11 +- .../InterlockedDecrement64/test2/test.cpp | 12 +- .../InterlockedIncrement/test2/test.cpp | 10 +- .../InterlockedIncrement64/test2/test.cpp | 11 +- .../pal/tests/palsuite/paltestlist.txt | 13 +- .../palsuite/paltestlist_to_be_reviewed.txt | 9 - .../threading/CreateThread/test1/test1.cpp | 34 +- .../threading/CreateThread/test2/test2.cpp | 19 +- .../threading/CreateThread/test3/test3.cpp | 44 +- .../DisableThreadLibraryCalls/test1/test1.cpp | 146 -- .../DisableThreadLibraryCalls/test2/test2.cpp | 236 --- .../threading/DuplicateHandle/test2/test2.cpp | 95 - .../threading/DuplicateHandle/test3/test3.cpp | 122 -- .../threading/DuplicateHandle/test7/test7.cpp | 47 +- .../threading/DuplicateHandle/test8/test8.cpp | 14 +- .../threading/ExitThread/test1/test1.cpp | 31 +- .../threading/ExitThread/test3/test3.cpp | 161 -- .../GetCurrentThread/test2/test2.cpp | 14 +- .../GetCurrentThreadId/test1/threadId.cpp | 8 +- .../threading/OpenEventW/test1/test1.cpp | 133 -- .../threading/OpenEventW/test2/test2.cpp | 193 -- .../threading/OpenEventW/test5/test5.cpp | 195 -- .../QueryThreadCycleTime/test1/test1.cpp | 2 +- .../threading/ResetEvent/test1/test1.cpp | 98 - .../threading/ResetEvent/test2/test2.cpp | 88 - .../threading/ResetEvent/test3/test3.cpp | 85 - .../threading/ResetEvent/test4/test4.cpp | 160 -- .../threading/ResumeThread/test1/test1.cpp | 61 +- .../threading/RuntimeEvent/test1/test1.cpp | 95 + .../threading/SetEvent/test1/test1.cpp | 93 - .../threading/SetEvent/test2/test2.cpp | 124 -- .../threading/SetEvent/test3/test3.cpp | 84 - .../threading/SetEvent/test4/test4.cpp | 160 -- .../palsuite/threading/Sleep/test1/Sleep.cpp | 2 +- .../palsuite/threading/Sleep/test2/sleep.cpp | 2 +- .../threading/SleepEx/test1/test1.cpp | 82 - .../threading/SwitchToThread/test1/test1.cpp | 14 +- .../WaitForMultipleObjectsEx/test1/test1.cpp | 225 --- .../WFSOThreadTest/WFSOThreadTest.cpp | 161 -- .../WaitForSingleObject/test1/test1.cpp | 120 -- .../threading/YieldProcessor/test1/test1.cpp | 14 +- src/coreclr/runtime/RuntimeEvent.h | 23 + src/coreclr/runtime/unix/RuntimeEvent.cpp | 338 ++++ src/coreclr/runtime/windows/RuntimeEvent.cpp | 45 + src/coreclr/utilcode/hostimpl.cpp | 5 - src/coreclr/utilcode/stresslog.cpp | 4 +- src/coreclr/vm/assembly.cpp | 3 +- src/coreclr/vm/ceemain.cpp | 6 +- src/coreclr/vm/common.h | 1 - src/coreclr/vm/eepolicy.cpp | 26 +- .../vm/eventing/eventpipe/ep-rt-coreclr.h | 3 +- src/coreclr/vm/finalizerthread.cpp | 5 +- src/coreclr/vm/hosting.cpp | 11 +- src/coreclr/vm/multicorejit.cpp | 3 +- src/coreclr/vm/profdetach.cpp | 3 +- src/coreclr/vm/rejit.cpp | 3 +- src/coreclr/vm/synch.cpp | 17 +- src/coreclr/vm/threads.cpp | 32 +- src/coreclr/vm/threads.h | 17 + src/coreclr/vm/threadsuspend.cpp | 5 +- src/coreclr/vm/tieredcompilation.cpp | 7 +- src/native/minipal/time.c | 2 +- 113 files changed, 1015 insertions(+), 9780 deletions(-) delete mode 100644 src/coreclr/pal/src/include/pal/event.hpp delete mode 100644 src/coreclr/pal/src/include/pal/synchcache.hpp delete mode 100644 src/coreclr/pal/src/include/pal/synchobjects.hpp delete mode 100644 src/coreclr/pal/src/synchmgr/synchcontrollers.cpp delete mode 100644 src/coreclr/pal/src/synchmgr/synchmanager.cpp delete mode 100644 src/coreclr/pal/src/synchmgr/synchmanager.hpp delete mode 100644 src/coreclr/pal/src/synchmgr/wait.cpp delete mode 100644 src/coreclr/pal/src/synchobj/event.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/ExitThread/test3/test3.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/OpenEventW/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/OpenEventW/test2/test2.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/OpenEventW/test5/test5.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/ResetEvent/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/ResetEvent/test2/test2.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/ResetEvent/test3/test3.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/ResetEvent/test4/test4.cpp create mode 100644 src/coreclr/pal/tests/palsuite/threading/RuntimeEvent/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/SetEvent/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/SetEvent/test2/test2.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/SetEvent/test3/test3.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/SetEvent/test4/test4.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/SleepEx/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.cpp delete mode 100644 src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.cpp create mode 100644 src/coreclr/runtime/RuntimeEvent.h create mode 100644 src/coreclr/runtime/unix/RuntimeEvent.cpp create mode 100644 src/coreclr/runtime/windows/RuntimeEvent.cpp diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 21ddf8b5f37383..ade9953a2e46ad 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -7,6 +7,7 @@ //***************************************************************************** #include "stdafx.h" +#include "RuntimeEvent.h" #include "primitives.h" #include "safewrap.h" @@ -270,7 +271,7 @@ inline DWORD SafeWaitForSingleObject(CordbProcess * p, HANDLE h, DWORD dwTimeout // Can't hold process lock while blocking _ASSERTE(!p->ThreadHoldsProcessLock()); - return ::WaitForSingleObject(h, dwTimeout); + return PAL_WaitForMultipleObjectsEx(1, &h, false, dwTimeout, false); } #define CORDB_WAIT_TIMEOUT 360000 // milliseconds @@ -1278,7 +1279,7 @@ void CordbProcess::CloseIPCHandles() if (m_leftSideEventRead != NULL) { - CloseHandle(m_leftSideEventRead); + PAL_CloseEvent(m_leftSideEventRead); m_leftSideEventRead = NULL; } @@ -1291,21 +1292,21 @@ void CordbProcess::CloseIPCHandles() #if defined(FEATURE_INTEROP_DEBUGGING) if (m_leftSideUnmanagedWaitEvent != NULL) { - CloseHandle(m_leftSideUnmanagedWaitEvent); + PAL_CloseEvent(m_leftSideUnmanagedWaitEvent); m_leftSideUnmanagedWaitEvent = NULL; } #endif // FEATURE_INTEROP_DEBUGGING if (m_stopWaitEvent != NULL) { - CloseHandle(m_stopWaitEvent); + PAL_CloseEvent(m_stopWaitEvent); m_stopWaitEvent = NULL; } #ifdef OUT_OF_PROCESS_SETTHREADCONTEXT if (m_detachSetThreadContextNeededEvent != NULL) { - CloseHandle(m_detachSetThreadContextNeededEvent); + PAL_CloseEvent(m_detachSetThreadContextNeededEvent); m_detachSetThreadContextNeededEvent = NULL; } #endif @@ -1628,23 +1629,23 @@ HRESULT CordbProcess::Init() ThrowOutOfMemory(); } - m_leftSideEventRead = CreateEvent(NULL, FALSE, FALSE, NULL); + m_leftSideEventRead = PAL_CreateEvent(NULL, false, false); if (m_leftSideEventRead == NULL) { - ThrowLastError(); + ThrowOutOfMemory(); } - m_stopWaitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + m_stopWaitEvent = PAL_CreateEvent(NULL, true, false); if (m_stopWaitEvent == NULL) { - ThrowLastError(); + ThrowOutOfMemory(); } #ifdef OUT_OF_PROCESS_SETTHREADCONTEXT - m_detachSetThreadContextNeededEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + m_detachSetThreadContextNeededEvent = PAL_CreateEvent(NULL, false, false); if (m_detachSetThreadContextNeededEvent == NULL) { - ThrowLastError(); + ThrowOutOfMemory(); } #endif @@ -1776,9 +1777,9 @@ void CordbProcess::Terminating(BOOL fDetach) // Set events that may be blocking stuff. // But don't set RSER unless we actually read the event. We don't block on RSER // since that wait also checks the leftside's process handle. - SetEvent(m_leftSideEventRead); + PAL_SetEvent(m_leftSideEventRead); m_leftSideEventAvailable->Set(); - SetEvent(m_stopWaitEvent); + PAL_SetEvent(m_stopWaitEvent); if (m_pShim != NULL) m_pShim->SetTerminatingEvent(); @@ -3760,7 +3761,7 @@ HRESULT CordbProcess::ContinueInternal(BOOL fIsOutOfBand) } // We're no longer stopped, so reset the m_stopWaitEvent. - ResetEvent(m_stopWaitEvent); + PAL_ResetEvent(m_stopWaitEvent); // If we're continuing from an uninitialized stop, then we don't need to do much at all. No event need be sent to // the Left Side (duh, it isn't even there yet.) We just need to get the RC Event Thread to start listening to the @@ -4110,7 +4111,7 @@ HRESULT CordbProcess::ContinueInternal(BOOL fIsOutOfBand) if ((dwRace & 1) == 1) { - Sleep(30); + PAL_Sleep(30); } } #endif @@ -7275,7 +7276,7 @@ void CordbProcess::ResumeHijackedThreads() // we let the hijacks run free. if (this->m_leftSideUnmanagedWaitEvent != NULL) { - SetEvent(this->m_leftSideUnmanagedWaitEvent); + PAL_SetEvent(this->m_leftSideUnmanagedWaitEvent); } else { @@ -8742,6 +8743,7 @@ CordbRCEventThread::CordbRCEventThread(Cordb* cordb) m_threadId = 0; m_run = TRUE; m_threadControlEvent = NULL; + m_threadExitedEvent = NULL; m_processStateChanged = FALSE; g_pRSDebuggingInfo->m_RCET = this; @@ -8758,6 +8760,9 @@ CordbRCEventThread::~CordbRCEventThread() if (m_threadControlEvent != NULL) delete m_threadControlEvent; + if (m_threadExitedEvent != NULL) + delete m_threadExitedEvent; + if (m_thread != NULL) CloseHandle(m_thread); @@ -8781,6 +8786,16 @@ HRESULT CordbRCEventThread::Init() return E_OUTOFMEMORY; } + m_threadExitedEvent = new (nothrow) WaitLatch(); + if ((m_threadExitedEvent == nullptr) || !m_threadExitedEvent->IsValid()) + { + delete m_threadExitedEvent; + m_threadExitedEvent = nullptr; + delete m_threadControlEvent; + m_threadControlEvent = nullptr; + return E_OUTOFMEMORY; + } + return S_OK; } @@ -9920,6 +9935,7 @@ DWORD WINAPI CordbRCEventThread::ThreadProc(LPVOID parameter) INTERNAL_THREAD_ENTRY(pThread); pThread->ThreadProc(); + pThread->m_threadExitedEvent->Set(); return 0; } @@ -10085,7 +10101,7 @@ HRESULT CordbRCEventThread::WaitForIPCEventFromProcess(CordbProcess * pProcess, } EX_CATCH_HRESULT(hr) - SetEvent(pProcess->m_leftSideEventRead); + PAL_SetEvent(pProcess->m_leftSideEventRead); return hr; } @@ -10162,9 +10178,10 @@ HRESULT CordbRCEventThread::Stop() m_threadControlEvent->Set(); - DWORD ret = WaitForSingleObject(m_thread, INFINITE); + const WaitHandle *waitSet[] = { m_threadExitedEvent }; + int32_t ret = WaitHandle::Wait(waitSet, ARRAY_SIZE(waitSet), INFINITE); - if (ret != WAIT_OBJECT_0) + if (ret != 0) { return HRESULT_FROM_GetLastError(); } @@ -10205,7 +10222,7 @@ CordbWin32EventThread::CordbWin32EventThread( Cordb * pCordb, ShimProcess * pShim ) : - m_thread(NULL), m_threadControlEvent(NULL), + m_thread(NULL), m_threadControlEvent(NULL), m_threadExitedEvent(NULL), m_actionTakenEvent(NULL), m_run(TRUE), m_action(W32ETA_NONE) { @@ -10231,8 +10248,11 @@ CordbWin32EventThread::~CordbWin32EventThread() if (m_threadControlEvent != NULL) delete m_threadControlEvent; + if (m_threadExitedEvent != NULL) + delete m_threadExitedEvent; + if (m_actionTakenEvent != NULL) - CloseHandle(m_actionTakenEvent); + PAL_CloseEvent(m_actionTakenEvent); if (m_pNativePipeline != NULL) { @@ -10262,9 +10282,19 @@ HRESULT CordbWin32EventThread::Init() return E_OUTOFMEMORY; } - m_actionTakenEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + m_threadExitedEvent = new (nothrow) WaitLatch(); + if ((m_threadExitedEvent == nullptr) || !m_threadExitedEvent->IsValid()) + { + delete m_threadExitedEvent; + m_threadExitedEvent = nullptr; + delete m_threadControlEvent; + m_threadControlEvent = nullptr; + return E_OUTOFMEMORY; + } + + m_actionTakenEvent = PAL_CreateEvent(NULL, false, false); if (m_actionTakenEvent == NULL) - return HRESULT_FROM_GetLastError(); + return E_OUTOFMEMORY; m_pNativePipeline = NewPipelineForThisPlatform(); if (m_pNativePipeline == NULL) @@ -10375,7 +10405,8 @@ void CordbProcess::FilterClrNotification( // Some other thread called code:CordbRCEventThread::WaitForIPCEventFromProcess, and // that will respond here and set the event. - DWORD dwResult = WaitForSingleObject(this->m_leftSideEventRead, CordbGetWaitTimeout()); + HANDLE waitHandles[] = { this->m_leftSideEventRead }; + DWORD dwResult = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, CordbGetWaitTimeout(), false); pLockHolder->Acquire(); if (dwResult != WAIT_OBJECT_0) { @@ -11433,13 +11464,13 @@ void CordbProcess::HandleSyncCompleteReceived() if (this->m_stopRequested) { this->SetSynchronized(true); - SetEvent(this->m_stopWaitEvent); + PAL_SetEvent(this->m_stopWaitEvent); } else { // Note: we set the m_stopWaitEvent all the time and leave it high while we're stopped. This // must be done after we've checked m_stopRequested. - SetEvent(this->m_stopWaitEvent); + PAL_SetEvent(this->m_stopWaitEvent); // Otherwise, simply mark that the state of the process has changed and let the // managed event dispatch logic take over. @@ -13442,6 +13473,7 @@ void CordbWin32EventThread::ForceDbgContinue(CordbProcess *pProcess, CordbUnmana CordbWin32EventThread* t = (CordbWin32EventThread*) parameter; INTERNAL_THREAD_ENTRY(t); t->ThreadProc(); + t->m_threadExitedEvent->Set(); return 0; } @@ -13477,7 +13509,8 @@ HRESULT CordbWin32EventThread::SendDebugActiveProcessEvent( if (succ) { - DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE); + HANDLE waitHandles[] = { m_actionTakenEvent }; + DWORD ret = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); if (ret == WAIT_OBJECT_0) hr = m_actionResult; @@ -13692,7 +13725,7 @@ void CordbWin32EventThread::AttachProcess() // Signal the hr to the caller. // m_actionResult = hr; - SetEvent(m_actionTakenEvent); + PAL_SetEvent(m_actionTakenEvent); } @@ -13716,7 +13749,8 @@ HRESULT CordbWin32EventThread::SendDetachProcessEvent(CordbProcess *pProcess) if (succ) { - DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE); + HANDLE waitHandles[] = { m_actionTakenEvent }; + DWORD ret = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); if (ret == WAIT_OBJECT_0) hr = m_actionResult; @@ -13763,7 +13797,8 @@ HRESULT CordbWin32EventThread::SendUnmanagedContinue(CordbProcess *pProcess, if (succ) { - DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE); + HANDLE waitHandles[] = { m_actionTakenEvent }; + DWORD ret = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); if (ret == WAIT_OBJECT_0) hr = m_actionResult; @@ -13812,7 +13847,7 @@ void CordbWin32EventThread::HandleUnmanagedContinue() // Signal the hr to the caller. m_actionResult = hr; - SetEvent(m_actionTakenEvent); + PAL_SetEvent(m_actionTakenEvent); } // @@ -14111,7 +14146,7 @@ void CordbWin32EventThread::ExitProcess(bool fDetach) if( FAILED(hr) ) { m_actionResult = hr; - SetEvent(m_actionTakenEvent); + PAL_SetEvent(m_actionTakenEvent); return; } } @@ -14137,7 +14172,7 @@ void CordbWin32EventThread::ExitProcess(bool fDetach) LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: In EP(detach), but EP(exit) already called. Early failure\n")); m_actionResult = CORDBG_E_PROCESS_TERMINATED; - SetEvent(m_actionTakenEvent); + PAL_SetEvent(m_actionTakenEvent); return; } @@ -14187,7 +14222,7 @@ void CordbWin32EventThread::ExitProcess(bool fDetach) LOG((LF_CORDB, LL_INFO1000,"W32ET::EP: Detach: send result back!\n")); m_actionResult = S_OK; - SetEvent(m_actionTakenEvent); + PAL_SetEvent(m_actionTakenEvent); } m_pProcess->Unlock(); @@ -14228,7 +14263,8 @@ HRESULT CordbWin32EventThread::SendCanDetach() if (succ) { - DWORD ret = WaitForSingleObject(m_actionTakenEvent, INFINITE); + HANDLE waitHandles[] = { m_actionTakenEvent }; + DWORD ret = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); if (ret == WAIT_OBJECT_0) hr = m_actionResult; @@ -14255,7 +14291,7 @@ void CordbWin32EventThread::HandleCanDetach() // Signal the hr to the caller. m_actionResult = canDetach ? S_OK : S_FALSE; - SetEvent(m_actionTakenEvent); + PAL_SetEvent(m_actionTakenEvent); } #endif @@ -14306,9 +14342,10 @@ HRESULT CordbWin32EventThread::Stop() m_threadControlEvent->Set(); UnlockSendToWin32EventThreadMutex(); - DWORD ret = WaitForSingleObject(m_thread, INFINITE); + const WaitHandle *waitSet[] = { m_threadExitedEvent }; + int32_t ret = WaitHandle::Wait(waitSet, ARRAY_SIZE(waitSet), INFINITE); - if (ret != WAIT_OBJECT_0) + if (ret != 0) hr = HRESULT_FROM_GetLastError(); } @@ -14653,7 +14690,7 @@ HRESULT CordbProcess::HijackIBEvent(CordbUnmanagedEvent * pUnmanagedEvent) return S_OK; } - ResetEvent(this->m_leftSideUnmanagedWaitEvent); + PAL_ResetEvent(this->m_leftSideUnmanagedWaitEvent); if (pUnmanagedEvent->m_currentDebugEvent.u.Exception.dwFirstChance) { HRESULT hr = pUnmanagedEvent->m_owner->SetupFirstChanceHijackForSync(); @@ -14859,6 +14896,6 @@ bool CordbProcess::CanDetach() void CordbProcess::TryDetach() { - SetEvent(m_detachSetThreadContextNeededEvent); + PAL_SetEvent(m_detachSetThreadContextNeededEvent); } #endif // OUT_OF_PROCESS_SETTHREADCONTEXT diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index f8011e14d564a8..19c46674da07e3 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -10128,6 +10128,7 @@ class CordbWin32EventThread HANDLE m_thread; DWORD m_threadId; WaitEvent *m_threadControlEvent; + WaitLatch *m_threadExitedEvent; HANDLE m_actionTakenEvent; BOOL m_run; @@ -10302,6 +10303,7 @@ class CordbRCEventThread DWORD m_threadId; BOOL m_run; WaitEvent *m_threadControlEvent; + WaitLatch *m_threadExitedEvent; BOOL m_processStateChanged; }; diff --git a/src/coreclr/debug/di/shimprocess.cpp b/src/coreclr/debug/di/shimprocess.cpp index 363cd07f926ff1..79755fbf77ae3b 100644 --- a/src/coreclr/debug/di/shimprocess.cpp +++ b/src/coreclr/debug/di/shimprocess.cpp @@ -10,6 +10,7 @@ //***************************************************************************** #include "stdafx.h" +#include "RuntimeEvent.h" #include "safewrap.h" #include "check.h" @@ -52,16 +53,18 @@ ShimProcess::ShimProcess() : m_machineInfo.Clear(); - m_markAttachPendingEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + m_markAttachPendingEvent = PAL_CreateEvent(NULL, true, false); if (m_markAttachPendingEvent == NULL) { - ThrowLastError(); + ThrowOutOfMemory(); } - m_terminatingEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + m_terminatingEvent = PAL_CreateEvent(NULL, true, false); if (m_terminatingEvent == NULL) { - ThrowLastError(); + PAL_CloseEvent(m_markAttachPendingEvent); + m_markAttachPendingEvent = NULL; + ThrowOutOfMemory(); } } @@ -84,13 +87,13 @@ ShimProcess::~ShimProcess() if (m_markAttachPendingEvent != NULL) { - CloseHandle(m_markAttachPendingEvent); + PAL_CloseEvent(m_markAttachPendingEvent); m_markAttachPendingEvent = NULL; } if (m_terminatingEvent != NULL) { - CloseHandle(m_terminatingEvent); + PAL_CloseEvent(m_terminatingEvent); m_terminatingEvent = NULL; } @@ -874,7 +877,7 @@ HRESULT ShimProcess::HandleWin32DebugEvent(const DEBUG_EVENT * pEvent) DWORD fSkipResume = config.val(CLRConfig::UNSUPPORTED_DbgDontResumeThreadsOnUnhandledException); if (!fSkipResume) { - ::Sleep(500); + PAL_Sleep(500); } } } @@ -1612,12 +1615,12 @@ MachineInfo ShimProcess::GetMachineInfo() void ShimProcess::SetMarkAttachPendingEvent() { - SetEvent(m_markAttachPendingEvent); + PAL_SetEvent(m_markAttachPendingEvent); } void ShimProcess::SetTerminatingEvent() { - SetEvent(m_terminatingEvent); + PAL_SetEvent(m_terminatingEvent); } RSLock * ShimProcess::GetShimLock() diff --git a/src/coreclr/debug/ee/canary.cpp b/src/coreclr/debug/ee/canary.cpp index ffa635e9a19266..9f5bff9e3e46c0 100644 --- a/src/coreclr/debug/ee/canary.cpp +++ b/src/coreclr/debug/ee/canary.cpp @@ -10,6 +10,7 @@ //***************************************************************************** #include "stdafx.h" +#include "RuntimeEvent.h" //----------------------------------------------------------------------------- @@ -19,6 +20,9 @@ HelperCanary::HelperCanary() { m_hCanaryThread = NULL; m_CanaryThreadId = 0; + m_hPingEvent = NULL; + m_hCanaryThreadExitedEvent = NULL; + m_hWaitEvent = NULL; m_RequestCounter = 0; m_AnswerCounter = 0; m_fStop = false; @@ -35,10 +39,29 @@ HelperCanary::~HelperCanary() { // Since we're deleting this memory, we need to kill the canary thread. m_fStop = true; - SetEvent(m_hPingEvent); + if (m_hPingEvent != NULL) + { + PAL_SetEvent(m_hPingEvent); + } - // m_hPingEvent dtor will close handle - WaitForSingleObject(m_hCanaryThread, INFINITE); + if (m_hCanaryThread != NULL) + { + HANDLE waitHandles[] = { m_hCanaryThreadExitedEvent }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); + CloseHandle(m_hCanaryThread); + } + if (m_hPingEvent != NULL) + { + PAL_CloseEvent(m_hPingEvent); + } + if (m_hCanaryThreadExitedEvent != NULL) + { + PAL_CloseEvent(m_hCanaryThreadExitedEvent); + } + if (m_hWaitEvent != NULL) + { + PAL_CloseEvent(m_hWaitEvent); + } } //----------------------------------------------------------------------------- @@ -119,7 +142,7 @@ void HelperCanary::Init() m_initialized = true; } - m_hPingEvent = CreateEvent(NULL, (BOOL) kAutoResetEvent, FALSE, NULL); + m_hPingEvent = PAL_CreateEvent(NULL, false, false); if (m_hPingEvent == NULL) { STRESS_LOG1(LF_CORDB, LL_ALWAYS, "Canary failed to create ping event. gle=%d\n", GetLastError()); @@ -130,7 +153,7 @@ void HelperCanary::Init() return; } - m_hWaitEvent = CreateEvent(NULL, (BOOL) kManualResetEvent, FALSE, NULL); + m_hWaitEvent = PAL_CreateEvent(NULL, true, false); if (m_hWaitEvent == NULL) { STRESS_LOG1(LF_CORDB, LL_ALWAYS, "Canary failed to create wait event. gle=%d\n", GetLastError()); @@ -141,6 +164,14 @@ void HelperCanary::Init() return; } + m_hCanaryThreadExitedEvent = PAL_CreateEvent(NULL, true, false); + if (m_hCanaryThreadExitedEvent == NULL) + { + STRESS_LOG1(LF_CORDB, LL_ALWAYS, "Canary failed to create thread-exited event. gle=%d\n", GetLastError()); + _ASSERTE(!"Canary failed to create thread-exited event"); + return; + } + // Spin up the canary. This will call dllmain, but that's ok because it just // degenerates to our timeout case. const DWORD flags = CREATE_SUSPENDED; @@ -203,13 +234,13 @@ bool HelperCanary::AreLocksAvailableWorker() // Canary will take the locks of interest and then set the Answer counter equal to our request counter. m_RequestCounter = m_RequestCounter + 1; - ResetEvent(m_hWaitEvent); - SetEvent(m_hPingEvent); + PAL_ResetEvent(m_hWaitEvent); + PAL_SetEvent(m_hPingEvent); // Spin waiting for answer. If canary gets back to us, then the locks must be free and so it's safe for helper-thread. // If we timeout, then we err on the side of safety and assume canary blocked on a lock and so it's not safe // for the helper thread to take those locks. - // We explicitly have a simple spin-wait instead of using win32 events because we want something simple and + // We explicitly have a simple spin-wait instead of relying only on events because we want something simple and // provably correct. Since we already need the spin-wait for the counters, adding an extra win32 event // to get rid of the sleep would be additional complexity and race windows without a clear benefit. @@ -239,11 +270,12 @@ bool HelperCanary::AreLocksAvailableWorker() // We'll either timeout (in which case it's like a Sleep(), or // get the event, which shortcuts the sleep. - WaitForSingleObject(m_hWaitEvent, msSleep); + HANDLE waitHandles[] = { m_hWaitEvent }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, msSleep, false); // In case a stale answer sets the wait event high, reset it now to avoid us doing // a live spin-lock. - ResetEvent(m_hWaitEvent); + PAL_ResetEvent(m_hWaitEvent); msSleep = msSleepSteadyState; @@ -266,6 +298,7 @@ DWORD HelperCanary::ThreadProc(LPVOID param) HelperCanary * pThis = reinterpret_cast (param); pThis->ThreadProc(); _ASSERTE(pThis->m_fStop); + PAL_SetEvent(pThis->m_hCanaryThreadExitedEvent); STRESS_LOG0(LF_CORDB, LL_ALWAYS, "Canary thread exiting\n"); return 0; @@ -281,7 +314,8 @@ void HelperCanary::ThreadProc() while(true) { - WaitForSingleObject(m_hPingEvent, INFINITE); + HANDLE waitHandles[] = { m_hPingEvent }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); m_AnswerCounter = 0; DWORD dwRequest = m_RequestCounter; @@ -300,7 +334,7 @@ void HelperCanary::ThreadProc() // Set wait event to let Requesting thread shortcut its spin lock. This is purely an // optimization because requesting thread will still check Answer/Request counters. // That protects us from recyling bugs. - SetEvent(m_hWaitEvent); + PAL_SetEvent(m_hWaitEvent); } } @@ -319,5 +353,3 @@ void HelperCanary::TakeLocks() STRESS_LOG1(LF_CORDB, LL_ALWAYS, "canary stage:%d\n", 1); } - - diff --git a/src/coreclr/debug/ee/canary.h b/src/coreclr/debug/ee/canary.h index 225c7652e0724b..960081fdd38863 100644 --- a/src/coreclr/debug/ee/canary.h +++ b/src/coreclr/debug/ee/canary.h @@ -68,12 +68,12 @@ class HelperCanary // sufficient to deal with memory barrier issues. Volatile m_RequestCounter; Volatile m_AnswerCounter; - HandleHolder m_hPingEvent; + HANDLE m_hPingEvent; + HANDLE m_hCanaryThreadExitedEvent; // We use a Manual wait event to replace Sleep. - HandleHolder m_hWaitEvent; + HANDLE m_hWaitEvent; }; #endif // CANARY_H - diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index b7cfc4d2278fdd..8b847749599895 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -8,6 +8,7 @@ //***************************************************************************** #include "stdafx.h" +#include "RuntimeEvent.h" #include "debugdebugger.h" #include "../inc/common.h" #include "eeconfig.h" // This is here even for retail & free builds... @@ -1326,8 +1327,8 @@ DWORD WINAPI DbgInteropStressProc(void * lpParameter) // This helps parallelize if we have a lot of threads, and keeps us from // chewing too much CPU time. - ClrSleepEx(2000,FALSE); - ClrSleepEx(GetRandomInt(1000), FALSE); + PAL_Sleep(2000); + PAL_Sleep(GetRandomInt(1000)); } return 0; @@ -1349,7 +1350,7 @@ DWORD WINAPI DbgInteropDummyStressProc(void * lpParameter) { LIMITED_METHOD_CONTRACT; - ClrSleepEx(1,FALSE); + PAL_Sleep(1); return 0; } @@ -1374,7 +1375,7 @@ DWORD WINAPI DbgInteropOOBStressProc(void * lpParameter) OutputDebugString(W("OOB ping from ")); } - ClrSleepEx(3000, FALSE); + PAL_Sleep(3000); } return 0; @@ -2147,13 +2148,13 @@ void DebuggerLazyInit::Init() // Create some synchronization events... // these events stay signaled all the time except when an attach is in progress - m_exAttachEvent = CreateWin32EventOrThrow(NULL, kManualResetEvent, TRUE); - m_exUnmanagedAttachEvent = CreateWin32EventOrThrow(pSA, kManualResetEvent, TRUE); + m_exAttachEvent = CreateEventOrThrow(NULL, kManualResetEvent, TRUE); + m_exUnmanagedAttachEvent = CreateEventOrThrow(pSA, kManualResetEvent, TRUE); - m_CtrlCMutex = CreateWin32EventOrThrow(NULL, kAutoResetEvent, FALSE); + m_CtrlCMutex = CreateEventOrThrow(NULL, kAutoResetEvent, FALSE); m_DebuggerHandlingCtrlC = FALSE; - m_garbageCollectionBlockerEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + m_garbageCollectionBlockerEvent = CreateEventOrThrow(NULL, kManualResetEvent, FALSE); // Let the helper thread lazy init stuff too. m_RCThread.Init(); @@ -2180,22 +2181,22 @@ DebuggerLazyInit::~DebuggerLazyInit() if (m_CtrlCMutex != NULL) { - CloseHandle(m_CtrlCMutex); + PAL_CloseEvent(m_CtrlCMutex); } if (m_exAttachEvent != NULL) { - CloseHandle(m_exAttachEvent); + PAL_CloseEvent(m_exAttachEvent); } if (m_exUnmanagedAttachEvent != NULL) { - CloseHandle(m_exUnmanagedAttachEvent); + PAL_CloseEvent(m_exUnmanagedAttachEvent); } if (m_garbageCollectionBlockerEvent != NULL) { - CloseHandle(m_garbageCollectionBlockerEvent); + PAL_CloseEvent(m_garbageCollectionBlockerEvent); } } @@ -5683,8 +5684,9 @@ void Debugger::SuspendForGarbageCollectionCompleted() this->SuspendComplete(true); } - WaitForSingleObject(this->GetGarbageCollectionBlockerEvent(), INFINITE); - ResetEvent(this->GetGarbageCollectionBlockerEvent()); + HANDLE waitHandles[] = { this->GetGarbageCollectionBlockerEvent() }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); + PAL_ResetEvent(this->GetGarbageCollectionBlockerEvent()); } void Debugger::ResumeForGarbageCollectionStarted() @@ -5720,8 +5722,9 @@ void Debugger::ResumeForGarbageCollectionStarted() this->SuspendComplete(true); } - WaitForSingleObject(this->GetGarbageCollectionBlockerEvent(), INFINITE); - ResetEvent(this->GetGarbageCollectionBlockerEvent()); + HANDLE waitHandles[] = { this->GetGarbageCollectionBlockerEvent() }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); + PAL_ResetEvent(this->GetGarbageCollectionBlockerEvent()); this->m_isBlockedOnGarbageCollectionEvent = FALSE; this->m_willBlockOnGarbageCollectionEvent = FALSE; } @@ -6729,8 +6732,8 @@ BOOL Debugger::PreJitAttach(BOOL willSendManagedEvent, BOOL willLaunchDebugger, m_jitAttachInProgress = TRUE; m_launchingDebugger = willLaunchDebugger; CLRJitAttachState = (willSendManagedEvent ? CLR_DEBUGGING_MANAGED_EVENT_PENDING : 0) | (explicitUserRequest ? CLR_DEBUGGING_MANAGED_EVENT_DEBUGGER_LAUNCH : 0); - ResetEvent(GetUnmanagedAttachEvent()); - ResetEvent(GetAttachEvent()); + PAL_ResetEvent(GetUnmanagedAttachEvent()); + PAL_ResetEvent(GetAttachEvent()); LOG( (LF_CORDB, LL_INFO10000, "D::PreJA: Leaving - first thread\n") ); return TRUE; } @@ -6867,14 +6870,16 @@ void Debugger::WaitForDebuggerAttach() // be signaled. if (m_launchingDebugger) { - WaitForSingleObject(GetUnmanagedAttachEvent(), INFINITE); + HANDLE waitHandles[] = { GetUnmanagedAttachEvent() }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); } // Wait until the pending managed debugger attach is completed if (CORDebuggerPendingAttach() && !CORDebuggerAttached()) { LOG( (LF_CORDB, LL_INFO10000, "D::WFDA: Waiting for managed attach too\n") ); - WaitForSingleObject(GetAttachEvent(), INFINITE); + HANDLE waitHandles[] = { GetAttachEvent() }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); } // We can't reset the event here because some threads may @@ -6912,8 +6917,8 @@ void Debugger::PostJitAttach() // set the attaching events to unblock other threads waiting on this attach // regardless of whether or not it completed - SetEvent(GetUnmanagedAttachEvent()); - SetEvent(GetAttachEvent()); + PAL_SetEvent(GetUnmanagedAttachEvent()); + PAL_SetEvent(GetAttachEvent()); LOG( (LF_CORDB, LL_INFO10000, "D::PostJA: Leaving\n") ); } @@ -10104,11 +10109,11 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) MarkDebuggerAttachedInternal(); // set the managed attach event so that waiting threads can continue - VERIFY(SetEvent(GetAttachEvent())); + VERIFY(PAL_SetEvent(GetAttachEvent())); break; } - VERIFY(SetEvent(GetAttachEvent())); + VERIFY(PAL_SetEvent(GetAttachEvent())); // // For regular (non-jit) attach, fall through to do an async break. @@ -10147,7 +10152,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) if (this->m_isBlockedOnGarbageCollectionEvent) { this->m_stopped = false; - SetEvent(this->GetGarbageCollectionBlockerEvent()); + PAL_SetEvent(this->GetGarbageCollectionBlockerEvent()); } else { @@ -10700,7 +10705,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) if (this->m_isBlockedOnGarbageCollectionEvent) { this->m_stopped = FALSE; - SetEvent(this->GetGarbageCollectionBlockerEvent()); + PAL_SetEvent(this->GetGarbageCollectionBlockerEvent()); } else { @@ -10905,7 +10910,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) // store the result of whether the event has been handled by the debugger and // wake up the thread waiting for the result SetDebuggerHandlingCtrlC(pEvent->hr == S_OK); - VERIFY(SetEvent(GetCtrlCMutex())); + VERIFY(PAL_SetEvent(GetCtrlCMutex())); } break; @@ -11420,7 +11425,7 @@ void Debugger::PollWaitingForHelper() _ASSERTE(!ThreadHoldsLock()); const DWORD dwTime = 50; - ClrSleepEx(dwTime, FALSE); + PAL_Sleep(dwTime); nTotalMSToWait -= dwTime; if (nTotalMSToWait <= 0) @@ -13481,7 +13486,8 @@ LONG Debugger::FirstChanceSuspendHijackWorker(CONTEXT *pContext, // Wait for the continue. We may / may not have an EE Thread for this, (and we're definitely // not doing fiber-mode debugging), so just use a raw win32 API, and not some fancy fiber-safe call. SPEW(fprintf(stderr, "0x%x D::FCHF: waiting for continue.\n", tid)); - DWORD ret = WaitForSingleObject(g_pDebugger->m_pRCThread->GetDCB()->m_leftSideUnmanagedWaitEvent, INFINITE); + HANDLE waitHandles[] = { g_pDebugger->m_pRCThread->GetDCB()->m_leftSideUnmanagedWaitEvent }; + DWORD ret = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); SPEW(fprintf(stderr, "0x%x D::FCHF: waiting for continue complete.\n", tid)); if (ret != WAIT_OBJECT_0) @@ -13571,8 +13577,8 @@ void GenericHijackFuncHelper() pEEThread->SetInteropDebuggingHijacked(TRUE); } - DWORD ret = WaitForSingleObject(g_pRCThread->GetDCB()->m_leftSideUnmanagedWaitEvent, - INFINITE); + HANDLE waitHandles[] = { g_pRCThread->GetDCB()->m_leftSideUnmanagedWaitEvent }; + DWORD ret = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); if (ret != WAIT_OBJECT_0) { @@ -14723,7 +14729,7 @@ void Debugger::DoHelperThreadDuty() // Make sure the helper thread has something to wait on while // we're trying to be the helper thread. - VERIFY(ResetEvent(m_pRCThread->GetHelperThreadCanGoEvent())); + VERIFY(PAL_ResetEvent(m_pRCThread->GetHelperThreadCanGoEvent())); // We have not sent the sync-complete flare yet. @@ -14753,7 +14759,7 @@ void Debugger::DoHelperThreadDuty() m_pRCThread->GetDCB()->m_temporaryHelperThreadId = 0; // Let the helper thread go if its waiting on us. - VERIFY(SetEvent(m_pRCThread->GetHelperThreadCanGoEvent())); + VERIFY(PAL_SetEvent(m_pRCThread->GetHelperThreadCanGoEvent())); } @@ -14892,7 +14898,8 @@ BOOL Debugger::SendCtrlCToDebugger(DWORD dwCtrlType) // now wait for notification from the right side about whether or not // the out-of-proc debugger is handling ControlC events. - ::WaitForSingleObject(GetCtrlCMutex(), INFINITE); + HANDLE waitHandles[] = { GetCtrlCMutex() }; + PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); return GetDebuggerHandlingCtrlC(); } diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index 3adb7ff084804f..d8176e3a99b0d3 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -3665,7 +3665,7 @@ enum EEventResetType { kAutoResetEvent = FALSE }; -HANDLE CreateWin32EventOrThrow( +HANDLE CreateEventOrThrow( LPSECURITY_ATTRIBUTES lpEventAttributes, EEventResetType eType, BOOL bInitialState diff --git a/src/coreclr/debug/ee/rcthread.cpp b/src/coreclr/debug/ee/rcthread.cpp index 26fcdcb1628aea..faf368cd10df28 100644 --- a/src/coreclr/debug/ee/rcthread.cpp +++ b/src/coreclr/debug/ee/rcthread.cpp @@ -10,6 +10,7 @@ //***************************************************************************** #include "stdafx.h" +#include "RuntimeEvent.h" #include "threadsuspend.h" #ifndef SM_REMOTESESSION @@ -103,7 +104,7 @@ void DebuggerRCThread::CloseIPCHandles() } //----------------------------------------------------------------------------- -// Simple wrapper to create win32 events. +// Simple wrapper to create runtime events. // This helps make DebuggerRCThread::Init pretty, beccause we // create lots of events there. // These will either: @@ -111,7 +112,7 @@ void DebuggerRCThread::CloseIPCHandles() // 2) or throw an exception. // @todo - should these be CLREvents? ClrCreateManualEvent / ClrCreateAutoEvent //----------------------------------------------------------------------------- -HANDLE CreateWin32EventOrThrow( +HANDLE CreateEventOrThrow( LPSECURITY_ATTRIBUTES lpEventAttributes, EEventResetType eType, BOOL bInitialState @@ -126,10 +127,10 @@ HANDLE CreateWin32EventOrThrow( CONTRACTL_END; HANDLE h = NULL; - h = CreateEvent(lpEventAttributes, (BOOL) eType, bInitialState, NULL); + h = PAL_CreateEvent(lpEventAttributes, eType == kManualResetEvent, bInitialState); if (h == NULL) - ThrowLastError(); + ThrowOutOfMemory(); return h; } @@ -296,7 +297,7 @@ HRESULT DebuggerRCThread::Init(void) } // Create the helper thread can go event. - m_helperThreadCanGoEvent = CreateWin32EventOrThrow(NULL, kManualResetEvent, TRUE); + m_helperThreadCanGoEvent = CreateEventOrThrow(NULL, kManualResetEvent, TRUE); m_pDCB = new(nothrow) DebuggerIPCControlBlock; @@ -352,7 +353,7 @@ HRESULT DebuggerRCThread::Init(void) } - HandleHolder leftSideUnmanagedWaitEvent(CreateWin32EventOrThrow(NULL, kManualResetEvent, FALSE)); + HandleHolder leftSideUnmanagedWaitEvent(CreateEventOrThrow(NULL, kManualResetEvent, FALSE)); // Copy RSEA and RSER into the control block only if shared memory is created without error. if (m_pDCB) @@ -639,7 +640,7 @@ void DebuggerRCThread::ThreadProc(void) case 3: dwSleep = INFINITE; break; } - ClrSleepEx(dwSleep, FALSE); + PAL_Sleep(dwSleep); } #endif @@ -671,14 +672,6 @@ void DebuggerRCThread::ThreadProc(void) // the handle was created by the Start method _ASSERTE(m_thread != NULL); -#ifdef _DEBUG - // Make sure that we have the proper permissions. - { - DWORD dwWaitResult = WaitForSingleObject(m_thread, 0); - _ASSERTE(dwWaitResult == WAIT_TIMEOUT); - } -#endif - // Mark that we're the true helper thread. Now that we've marked // this, no other threads will ever become the temporary helper // thread. @@ -702,7 +695,8 @@ void DebuggerRCThread::ThreadProc(void) debugLockHolder.Release(); // Wait for the temporary helper thread to finish up. - DWORD dwWaitResult = WaitForSingleObject(m_helperThreadCanGoEvent, INFINITE); + HANDLE waitHandles[] = { m_helperThreadCanGoEvent }; + DWORD dwWaitResult = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); (void)dwWaitResult; //prevent "unused variable" error from GCC LOG((LF_CORDB, LL_INFO1000, "DRCT::TP: done waiting for temp help to finish up.\n")); @@ -807,7 +801,7 @@ bool DebuggerRCThread::HandleRSEA() { LOG((LF_CORDB, LL_INFO1000, "DRCT::ML: no reply required, letting Right Side go.\n")); - BOOL succ = SetEvent(m_pDCB->m_rightSideEventRead); + BOOL succ = PAL_SetEvent(m_pDCB->m_rightSideEventRead); if (!succ) CORDBDebuggerSetUnrecoverableWin32Error(m_debugger, 0, true); @@ -1604,10 +1598,7 @@ bool DebuggerRCThread::IsRCThreadReady() return false; } - // a more subtle check. It's possible the thread was up, but then - // an bad call to ExitProcess suddenly terminated the helper thread, - // leaving the threadid still non-0. So check the actual thread object - // and make sure it's still around. +#ifdef TARGET_WINDOWS int ret = WaitForSingleObject(m_thread, 0); LOG((LF_CORDB, LL_EVERYTHING, "DRCT::IsReady - wait(%p)=0x%x, GetLastError() = 0x%x\n", m_thread, ret, GetLastError())); @@ -1615,6 +1606,7 @@ bool DebuggerRCThread::IsRCThreadReady() { return false; } +#endif // TARGET_WINDOWS return true; } @@ -1816,7 +1808,7 @@ HRESULT DebuggerRCThread::SendIPCReply() #endif #if !defined(FEATURE_DBGIPC_TRANSPORT_VM) - BOOL succ = SetEvent(m_pDCB->m_rightSideEventRead); + BOOL succ = PAL_SetEvent(m_pDCB->m_rightSideEventRead); if (!succ) { hr = CORDBDebuggerSetUnrecoverableWin32Error(m_debugger, 0, false); diff --git a/src/coreclr/debug/shared/dbgtransportsession.cpp b/src/coreclr/debug/shared/dbgtransportsession.cpp index c2a3578d4adee9..f18c705457035f 100644 --- a/src/coreclr/debug/shared/dbgtransportsession.cpp +++ b/src/coreclr/debug/shared/dbgtransportsession.cpp @@ -3,6 +3,7 @@ #include "dbgtransportsession.h" +#include "RuntimeEvent.h" #ifdef RIGHT_SIDE_COMPILE #include @@ -1336,7 +1337,7 @@ void DbgTransportSession::TransportWorker() { DbgTransportLog(LC_Proxy, "AllocateConnection() failed with %u\n", eStatus); DBG_TRANSPORT_INC_STAT(MiscErrors); - Sleep(1000); + PAL_Sleep(1000); continue; } #else // RIGHT_SIDE_COMPILE @@ -1370,7 +1371,7 @@ void DbgTransportSession::TransportWorker() { DbgTransportLog(LC_Proxy, "Accept() failed with %u\n", eStatus); DBG_TRANSPORT_INC_STAT(MiscErrors); - Sleep(1000); + PAL_Sleep(1000); continue; } diff --git a/src/coreclr/dlls/mscordac/mscordac_unixexports.src b/src/coreclr/dlls/mscordac/mscordac_unixexports.src index 895a13c032264a..d726161e7d0e9b 100644 --- a/src/coreclr/dlls/mscordac/mscordac_unixexports.src +++ b/src/coreclr/dlls/mscordac/mscordac_unixexports.src @@ -60,8 +60,6 @@ nativeStringResourceTable_mscorrc #CreateFileMappingW #CreateFileA #CreateFileW -#CreateEventW -#CreateEventExW #CreateThread #CloseHandle #DebugBreak @@ -92,20 +90,15 @@ nativeStringResourceTable_mscorrc #MapViewOfFileEx #MultiByteToWideChar #OutputDebugStringW -#OpenEventW #OutputDebugStringA #RaiseException #RaiseFailFastException #ReadFile -#ResetEvent #ResumeThread #SearchPathW -#SetEvent #SetFilePointer #SetLastError #SetThreadDescription -#Sleep -#SleepEx #SwitchToThread #TerminateProcess #VirtualAlloc @@ -113,9 +106,6 @@ nativeStringResourceTable_mscorrc #VirtualProtect #VirtualQuery #UnmapViewOfFile -#WaitForMultipleObjectsEx -#WaitForSingleObject -#WaitForSingleObjectEx #WideCharToMultiByte #WriteFile diff --git a/src/coreclr/gc/CMakeLists.txt b/src/coreclr/gc/CMakeLists.txt index 32eb0a81d140be..c6c1dc672e3e34 100644 --- a/src/coreclr/gc/CMakeLists.txt +++ b/src/coreclr/gc/CMakeLists.txt @@ -83,7 +83,8 @@ if(CLR_CMAKE_HOST_WIN32) ${STATIC_MT_CRT_LIB} ${STATIC_MT_VCRT_LIB} kernel32.lib - advapi32.lib) + advapi32.lib + coreclrminipal) endif(CLR_CMAKE_HOST_WIN32) set (GC_LINK_LIBRARIES diff --git a/src/coreclr/gc/sample/CMakeLists.txt b/src/coreclr/gc/sample/CMakeLists.txt index 28835e250d6361..d575a1b6e0578b 100644 --- a/src/coreclr/gc/sample/CMakeLists.txt +++ b/src/coreclr/gc/sample/CMakeLists.txt @@ -75,6 +75,7 @@ if(CLR_CMAKE_TARGET_WIN32) ${STATIC_MT_VCRT_LIB} kernel32.lib advapi32.lib + coreclrminipal minipal ) endif(CLR_CMAKE_TARGET_WIN32) diff --git a/src/coreclr/gc/windows/gcenv.windows.cpp b/src/coreclr/gc/windows/gcenv.windows.cpp index 9057bf04189519..148941bd2ad29a 100644 --- a/src/coreclr/gc/windows/gcenv.windows.cpp +++ b/src/coreclr/gc/windows/gcenv.windows.cpp @@ -14,6 +14,7 @@ #include "gcenv.windows.inl" #include "volatile.h" #include "gcconfig.h" +#include "../../runtime/RuntimeEvent.h" GCSystemInfo g_SystemInfo; @@ -663,7 +664,7 @@ void GCToOSInterface::Sleep(uint32_t sleepMSec) // to avoid context switches - is that interesting or useful here? if (sleepMSec > 0) { - ::SleepEx(sleepMSec, FALSE); + PAL_Sleep(sleepMSec); } } diff --git a/src/coreclr/inc/clrhost.h b/src/coreclr/inc/clrhost.h index e2eb8f04923ade..c6f94eeeac6028 100644 --- a/src/coreclr/inc/clrhost.h +++ b/src/coreclr/inc/clrhost.h @@ -80,8 +80,6 @@ void ClrDeleteCriticalSection(CRITSEC_COOKIE cookie); void ClrEnterCriticalSection(CRITSEC_COOKIE cookie); void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie); -DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable); - // Rather than use the above APIs directly, it is recommended that holder classes // be used. This guarantees that the locks will be vacated when the scope is popped, // either on exception or on return. diff --git a/src/coreclr/minipal/Unix/CMakeLists.txt b/src/coreclr/minipal/Unix/CMakeLists.txt index 969c502323ea79..b78b439c3ef898 100644 --- a/src/coreclr/minipal/Unix/CMakeLists.txt +++ b/src/coreclr/minipal/Unix/CMakeLists.txt @@ -1,4 +1,5 @@ set(SOURCES + ${RUNTIME_DIR}/unix/RuntimeEvent.cpp doublemapping.cpp dn-u16.cpp dn-stdio.cpp @@ -9,6 +10,7 @@ add_library(coreclrminipal_objects OBJECT ${SOURCES} ) +target_include_directories(coreclrminipal_objects PRIVATE ${CMAKE_BINARY_DIR}/shared_minipal) add_library(coreclrminipal STATIC diff --git a/src/coreclr/minipal/Windows/CMakeLists.txt b/src/coreclr/minipal/Windows/CMakeLists.txt index fa6ed5bd8a4b82..7af4a443691fd7 100644 --- a/src/coreclr/minipal/Windows/CMakeLists.txt +++ b/src/coreclr/minipal/Windows/CMakeLists.txt @@ -1,4 +1,5 @@ set(SOURCES + ${RUNTIME_DIR}/windows/RuntimeEvent.cpp doublemapping.cpp dn-u16.cpp dn-stdio.cpp diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt index 1fab02de90e1be..7a7711181895a4 100644 --- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt @@ -99,6 +99,7 @@ include_directories(.) include_directories(${GC_DIR}) include_directories(${GC_DIR}/env) include_directories(${CMAKE_CURRENT_BINARY_DIR}/eventpipe/inc) +include_directories(${CMAKE_BINARY_DIR}/shared_minipal) include_directories(${RUNTIME_DIR}) if (WIN32) @@ -141,6 +142,7 @@ if (WIN32) include_directories(windows) list(APPEND COMMON_RUNTIME_SOURCES + ${RUNTIME_DIR}/windows/RuntimeEvent.cpp windows/PalCommon.cpp windows/PalMinWin.cpp ${GC_DIR}/windows/gcenv.windows.cpp @@ -196,6 +198,7 @@ else() endif() list(APPEND COMMON_RUNTIME_SOURCES + ${RUNTIME_DIR}/unix/RuntimeEvent.cpp unix/PalUnix.cpp unix/PalCreateDump.cpp ${GC_DIR}/unix/gcenv.unix.cpp diff --git a/src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp b/src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp index ed25a700b89b10..4df579f88eebdc 100644 --- a/src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/FinalizerHelpers.cpp @@ -44,14 +44,14 @@ uint32_t WINAPI FinalizerStart(void* pContext) #ifdef TARGET_WINDOWS g_ComAndFlsInitSucceeded = PalInitComAndFlsSlot(); // handshake with EE initialization, as now we can attach Thread objects to native threads. - UInt32_BOOL res = PalSetEvent(g_FinalizerDoneEvent.GetOSEvent()); + bool res = PAL_SetEvent(g_FinalizerDoneEvent.GetOSEvent()); ASSERT(res); // if FLS initialization failed do not attach the current thread and just exit instead. // we are going to fail the runtime initialization. if (!g_ComAndFlsInitSucceeded) return 0; -#endif // DEBUG +#endif // TARGET_WINDOWS HANDLE hFinalizerEvent = (HANDLE)pContext; @@ -67,12 +67,13 @@ uint32_t WINAPI FinalizerStart(void* pContext) g_pFinalizerThread = PTR_Thread(pThread); // Wait for a finalization request. - uint32_t uResult = PalWaitForSingleObjectEx(hFinalizerEvent, INFINITE, FALSE); + HANDLE waitHandles[] = { hFinalizerEvent }; + uint32_t uResult = PAL_WaitForMultipleObjectsEx(1, waitHandles, false, INFINITE, false); ASSERT(uResult == WAIT_OBJECT_0); // Since we just consumed the request (and the event is auto-reset) we must set the event again so the // managed finalizer code will immediately start processing the queue when we run it. - UInt32_BOOL fResult = PalSetEvent(hFinalizerEvent); + bool fResult = PAL_SetEvent(hFinalizerEvent); ASSERT(fResult); // Run the managed portion of the finalizer. This call will never return. @@ -194,7 +195,7 @@ EXTERN_C UInt32_BOOL QCALLTYPE RhpWaitForFinalizerRequest() uint32_t cWaitHandles = (fLastEventWasLowMemory || (lowMemEvent == NULL)) ? 1 : 2; uint32_t uTimeout = fLastEventWasLowMemory ? 2000 : INFINITE; - uint32_t uResult = PalCompatibleWaitAny(/*alertable=*/ FALSE, uTimeout, cWaitHandles, rgWaitHandles, /*allowReentrantWait=*/ FALSE); + uint32_t uResult = PAL_WaitForMultipleObjectsEx(cWaitHandles, rgWaitHandles, false, uTimeout, false); switch (uResult) { @@ -227,7 +228,7 @@ EXTERN_C UInt32_BOOL QCALLTYPE RhpWaitForFinalizerRequest() break; default: - ASSERT(!"Unexpected PalWaitForMultipleObjectsEx() result"); + ASSERT(!"Unexpected PAL_WaitForMultipleObjectsEx() result"); return FALSE; } } while (true); diff --git a/src/coreclr/nativeaot/Runtime/Pal.h b/src/coreclr/nativeaot/Runtime/Pal.h index 534b69675410e1..660d61d48b2c93 100644 --- a/src/coreclr/nativeaot/Runtime/Pal.h +++ b/src/coreclr/nativeaot/Runtime/Pal.h @@ -29,6 +29,7 @@ #include "CommonTypes.h" #include "CommonMacros.h" #include "PalLimitedContext.h" +#include "RuntimeEvent.h" #include "gcenv.structs.h" // EEThreadId #ifndef PAL_INCLUDED @@ -231,10 +232,8 @@ _Ret_maybenull_ _Post_writable_byte_size_(size) void* PalVirtualAlloc(uintptr_t void PalVirtualFree(_In_ void* pAddress, uintptr_t size); UInt32_BOOL PalVirtualProtect(_In_ void* pAddress, uintptr_t size, uint32_t protect); void PalFlushInstructionCache(_In_ void* pAddress, size_t size); -void PalSleep(uint32_t milliseconds); UInt32_BOOL PalSwitchToThread(); UInt32_BOOL PalAreShadowStacksEnabled(); -HANDLE PalCreateEventW(_In_opt_ LPSECURITY_ATTRIBUTES pEventAttributes, UInt32_BOOL manualReset, UInt32_BOOL initialState, _In_opt_z_ LPCWSTR pName); HANDLE PalGetModuleHandleFromPointer(_In_ void* pointer, bool pinModule = false); #ifdef TARGET_UNIX @@ -268,7 +267,9 @@ UInt32_BOOL PalMarkThunksAsValidCallTargets( int thunkBlockSize, int thunkBlocksPerMapping); +#ifdef TARGET_WINDOWS uint32_t PalCompatibleWaitAny(UInt32_BOOL alertable, uint32_t timeout, uint32_t count, HANDLE* pHandles, UInt32_BOOL allowReentrantWait); +#endif HANDLE PalCreateLowMemoryResourceNotification(); @@ -289,7 +290,6 @@ int32_t _stricmp(const char *string1, const char *string2); #endif // TARGET_UNIX uint16_t PalCaptureStackBackTrace(uint32_t arg1, uint32_t arg2, void* arg3, uint32_t* arg4); -UInt32_BOOL PalCloseHandle(HANDLE arg1); uint32_t PalGetCurrentProcessId(); #ifdef UNICODE @@ -298,10 +298,6 @@ uint32_t PalGetEnvironmentVariable(_In_opt_ LPCWSTR lpName, _Out_writes_to_opt_( uint32_t PalGetEnvironmentVariable(_In_opt_ LPCSTR lpName, _Out_writes_to_opt_(nSize, return + 1) LPSTR lpBuffer, _In_ uint32_t nSize); #endif -UInt32_BOOL PalResetEvent(HANDLE arg1); -UInt32_BOOL PalSetEvent(HANDLE arg1); -uint32_t PalWaitForSingleObjectEx(HANDLE arg1, uint32_t arg2, UInt32_BOOL arg3); - void RuntimeThreadShutdown(void* thread); typedef void (*ThreadExitCallback)(); diff --git a/src/coreclr/nativeaot/Runtime/event.cpp b/src/coreclr/nativeaot/Runtime/event.cpp index 1d97dd30780d1c..3647e844ceb1a6 100644 --- a/src/coreclr/nativeaot/Runtime/event.cpp +++ b/src/coreclr/nativeaot/Runtime/event.cpp @@ -22,64 +22,63 @@ // // ----------------------------------------------------------------------------------------------------------- // -// CLR wrapper around events. This version directly uses Win32 events (there's no support for host -// interception). +// CLR wrapper around native events. This version does not support host interception. // bool CLREventStatic::CreateManualEventNoThrow(bool bInitialState) { - m_hEvent = PalCreateEventW(NULL, TRUE, bInitialState, NULL); + m_hEvent = PAL_CreateEvent(NULL, true, bInitialState); m_fInitialized = true; return IsValid(); } bool CLREventStatic::CreateAutoEventNoThrow(bool bInitialState) { - m_hEvent = PalCreateEventW(NULL, FALSE, bInitialState, NULL); + m_hEvent = PAL_CreateEvent(NULL, false, bInitialState); m_fInitialized = true; return IsValid(); } bool CLREventStatic::CreateOSManualEventNoThrow(bool bInitialState) { - m_hEvent = PalCreateEventW(NULL, TRUE, bInitialState, NULL); + m_hEvent = PAL_CreateEvent(NULL, true, bInitialState); m_fInitialized = true; return IsValid(); } bool CLREventStatic::CreateOSAutoEventNoThrow(bool bInitialState) { - m_hEvent = PalCreateEventW(NULL, FALSE, bInitialState, NULL); + m_hEvent = PAL_CreateEvent(NULL, false, bInitialState); m_fInitialized = true; return IsValid(); } void CLREventStatic::CloseEvent() { - if (m_fInitialized && m_hEvent != INVALID_HANDLE_VALUE) + if (m_fInitialized && m_hEvent != NULL && m_hEvent != INVALID_HANDLE_VALUE) { - PalCloseHandle(m_hEvent); + PAL_CloseEvent(m_hEvent); m_hEvent = INVALID_HANDLE_VALUE; } } bool CLREventStatic::IsValid() const { - return m_fInitialized && m_hEvent != INVALID_HANDLE_VALUE; + return m_fInitialized && m_hEvent != NULL && m_hEvent != INVALID_HANDLE_VALUE; } bool CLREventStatic::Set() { if (!m_fInitialized) return false; - return PalSetEvent(m_hEvent); + return PAL_SetEvent(m_hEvent); } bool CLREventStatic::Reset() { if (!m_fInitialized) return false; - return PalResetEvent(m_hEvent); + return PAL_ResetEvent(m_hEvent); } uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable, bool bAllowReentrantWait) @@ -100,7 +99,16 @@ uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable, bool bAl } } - result = PalCompatibleWaitAny(bAlertable, dwMilliseconds, 1, &m_hEvent, bAllowReentrantWait); +#ifdef TARGET_WINDOWS + if (bAllowReentrantWait) + { + result = PalCompatibleWaitAny(bAlertable, dwMilliseconds, 1, &m_hEvent, TRUE); + } + else +#endif // TARGET_WINDOWS + { + result = PAL_WaitForMultipleObjectsEx(1, &m_hEvent, false, dwMilliseconds, bAlertable); + } if (disablePreemptive) { diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp index 35ddf3d5149955..9dde9aadec88b3 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp @@ -483,7 +483,7 @@ void ep_rt_aot_thread_sleep (uint64_t ns) { STATIC_CONTRACT_NOTHROW; - PalSleep(static_cast(ns/1000000)); + PAL_Sleep(static_cast(ns/1000000)); } uint32_t diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h index 45a5c65f3416a3..039906004dbe41 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.h @@ -792,7 +792,7 @@ EP_RT_DEFINE_THREAD_FUNC (ep_rt_thread_aot_start_session_or_sampling_thread) ep_rt_thread_params_t* thread_params = reinterpret_cast(data); if (thread_params->thread_type == EP_THREAD_TYPE_SESSION) { - // The session drain thread runs a purely native drain loop whose blocking primitives (PalSleep, + // The session drain thread runs a purely native drain loop whose blocking primitives (PAL_Sleep, // CLREventStatic::Wait, CrstStatic::Enter) all tolerate a thread with no runtime Thread, so - like the // CoreCLR native drain thread - it does not attach to the ThreadStore. That lets it start during // diagnostic-port startup suspension, before RuntimeInstance/ThreadStore is initialized, without diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 158c2698eb14c9..fadd62ef90ae7c 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -1287,7 +1287,7 @@ void Thread::EnsureRuntimeInitialized() { while (PalInterlockedCompareExchangePointer((void *volatile *)&g_RuntimeInitializingThread, this, NULL) != NULL) { - PalSleep(1); + PAL_Sleep(1); } if (g_RuntimeInitializationCallback != NULL) diff --git a/src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp index 37648c15db835d..9cd2b0a1f65d6a 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp @@ -83,17 +83,6 @@ using std::nullptr_t; #define PAGE_EXECUTE_READ 0x20 #define PAGE_EXECUTE_READWRITE 0x40 -#define WAIT_OBJECT_0 0 -#define WAIT_TIMEOUT 258 -#define WAIT_FAILED 0xFFFFFFFF - -static const int tccSecondsToMilliSeconds = 1000; -static const int tccSecondsToMicroSeconds = 1000000; -static const int tccSecondsToNanoSeconds = 1000000000; -static const int tccMilliSecondsToMicroSeconds = 1000; -static const int tccMilliSecondsToNanoSeconds = 1000000; -static const int tccMicroSecondsToNanoSeconds = 1000; - void RhFailFast() { // Causes creation of a crash dump if enabled @@ -205,230 +194,6 @@ static void UnmaskActivationSignal() _ASSERTE(sigmaskRet == 0); } -static void TimeSpecAdd(timespec* time, uint32_t milliseconds) -{ - uint64_t nsec = time->tv_nsec + (uint64_t)milliseconds * tccMilliSecondsToNanoSeconds; - if (nsec >= tccSecondsToNanoSeconds) - { - time->tv_sec += nsec / tccSecondsToNanoSeconds; - nsec %= tccSecondsToNanoSeconds; - } - - time->tv_nsec = nsec; -} - -// Convert nanoseconds to the timespec structure -// Parameters: -// nanoseconds - time in nanoseconds to convert -// t - the target timespec structure -static void NanosecondsToTimeSpec(uint64_t nanoseconds, timespec* t) -{ - t->tv_sec = nanoseconds / tccSecondsToNanoSeconds; - t->tv_nsec = nanoseconds % tccSecondsToNanoSeconds; -} - -void ReleaseCondAttr(pthread_condattr_t* condAttr) -{ - int st = pthread_condattr_destroy(condAttr); - ASSERT_MSG(st == 0, "Failed to destroy pthread_condattr_t object"); -} - -class PthreadCondAttrHolder : public Wrapper -{ -public: - PthreadCondAttrHolder(pthread_condattr_t* attrs) - : Wrapper(attrs) - { - } -}; - -class UnixEvent -{ - pthread_cond_t m_condition; - pthread_mutex_t m_mutex; - bool m_manualReset; - bool m_state; - bool m_isValid; - -public: - - UnixEvent(bool manualReset, bool initialState) - : m_manualReset(manualReset), - m_state(initialState), - m_isValid(false) - { - } - - bool Initialize() - { - pthread_condattr_t attrs; - int st = pthread_condattr_init(&attrs); - if (st != 0) - { - ASSERT_UNCONDITIONALLY("Failed to initialize UnixEvent condition attribute"); - return false; - } - - PthreadCondAttrHolder attrsHolder(&attrs); - -#if HAVE_PTHREAD_CONDATTR_SETCLOCK && !HAVE_CLOCK_GETTIME_NSEC_NP - // Ensure that the pthread_cond_timedwait will use CLOCK_MONOTONIC - st = pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); - if (st != 0) - { - ASSERT_UNCONDITIONALLY("Failed to set UnixEvent condition variable wait clock"); - return false; - } -#endif // HAVE_PTHREAD_CONDATTR_SETCLOCK && !HAVE_CLOCK_GETTIME_NSEC_NP - - st = pthread_mutex_init(&m_mutex, NULL); - if (st != 0) - { - ASSERT_UNCONDITIONALLY("Failed to initialize UnixEvent mutex"); - return false; - } - - st = pthread_cond_init(&m_condition, &attrs); - if (st != 0) - { - ASSERT_UNCONDITIONALLY("Failed to initialize UnixEvent condition variable"); - - st = pthread_mutex_destroy(&m_mutex); - ASSERT_MSG(st == 0, "Failed to destroy UnixEvent mutex"); - return false; - } - - m_isValid = true; - - return true; - } - - bool Destroy() - { - bool success = true; - - if (m_isValid) - { - int st = pthread_mutex_destroy(&m_mutex); - ASSERT_MSG(st == 0, "Failed to destroy UnixEvent mutex"); - success = success && (st == 0); - - st = pthread_cond_destroy(&m_condition); - ASSERT_MSG(st == 0, "Failed to destroy UnixEvent condition variable"); - success = success && (st == 0); - } - - return success; - } - - uint32_t Wait(uint32_t milliseconds) - { - timespec endTime; -#if HAVE_CLOCK_GETTIME_NSEC_NP - uint64_t endNanoseconds; - if (milliseconds != INFINITE) - { - uint64_t nanoseconds = (uint64_t)milliseconds * tccMilliSecondsToNanoSeconds; - NanosecondsToTimeSpec(nanoseconds, &endTime); - endNanoseconds = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) + nanoseconds; - } -#elif HAVE_PTHREAD_CONDATTR_SETCLOCK - if (milliseconds != INFINITE) - { - clock_gettime(CLOCK_MONOTONIC, &endTime); - TimeSpecAdd(&endTime, milliseconds); - } -#else -#error "Don't know how to perform timed wait on this platform" -#endif - - int st = 0; - - pthread_mutex_lock(&m_mutex); - while (!m_state) - { - if (milliseconds == INFINITE) - { - st = pthread_cond_wait(&m_condition, &m_mutex); - } - else - { -#if HAVE_CLOCK_GETTIME_NSEC_NP - // Since OSX doesn't support CLOCK_MONOTONIC, we use relative variant of the - // timed wait and we need to handle spurious wakeups properly. - st = pthread_cond_timedwait_relative_np(&m_condition, &m_mutex, &endTime); - if ((st == 0) && !m_state) - { - uint64_t currentNanoseconds = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - if (currentNanoseconds < endNanoseconds) - { - // The wake up was spurious, recalculate the relative endTime - uint64_t remainingNanoseconds = (endNanoseconds - currentNanoseconds); - NanosecondsToTimeSpec(remainingNanoseconds, &endTime); - } - else - { - // Although the timed wait didn't report a timeout, time calculated from the - // mach time shows we have already reached the end time. It can happen if - // the wait was spuriously woken up right before the timeout. - st = ETIMEDOUT; - } - } -#else // HAVE_CLOCK_GETTIME_NSEC_NP - st = pthread_cond_timedwait(&m_condition, &m_mutex, &endTime); -#endif // HAVE_CLOCK_GETTIME_NSEC_NP - } - - if (st != 0) - { - // wait failed or timed out - break; - } - } - - if ((st == 0) && !m_manualReset) - { - // Clear the state for auto-reset events so that only one waiter gets released - m_state = false; - } - - pthread_mutex_unlock(&m_mutex); - - uint32_t waitStatus; - - if (st == 0) - { - waitStatus = WAIT_OBJECT_0; - } - else if (st == ETIMEDOUT) - { - waitStatus = WAIT_TIMEOUT; - } - else - { - waitStatus = WAIT_FAILED; - } - - return waitStatus; - } - - void Set() - { - pthread_mutex_lock(&m_mutex); - m_state = true; - // Unblock all threads waiting for the condition variable - pthread_cond_broadcast(&m_condition); - pthread_mutex_unlock(&m_mutex); - } - - void Reset() - { - pthread_mutex_lock(&m_mutex); - m_state = false; - pthread_mutex_unlock(&m_mutex); - } -}; - // This functions configures behavior of the signals that are not // related to hardware exception handling. void ConfigureSignals() @@ -712,28 +477,6 @@ UInt32_BOOL PalMarkThunksAsValidCallTargets( return ret == 0 ? UInt32_TRUE : UInt32_FALSE; } -void PalSleep(uint32_t milliseconds) -{ -#if HAVE_CLOCK_NANOSLEEP - timespec endTime; - clock_gettime(CLOCK_MONOTONIC, &endTime); - TimeSpecAdd(&endTime, milliseconds); - while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &endTime, NULL) == EINTR) - { - } -#else // HAVE_CLOCK_NANOSLEEP - timespec requested; - requested.tv_sec = milliseconds / tccSecondsToMilliSeconds; - requested.tv_nsec = (milliseconds - requested.tv_sec * tccSecondsToMilliSeconds) * tccMilliSecondsToNanoSeconds; - - timespec remaining; - while (nanosleep(&requested, &remaining) == EINTR) - { - requested = remaining; - } -#endif // HAVE_CLOCK_NANOSLEEP -} - UInt32_BOOL __stdcall PalSwitchToThread() { // sched_yield yields to another thread in the current process. @@ -750,35 +493,6 @@ UInt32_BOOL PalAreShadowStacksEnabled() return false; } -UInt32_BOOL PalCloseHandle(HANDLE handle) -{ - if ((handle == NULL) || (handle == INVALID_HANDLE_VALUE)) - { - return UInt32_FALSE; - } - - UnixEvent* event = (UnixEvent*)handle; - bool success = event->Destroy(); - delete event; - - return success ? UInt32_TRUE : UInt32_FALSE; -} - -HANDLE PalCreateEventW(_In_opt_ LPSECURITY_ATTRIBUTES pEventAttributes, UInt32_BOOL manualReset, UInt32_BOOL initialState, _In_opt_z_ const WCHAR* pName) -{ - UnixEvent* event = new (nothrow) UnixEvent(manualReset, initialState); - if (event == NULL) - { - return INVALID_HANDLE_VALUE; - } - if (!event->Initialize()) - { - delete event; - return INVALID_HANDLE_VALUE; - } - return (HANDLE)event; -} - typedef uint32_t(__stdcall *BackgroundCallback)(_In_opt_ void* pCallbackContext); bool PalStartBackgroundWork(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext, UInt32_BOOL highPriority) @@ -1013,20 +727,6 @@ uint32_t PalGetCurrentProcessId() return getpid(); } -UInt32_BOOL PalSetEvent(HANDLE event) -{ - UnixEvent* unixEvent = (UnixEvent*)event; - unixEvent->Set(); - return UInt32_TRUE; -} - -UInt32_BOOL PalResetEvent(HANDLE event) -{ - UnixEvent* unixEvent = (UnixEvent*)event; - unixEvent->Reset(); - return UInt32_TRUE; -} - uint32_t PalGetEnvironmentVariable(const char * name, char * buffer, uint32_t size) { const char* value = getenv(name); @@ -1166,20 +866,6 @@ void PalHijack(Thread* pThreadToHijack) } #endif // FEATURE_HIJACK -uint32_t PalWaitForSingleObjectEx(HANDLE handle, uint32_t milliseconds, UInt32_BOOL alertable) -{ - UnixEvent* unixEvent = (UnixEvent*)handle; - return unixEvent->Wait(milliseconds); -} - -uint32_t PalCompatibleWaitAny(UInt32_BOOL alertable, uint32_t timeout, uint32_t handleCount, HANDLE* pHandles, UInt32_BOOL allowReentrantWait) -{ - // Only a single handle wait for event is supported - ASSERT(handleCount == 1); - - return PalWaitForSingleObjectEx(pHandles[0], timeout, alertable); -} - HANDLE PalCreateLowMemoryResourceNotification() { return NULL; diff --git a/src/coreclr/nativeaot/Runtime/windows/PalMinWin.cpp b/src/coreclr/nativeaot/Runtime/windows/PalMinWin.cpp index 789f9269755d84..c56d5b1e72219c 100644 --- a/src/coreclr/nativeaot/Runtime/windows/PalMinWin.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/PalMinWin.cpp @@ -259,7 +259,7 @@ uint32_t PalCompatibleWaitAny(UInt32_BOOL alertable, uint32_t timeout, uint32_t { if (!allowReentrantWait) { - return WaitForMultipleObjectsEx(handleCount, pHandles, FALSE, timeout, alertable); + return PAL_WaitForMultipleObjectsEx(handleCount, pHandles, false, timeout, alertable); } else { @@ -287,21 +287,11 @@ HANDLE PalCreateLowMemoryResourceNotification() return CreateMemoryResourceNotification(LowMemoryResourceNotification); } -void PalSleep(uint32_t milliseconds) -{ - return Sleep(milliseconds); -} - UInt32_BOOL PalSwitchToThread() { return SwitchToThread(); } -HANDLE PalCreateEventW(_In_opt_ LPSECURITY_ATTRIBUTES pEventAttributes, UInt32_BOOL manualReset, UInt32_BOOL initialState, _In_opt_z_ LPCWSTR pName) -{ - return CreateEventW(pEventAttributes, manualReset, initialState, pName); -} - UInt32_BOOL PalAreShadowStacksEnabled() { #if defined(TARGET_AMD64) @@ -1042,11 +1032,6 @@ uint16_t PalCaptureStackBackTrace(uint32_t arg1, uint32_t arg2, void* arg3, uint return res; } -UInt32_BOOL PalCloseHandle(HANDLE arg1) -{ - return ::CloseHandle(arg1); -} - uint32_t PalGetCurrentProcessId() { return static_cast(::GetCurrentProcessId()); @@ -1056,18 +1041,3 @@ uint32_t PalGetEnvironmentVariable(_In_opt_ LPCWSTR lpName, _Out_writes_to_opt_( { return ::GetEnvironmentVariableW(lpName, lpBuffer, nSize); } - -UInt32_BOOL PalResetEvent(HANDLE arg1) -{ - return ::ResetEvent(arg1); -} - -UInt32_BOOL PalSetEvent(HANDLE arg1) -{ - return ::SetEvent(arg1); -} - -uint32_t PalWaitForSingleObjectEx(HANDLE arg1, uint32_t arg2, UInt32_BOOL arg3) -{ - return ::WaitForSingleObjectEx(arg1, arg2, arg3); -} diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index a4f4e64848bd47..5a727b4a398073 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -582,54 +582,6 @@ GetTempPathA( #define GetTempPath GetTempPathA #endif -PALIMPORT -HANDLE -PALAPI -CreateEventW( - IN LPSECURITY_ATTRIBUTES lpEventAttributes, - IN BOOL bManualReset, - IN BOOL bInitialState, - IN LPCWSTR lpName); - -PALIMPORT -HANDLE -PALAPI -CreateEventExW( - IN LPSECURITY_ATTRIBUTES lpEventAttributes, - IN LPCWSTR lpName, - IN DWORD dwFlags, - IN DWORD dwDesiredAccess); - -// CreateEventExW: dwFlags -#define CREATE_EVENT_MANUAL_RESET ((DWORD)0x1) -#define CREATE_EVENT_INITIAL_SET ((DWORD)0x2) - -#define CreateEvent CreateEventW - -PALIMPORT -BOOL -PALAPI -SetEvent( - IN HANDLE hEvent); - -PALIMPORT -BOOL -PALAPI -ResetEvent( - IN HANDLE hEvent); - -PALIMPORT -HANDLE -PALAPI -OpenEventW( - IN DWORD dwDesiredAccess, - IN BOOL bInheritHandle, - IN LPCWSTR lpName); - -#ifdef UNICODE -#define OpenEvent OpenEventW -#endif - PALIMPORT DWORD PALAPI @@ -687,31 +639,6 @@ TerminateProcess( #define INFINITE 0xFFFFFFFF // Infinite timeout -PALIMPORT -DWORD -PALAPI -WaitForSingleObject( - IN HANDLE hHandle, - IN DWORD dwMilliseconds); - -PALIMPORT -DWORD -PALAPI -WaitForSingleObjectEx( - IN HANDLE hHandle, - IN DWORD dwMilliseconds, - IN BOOL bAlertable); - -PALIMPORT -DWORD -PALAPI -WaitForMultipleObjectsEx( - IN DWORD nCount, - IN CONST HANDLE *lpHandles, - IN BOOL bWaitAll, - IN DWORD dwMilliseconds, - IN BOOL bAlertable); - #define DUPLICATE_CLOSE_SOURCE 0x00000001 #define DUPLICATE_SAME_ACCESS 0x00000002 @@ -727,19 +654,6 @@ DuplicateHandle( IN BOOL bInheritHandle, IN DWORD dwOptions); -PALIMPORT -VOID -PALAPI -Sleep( - IN DWORD dwMilliseconds); - -PALIMPORT -DWORD -PALAPI -SleepEx( - IN DWORD dwMilliseconds, - IN BOOL bAlertable); - PALIMPORT BOOL PALAPI @@ -2644,9 +2558,6 @@ typedef struct _RUNTIME_FUNCTION { #define READ_CONTROL (0x00020000L) #define MAXIMUM_ALLOWED (0x02000000L) -#define EVENT_MODIFY_STATE (0x0002) -#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3) - #define MUTANT_QUERY_STATE (0x0001) #define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE) #define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS diff --git a/src/coreclr/pal/src/CMakeLists.txt b/src/coreclr/pal/src/CMakeLists.txt index 42ba78af10f4c5..75da7a8bd612c3 100644 --- a/src/coreclr/pal/src/CMakeLists.txt +++ b/src/coreclr/pal/src/CMakeLists.txt @@ -196,10 +196,6 @@ set(SOURCES safecrt/wcsncat_s.cpp safecrt/wcsncpy_s.cpp safecrt/wmakepath_s.cpp - synchobj/event.cpp - synchmgr/synchcontrollers.cpp - synchmgr/synchmanager.cpp - synchmgr/wait.cpp thread/process.cpp thread/thread.cpp thread/threadsusp.cpp diff --git a/src/coreclr/pal/src/file/file.cpp b/src/coreclr/pal/src/file/file.cpp index 56b483b8496de7..30b16e472b1944 100644 --- a/src/coreclr/pal/src/file/file.cpp +++ b/src/coreclr/pal/src/file/file.cpp @@ -71,10 +71,7 @@ CObjectType CorUnix::otFile( NULL, // No immutable data copy routine NULL, // No immutable data cleanup routine sizeof(CFileProcessLocalData), - CFileProcessLocalDataCleanupRoutine, - CObjectType::UnwaitableObject, - CObjectType::SignalingNotApplicable, - CObjectType::ThreadReleaseNotApplicable + CFileProcessLocalDataCleanupRoutine ); CAllowedObjectTypes CorUnix::aotFile(otiFile); diff --git a/src/coreclr/pal/src/include/pal/corunix.hpp b/src/coreclr/pal/src/include/pal/corunix.hpp index cddda4626fa0aa..c4e44c9922991b 100644 --- a/src/coreclr/pal/src/include/pal/corunix.hpp +++ b/src/coreclr/pal/src/include/pal/corunix.hpp @@ -157,9 +157,7 @@ namespace CorUnix enum PalObjectTypeId { - otiAutoResetEvent = 0, - otiManualResetEvent, - otiFile, + otiFile = 0, otiFileMapping, otiSocket, otiThread, @@ -177,55 +175,8 @@ namespace CorUnix // The data size members control how much space will be allocated for // instances of this object. Any or all of those members may be 0. // - // dwSupportedAccessRights is the mask of valid access bits for this - // object type. Supported generic rights should not be included in - // this member. - // - // The generic access rights mapping (structure TBD) defines how the - // supported generic access rights (e.g., GENERIC_READ) map to the - // specific access rights for this object type. - // - // If the object may be waited on eSynchronizationSupport should be - // WaitableObject. (Note that this implies that object type supports - // the SYNCHRONIZE access right.) - // - // The remaining members describe the wait-object semantics for the - // object type when eSynchronizationSupport is WaitableObject: - // - // * eSignalingSemantics: SingleTransitionObject for objects that, once - // they transition to the signaled state, can never transition back to - // the unsignaled state (e.g., processes and threads) - // - // * eThreadReleaseSemantics: if ThreadReleaseAltersSignalCount the object's - // signal count is decremented when a waiting thread is released; otherwise, - // the signal count is not modified (as is desired for a manual reset event). - // Must be ThreadReleaseHasNoSideEffects if eSignalingSemantics is - // SingleTransitionObject - // - class CObjectType { - public: - enum SynchronizationSupport - { - WaitableObject, - UnwaitableObject - }; - - enum SignalingSemantics - { - ObjectCanBeUnsignaled, - SingleTransitionObject, - SignalingNotApplicable - }; - - enum ThreadReleaseSemantics - { - ThreadReleaseAltersSignalCount, - ThreadReleaseHasNoSideEffects, - ThreadReleaseNotApplicable - }; - private: // @@ -242,10 +193,6 @@ namespace CorUnix OBJECT_IMMUTABLE_DATA_CLEANUP_ROUTINE m_pImmutableDataCleanupRoutine; DWORD m_dwProcessLocalDataSize; OBJECT_PROCESS_LOCAL_DATA_CLEANUP_ROUTINE m_pProcessLocalDataCleanupRoutine; - // Generic access rights mapping - SynchronizationSupport m_eSynchronizationSupport; - SignalingSemantics m_eSignalingSemantics; - ThreadReleaseSemantics m_eThreadReleaseSemantics; public: @@ -256,10 +203,7 @@ namespace CorUnix OBJECT_IMMUTABLE_DATA_COPY_ROUTINE pImmutableDataCopyRoutine, OBJECT_IMMUTABLE_DATA_CLEANUP_ROUTINE pImmutableDataCleanupRoutine, DWORD dwProcessLocalDataSize, - OBJECT_PROCESS_LOCAL_DATA_CLEANUP_ROUTINE pProcessLocalDataCleanupRoutine, - SynchronizationSupport eSynchronizationSupport, - SignalingSemantics eSignalingSemantics, - ThreadReleaseSemantics eThreadReleaseSemantics + OBJECT_PROCESS_LOCAL_DATA_CLEANUP_ROUTINE pProcessLocalDataCleanupRoutine ) : m_eTypeId(eTypeId), @@ -268,10 +212,7 @@ namespace CorUnix m_pImmutableDataCopyRoutine(pImmutableDataCopyRoutine), m_pImmutableDataCleanupRoutine(pImmutableDataCleanupRoutine), m_dwProcessLocalDataSize(dwProcessLocalDataSize), - m_pProcessLocalDataCleanupRoutine(pProcessLocalDataCleanupRoutine), - m_eSynchronizationSupport(eSynchronizationSupport), - m_eSignalingSemantics(eSignalingSemantics), - m_eThreadReleaseSemantics(eThreadReleaseSemantics) + m_pProcessLocalDataCleanupRoutine(pProcessLocalDataCleanupRoutine) { s_rgotIdMapping[eTypeId] = this; }; @@ -357,31 +298,6 @@ namespace CorUnix return m_pProcessLocalDataCleanupRoutine; } - // Generic access rights mapping - - SynchronizationSupport - GetSynchronizationSupport( - void - ) - { - return m_eSynchronizationSupport; - }; - - SignalingSemantics - GetSignalingSemantics( - void - ) - { - return m_eSignalingSemantics; - }; - - ThreadReleaseSemantics - GetThreadReleaseSemantics( - void - ) - { - return m_eThreadReleaseSemantics; - }; }; class CAllowedObjectTypes @@ -465,126 +381,6 @@ namespace CorUnix }; }; - // - // ISynchStateController is used to modify any object's synchronization - // state. It is intended to be used from within the APIs exposed for - // various objects (e.g., SetEvent, ReleaseMutex, etc.). - // - // Each ISynchStateController instance implicitly holds what should be - // viewed as the global dispatcher lock, and as such should be released - // as quickly as possible. An ISynchStateController instance is bound to - // the thread that requested it; it may not be passed to a different - // thread. - // - - class ISynchStateController - { - public: - - virtual - PAL_ERROR - GetSignalCount( - LONG *plSignalCount - ) = 0; - - virtual - PAL_ERROR - SetSignalCount( - LONG lNewCount - ) = 0; - - virtual - PAL_ERROR - IncrementSignalCount( - LONG lAmountToIncrement - ) = 0; - - virtual - PAL_ERROR - DecrementSignalCount( - LONG lAmountToDecrement - ) = 0; - - virtual - void - ReleaseController( - void - ) = 0; - }; - - // - // ISynchWaitController is used to indicate a thread's desire to wait for - // an object (which possibly includes detecting instances where the wait - // can be satisfied without blocking). It is intended to be used by object - // wait function (WaitForSingleObject, etc.). - // - // Each ISynchWaitController instance implicitly holds what should be - // viewed as the global dispatcher lock, and as such should be released - // as quickly as possible. An ISynchWaitController instance is bound to - // the thread that requested it; it may not be passed to a different - // thread. - // - // A thread may hold multiple ISynchWaitController instances - // simultaneously. - // - - enum WaitType - { - SingleObject, - MultipleObjectsWaitOne, - MultipleObjectsWaitAll - }; - - class ISynchWaitController - { - public: - - // - // CanThreadWaitWithoutBlocking informs the caller if a wait - // operation may succeed immediately, but does not actually - // alter any object state. ReleaseWaitingThreadWithoutBlocking - // alters the object state, and will return an error if it is - // not possible for the wait to be immediately satisfied. - // - - virtual - PAL_ERROR - CanThreadWaitWithoutBlocking( - bool *pfCanWaitWithoutBlocking // OUT - ) = 0; - - virtual - PAL_ERROR - ReleaseWaitingThreadWithoutBlocking( - ) = 0; - - // - // dwIndex is intended for MultipleObjectsWaitOne situations. The - // index for the object that becomes signaled and satisfies the - // wait will be returned in the call to BlockThread. - // - - virtual - PAL_ERROR - RegisterWaitingThread( - WaitType eWaitType, - DWORD dwIndex - ) = 0; - - // - // Why is there no unregister waiting thread routine? Unregistration - // is the responsibility of the synchronization provider, not the - // implementation of the wait object routines. (I can be convinced - // that this isn't the best approach, though...) - // - - virtual - void - ReleaseController( - void - ) = 0; - }; - enum LockType { ReadLock, @@ -649,41 +445,6 @@ namespace CorUnix void **ppvProcessLocalData // OUT ) = 0; - // - // The following two routines obtain the global dispatcher lock. - // If a thread needs to make use of a synchronization interface - // and examine object data it must obtain the synchronization - // interface first. A thread is allowed to hold synchronization - // interfaces for multiple objects at the same time if it obtains - // all of the interfaces through a single call (see IPalSynchronizationManager - // below). - // - // The single-call restriction allows the underlying implementation - // to possibly segement the global dispatcher lock. If this restriction - // were not in place (i.e., if a single thread were allowed to call - // GetSynchXXXController for multiple objects) no such segmentation - // would be possible as there would be no way know in what order a - // thread would choose to obtain the controllers. - // - // Note: this design precludes simultaneous acquisition of both - // the state and wait controller for an object but there are - // currently no places where doing so would be necessary. - // - - virtual - PAL_ERROR - GetSynchStateController( - CPalThread *pThread, // IN, OPTIONAL - ISynchStateController **ppStateController // OUT - ) = 0; - - virtual - PAL_ERROR - GetSynchWaitController( - CPalThread *pThread, // IN, OPTIONAL - ISynchWaitController **ppWaitController // OUT - ) = 0; - virtual DWORD AddReference( @@ -696,19 +457,6 @@ namespace CorUnix CPalThread *pThread ) = 0; - // - // This routine is only for use by the synchronization manager - // (specifically, for GetSynch*ControllersForObjects). The - // caller must have acquired the appropriate lock before - // (whatever exactly that must be) before calling this routine. - // - - virtual - PAL_ERROR - GetObjectSynchData( - VOID **ppvSynchData // OUT - ) = 0; - }; class IPalProcess @@ -726,7 +474,7 @@ namespace CorUnix public: // - // Object creation (e.g., what is done by CreateEvent) is a two step + // Object creation is a two step // process. First, the new object is allocated and the initial // properties set (e.g., initially signaled). Next, the object is // registered, yielding a handle. If an object of the same name @@ -759,12 +507,9 @@ namespace CorUnix // caller, therefore, is responsible for releasing the // latter. // - // For named object pAllowedTypes specifies what type of - // existing objects can be returned in ppRegisteredObjects. - // This is primarily intended for CreateEvent, so that - // a ManualResetEvent can be returned when attempting to - // register an AutoResetEvent (and vice-versa). pAllowedTypes - // must include the type of pObjectToRegister. + // For a named object pAllowedTypes specifies what type of existing + // objects can be returned in ppRegisteredObjects. pAllowedTypes must + // include the type of pObjectToRegister. // virtual @@ -837,144 +582,10 @@ namespace CorUnix IPalObject **ppObject // OUT ) = 0; - // - // This routine is intended for WaitForMultipleObjects[Ex] - // - - virtual - PAL_ERROR - ReferenceMultipleObjectsByHandleArray( - CPalThread *pThread, // IN, OPTIONAL - HANDLE rghHandlesToReference[], - DWORD dwHandleCount, - CAllowedObjectTypes *pAllowedTypes, - IPalObject *rgpObjects[] // OUT - ) = 0; }; extern IPalObjectManager *g_pObjectManager; - enum ThreadWakeupReason - { - WaitSucceeded, - WaitTimeout, - WaitFailed - }; - - class IPalSynchronizationManager - { - public: - - // - // A thread calls BlockThread to put itself to sleep after it has - // registered itself with the objects it is to wait on. A thread - // need not have registered with any objects, as would occur in - // the implementation of Sleep[Ex]. - // - // Needless to say a thread must not be holding any PAL locks - // directly or implicitly (e.g., by holding a reference to a - // synchronization controller) when it calls this method. - // - - virtual - PAL_ERROR - BlockThread( - CPalThread *pCurrentThread, - DWORD dwTimeout, - bool fIsSleep, - ThreadWakeupReason *peWakeupReason, // OUT - DWORD *pdwSignaledObject // OUT - ) = 0; - - - // - // This routine is primarily meant for use by WaitForMultipleObjects[Ex]. - // The caller must individually release each of the returned controller - // interfaces. - // - - virtual - PAL_ERROR - GetSynchWaitControllersForObjects( - CPalThread *pThread, - IPalObject *rgObjects[], - DWORD dwObjectCount, - ISynchWaitController *rgControllers[] - ) = 0; - - virtual - PAL_ERROR - GetSynchStateControllersForObjects( - CPalThread *pThread, - IPalObject *rgObjects[], - DWORD dwObjectCount, - ISynchStateController *rgControllers[] - ) = 0; - - // - // These following routines are meant for use only by IPalObject - // implementations. The first two routines are used to - // allocate and free an object's synchronization state; the third - // is called during object promotion. - // - - virtual - PAL_ERROR - AllocateObjectSynchData( - CObjectType *pObjectType, - VOID **ppvSynchData // OUT - ) = 0; - - virtual - void - FreeObjectSynchData( - CObjectType *pObjectType, - VOID *pvSynchData - ) = 0; - - // - // The next two routines provide access to the process-wide - // synchronization lock - // - - virtual - void - AcquireProcessLock( - CPalThread *pThread - ) = 0; - - virtual - void - ReleaseProcessLock( - CPalThread *pThread - ) = 0; - - // - // The final routines are used by IPalObject::GetSynchStateController - // and IPalObject::GetSynchWaitController - // - - virtual - PAL_ERROR - CreateSynchStateController( - CPalThread *pThread, // IN, OPTIONAL - CObjectType *pObjectType, - VOID *pvSynchData, - ISynchStateController **ppStateController // OUT - ) = 0; - - virtual - PAL_ERROR - CreateSynchWaitController( - CPalThread *pThread, // IN, OPTIONAL - CObjectType *pObjectType, - VOID *pvSynchData, - ISynchWaitController **ppWaitController // OUT - ) = 0; - }; - - extern IPalSynchronizationManager *g_pSynchronizationManager; - } #endif // _CORUNIX_H diff --git a/src/coreclr/pal/src/include/pal/event.hpp b/src/coreclr/pal/src/include/pal/event.hpp deleted file mode 100644 index 313e7e69433ede..00000000000000 --- a/src/coreclr/pal/src/include/pal/event.hpp +++ /dev/null @@ -1,59 +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: - - event.hpp - -Abstract: - - Event object structure definition. - - - ---*/ - -#ifndef _PAL_EVENT_H_ -#define _PAL_EVENT_H_ - -#include "corunix.hpp" - -namespace CorUnix -{ - extern CObjectType otManualResetEvent; - extern CObjectType otAutoResetEvent; - - PAL_ERROR - InternalCreateEvent( - CPalThread *pThread, - LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, - BOOL bInitialState, - LPCWSTR lpName, - HANDLE *phEvent - ); - - PAL_ERROR - InternalSetEvent( - CPalThread *pThread, - HANDLE hEvent, - BOOL fSetEvent - ); - -} - -#endif //PAL_EVENT_H_ - - - - - - - - - - diff --git a/src/coreclr/pal/src/include/pal/synchcache.hpp b/src/coreclr/pal/src/include/pal/synchcache.hpp deleted file mode 100644 index aee9f67b3df06b..00000000000000 --- a/src/coreclr/pal/src/include/pal/synchcache.hpp +++ /dev/null @@ -1,392 +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: - - include/pal/synchcache.hpp - -Abstract: - Simple look-aside cache for unused objects with default - constructor or no constructor ---*/ - -#ifndef _SYNCH_CACHE_H_ -#define _SYNCH_CACHE_H_ - -#include "pal/thread.hpp" -#include - -namespace CorUnix -{ - template class CSynchCache - { - typedef union _USynchCacheStackNode - { - union _USynchCacheStackNode * next; - BYTE objraw[sizeof(T)]; - } USynchCacheStackNode; - - static const int MaxDepth = 256; - - USynchCacheStackNode* m_pHead; - minipal_mutex m_cs; - int m_iDepth; - int m_iMaxDepth; -#ifdef _DEBUG - int m_iMaxTrackedDepth; -#endif - - void Lock(CPalThread * pthrCurrent) - { minipal_mutex_enter(&m_cs); } - void Unlock(CPalThread * pthrCurrent) - { minipal_mutex_leave(&m_cs); } - - public: - CSynchCache(int iMaxDepth = MaxDepth) : - m_pHead(NULL), - m_iDepth(0), - m_iMaxDepth(iMaxDepth) -#ifdef _DEBUG - ,m_iMaxTrackedDepth(0) -#endif - { - minipal_mutex_init(&m_cs); - if (m_iMaxDepth < 0) - { - m_iMaxDepth = 0; - } - } - - ~CSynchCache() - { - Flush(NULL, true); - minipal_mutex_destroy(&m_cs); - } - -#ifdef _DEBUG - int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; } -#endif - - T * Get(CPalThread * pthrCurrent) - { - T * pObj = NULL; - - Get(pthrCurrent, 1, &pObj); - return pObj; - } - - int Get(CPalThread * pthrCurrent, int n, T ** ppObjs) - { - void * pvObjRaw; - USynchCacheStackNode * pNode; - int i = 0,j; - - Lock(pthrCurrent); - pNode = m_pHead; - while (pNode && i < n) - { - ppObjs[i] = (T *)pNode; - pNode = pNode->next; - i++; - } - m_pHead = pNode; - m_iDepth -= i; - -#ifdef _DEBUG - if (NULL == m_pHead && m_iDepth != 0) - { - // Can't use ASSERT here, since this is header - // is included by other headers with inline methods - // which causes template instatiation in the header - // where the DEBUG CHANNEL is not defined and cannot - // be defined - fprintf(stderr,"SYNCCACHE: Invalid cache depth value"); - DebugBreak(); - } -#endif // _DEBUG - - Unlock(pthrCurrent); - - for (j=i;j(pvObjRaw); - } - - for (i=0;i(pobj); - - if (NULL == pobj) - { - return; - } - - pobj->~T(); - - Lock(pthrCurrent); - if (m_iDepth < m_iMaxDepth) - { -#ifdef _DEBUG - if (m_iDepth > m_iMaxTrackedDepth) - { - m_iMaxTrackedDepth = m_iDepth; - } -#endif - pNode->next = m_pHead; - m_pHead = pNode; - m_iDepth++; - } - else - { - delete pNode; - } - Unlock(pthrCurrent); - } - -private: - void Flush(CPalThread * pthrCurrent, bool fDontLock = false) - { - USynchCacheStackNode * pNode, * pTemp; - - if (!fDontLock) - { - Lock(pthrCurrent); - } - pNode = m_pHead; - m_pHead = NULL; - m_iDepth = 0; - if (!fDontLock) - { - Unlock(pthrCurrent); - } - - while (pNode) - { - pTemp = pNode; - pNode = pNode->next; - delete (char *)pTemp; - } - } - }; - - template class CSHRSynchCache - { - union _USHRSynchCacheStackNode; // fwd declaration - typedef struct _SHRCachePTRs - { - union _USHRSynchCacheStackNode * pNext; - SharedID shrid; - } SHRCachePTRs; - typedef union _USHRSynchCacheStackNode - { - SHRCachePTRs pointers; - BYTE objraw[sizeof(T)]; - } USHRSynchCacheStackNode; - - static const int MaxDepth = 256; - static const int PreAllocFactor = 10; // Everytime a Get finds no available - // cached raw instances, it preallocates - // MaxDepth/PreAllocFactor new raw - // instances and store them into the - // cache before continuing - - USHRSynchCacheStackNode* m_pHead; - minipal_mutex m_cs; - int m_iDepth; - int m_iMaxDepth; -#ifdef _DEBUG - int m_iMaxTrackedDepth; -#endif - - void Lock(CPalThread * pthrCurrent) - { minipal_mutex_enter(&m_cs); } - void Unlock(CPalThread * pthrCurrent) - { minipal_mutex_leave(&m_cs); } - - public: - CSHRSynchCache(int iMaxDepth = MaxDepth) : - m_pHead(NULL), - m_iDepth(0), - m_iMaxDepth(iMaxDepth) -#ifdef _DEBUG - ,m_iMaxTrackedDepth(0) -#endif - { - minipal_mutex_init(&m_cs); - if (m_iMaxDepth < 0) - { - m_iMaxDepth = 0; - } - } - - ~CSHRSynchCache() - { - Flush(NULL, true); - minipal_mutex_destroy(&m_cs); - } - -#ifdef _DEBUG - int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; } -#endif - - SharedID Get(CPalThread * pthrCurrent) - { - SharedID shridObj = NULL; - - Get(pthrCurrent, 1, &shridObj); - return shridObj; - } - - int Get(CPalThread * pthrCurrent, int n, SharedID * shridpObjs) - { - SharedID shridObj; - void * pvObjRaw = NULL; - USHRSynchCacheStackNode * pNode; - int i = 0, j, k; - - Lock(pthrCurrent); - pNode = m_pHead; - while (pNode && i < n) - { - shridpObjs[i] = pNode->pointers.shrid; - pvObjRaw = (void *)pNode; - pNode = pNode->pointers.pNext; - i++; - } - m_pHead = pNode; - m_iDepth -= i; - -#ifdef _DEBUG - if (NULL == m_pHead && m_iDepth != 0) - { - // Can't use ASSERT here, since this is header - // (see comment above) - fprintf(stderr,"SYNCCACHE: Invalid cache depth value"); - DebugBreak(); - } -#endif // _DEBUG - - if (0 == m_iDepth) - { - for (k=0; k(pNode), 0, sizeof(USHRSynchCacheStackNode)); -#endif - pNode->pointers.shrid = shridObj; - pNode->pointers.pNext = m_pHead; - m_pHead = pNode; - m_iDepth++; - } - } - - Unlock(pthrCurrent); - - for (j=i;j(pNode); - - pObj->~T(); - - pNode->pointers.shrid = shridObj; - - Lock(pthrCurrent); - if (m_iDepth < m_iMaxDepth) - { - m_iDepth++; -#ifdef _DEBUG - if (m_iDepth > m_iMaxTrackedDepth) - { - m_iMaxTrackedDepth = m_iDepth; - } -#endif - pNode->pointers.pNext = m_pHead; - m_pHead = pNode; - } - else - { - free(shridObj); - } - Unlock(pthrCurrent); - } - -private: - void Flush(CPalThread * pthrCurrent, bool fDontLock = false) - { - USHRSynchCacheStackNode * pNode, * pTemp; - SharedID shridTemp; - - if (!fDontLock) - { - Lock(pthrCurrent); - } - pNode = m_pHead; - m_pHead = NULL; - m_iDepth = 0; - if (!fDontLock) - { - Unlock(pthrCurrent); - } - - while (pNode) - { - pTemp = pNode; - pNode = pNode->pointers.pNext; - shridTemp = pTemp->pointers.shrid; - free(shridTemp); - } - } - }; -} - -#endif // _SYNCH_CACHE_H_ - diff --git a/src/coreclr/pal/src/include/pal/synchobjects.hpp b/src/coreclr/pal/src/include/pal/synchobjects.hpp deleted file mode 100644 index b7d93660ded768..00000000000000 --- a/src/coreclr/pal/src/include/pal/synchobjects.hpp +++ /dev/null @@ -1,168 +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: - - include/pal/synchobjects.hpp - -Abstract: - Header file for synchronization manager and controllers - - - ---*/ - -#ifndef _SINCHOBJECTS_HPP_ -#define _SINCHOBJECTS_HPP_ - -#include "corunix.hpp" -#include "threadinfo.hpp" -#include "list.h" - -#include - -typedef LPVOID SharedID; -#define SharedIDToPointer(shID) reinterpret_cast(shID) -#define SharedIDToTypePointer(TYPE,shID) reinterpret_cast(shID) - -namespace CorUnix -{ - DWORD InternalWaitForMultipleObjectsEx( - CPalThread * pthrCurrent, - DWORD nCount, - CONST HANDLE *lpHandles, - BOOL bWaitAll, - DWORD dwMilliseconds); - - PAL_ERROR InternalSleepEx( - CPalThread * pthrCurrent, - DWORD dwMilliseconds); - - enum THREAD_STATE - { - TS_IDLE, - TS_STARTING, - TS_RUNNING, - TS_FAILED, - TS_DONE, - }; - - // forward declarations - struct _ThreadWaitInfo; - struct _WaitingThreadsListNode; - class CSynchData; - - typedef struct _WaitingThreadsListNode * PWaitingThreadsListNode; - - typedef struct _ThreadWaitInfo - { - WaitType wtWaitType; - LONG lObjCount; - CPalThread * pthrOwner; - PWaitingThreadsListNode rgpWTLNodes[MAXIMUM_WAIT_OBJECTS]; - - _ThreadWaitInfo() : wtWaitType(SingleObject), - lObjCount(0), - pthrOwner(NULL) {} - } ThreadWaitInfo; - - typedef struct _ThreadNativeWaitData - { - pthread_mutex_t mutex; - pthread_cond_t cond; - int iPred; - DWORD dwObjectIndex; - ThreadWakeupReason twrWakeupReason; - bool fInitialized; - - _ThreadNativeWaitData() : - iPred(0), - dwObjectIndex(0), - twrWakeupReason(WaitSucceeded), - fInitialized(false) - { - } - - ~_ThreadNativeWaitData(); - } ThreadNativeWaitData; - - class CThreadSynchronizationInfo : public CThreadInfoInitializer - { - friend class CPalSynchronizationManager; - friend class CSynchWaitController; - - THREAD_STATE m_tsThreadState; - SharedID m_shridWaitAwakened; - LONG m_lLocalSynchLockCount; - LIST_ENTRY m_leOwnedObjsList; - - ThreadNativeWaitData m_tnwdNativeData; - ThreadWaitInfo m_twiWaitInfo; - -#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - static const int PendingSignalingsArraySize = 10; - LONG m_lPendingSignalingCount; - CPalThread * m_rgpthrPendingSignalings[PendingSignalingsArraySize]; - LIST_ENTRY m_lePendingSignalingsOverflowList; -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - - public: - - CThreadSynchronizationInfo(); - virtual ~CThreadSynchronizationInfo(); - - // - // CThreadInfoInitializer methods - // - virtual PAL_ERROR InitializePreCreate(void); - - virtual PAL_ERROR InitializePostCreate( - CPalThread *pthrCurrent, - SIZE_T threadId, - DWORD dwLwpId - ); - - THREAD_STATE GetThreadState(void) - { - return m_tsThreadState; - }; - - void SetThreadState(THREAD_STATE tsThreadState) - { - m_tsThreadState = tsThreadState; - }; - - ThreadNativeWaitData * GetNativeData() - { - return &m_tnwdNativeData; - } - -#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - PAL_ERROR RunDeferredThreadConditionSignalings(); -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - - // The following methods provide access to the native wait lock for - // those implementations that need a lock to protect the support for - // native thread blocking (e.g.: pthread conditions) - void AcquireNativeWaitLock(void); - void ReleaseNativeWaitLock(void); - bool TryAcquireNativeWaitLock(void); - }; - - class CPalSynchMgrController - { - public: - static IPalSynchronizationManager * CreatePalSynchronizationManager(); - - static PAL_ERROR PrepareForShutdown(void); - - static PAL_ERROR Shutdown(CPalThread *pthrCurrent, bool fFullCleanup); - }; -} - -#endif // _SINCHOBJECTS_HPP_ - diff --git a/src/coreclr/pal/src/include/pal/thread.hpp b/src/coreclr/pal/src/include/pal/thread.hpp index d7b159f631c502..7f9a905e22bb24 100644 --- a/src/coreclr/pal/src/include/pal/thread.hpp +++ b/src/coreclr/pal/src/include/pal/thread.hpp @@ -28,13 +28,21 @@ Module Name: #include "threadsusp.hpp" #include "threadinfo.hpp" -#include "synchobjects.hpp" #include #include #include namespace CorUnix { + enum THREAD_STATE + { + TS_IDLE, + TS_STARTING, + TS_RUNNING, + TS_FAILED, + TS_DONE, + }; + PAL_ERROR InternalCreateThread( CPalThread *pThread, @@ -197,6 +205,7 @@ namespace CorUnix minipal_mutex m_mtxLock; bool m_fLockInitialized; bool m_fIsDummy; + THREAD_STATE m_threadState; // // Minimal reference count, used primarily for cleanup purposes. A @@ -288,7 +297,6 @@ namespace CorUnix // Embedded information for areas owned by other subsystems // - CThreadSynchronizationInfo synchronizationInfo; CThreadSuspensionInfo suspensionInfo; CPalThread() @@ -298,6 +306,7 @@ namespace CorUnix m_fExitCodeSet(FALSE), m_fLockInitialized(FALSE), m_fIsDummy(FALSE), + m_threadState(TS_IDLE), m_lRefCount(1), m_pThreadObject(NULL), m_threadId(0), @@ -371,35 +380,6 @@ namespace CorUnix minipal_mutex_leave(&m_mtxLock); }; - // - // The following three methods provide access to the - // native lock used to protect thread native wait data. - // - - void - AcquireNativeWaitLock( - void - ) - { - synchronizationInfo.AcquireNativeWaitLock(); - } - - void - ReleaseNativeWaitLock( - void - ) - { - synchronizationInfo.ReleaseNativeWaitLock(); - } - - bool - TryAcquireNativeWaitLock( - void - ) - { - return synchronizationInfo.TryAcquireNativeWaitLock(); - } - static void SetLastError( DWORD dwLastError @@ -536,6 +516,16 @@ namespace CorUnix return m_fIsDummy; }; + THREAD_STATE GetThreadState() + { + return m_threadState; + } + + void SetThreadState(THREAD_STATE threadState) + { + m_threadState = threadState; + } + CPalThread* GetNext( void diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index 4f70878825bf0d..3b1cee417edc5e 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -17,7 +17,6 @@ Module Name: SET_DEFAULT_DEBUG_CHANNEL(PAL); // some headers have code with asserts, so do this first #include "pal/thread.hpp" -#include "pal/synchobjects.hpp" #include "pal/procobj.hpp" #include "pal/file.hpp" #include "pal/map.hpp" @@ -446,18 +445,6 @@ Initialize( g_pObjectManager = plom; - // - // Initialize the synchronization manager - // - g_pSynchronizationManager = - CPalSynchMgrController::CreatePalSynchronizationManager(); - - if (nullptr == g_pSynchronizationManager) - { - palError = ERROR_NOT_ENOUGH_MEMORY; - ERROR("Failure creating synchronization manager\n"); - goto CLEANUP1c; - } } else { @@ -579,7 +566,6 @@ Initialize( free(exe_path); CLEANUP1e: // Cleanup synchronization manager -CLEANUP1c: // Cleanup object manager CLEANUP1b: // Cleanup initial thread data @@ -752,10 +738,6 @@ PALCommonCleanup() { cleanupDone = true; - // - // Let the synchronization manager know we're about to shutdown - // - CPalSynchMgrController::PrepareForShutdown(); } } diff --git a/src/coreclr/pal/src/map/map.cpp b/src/coreclr/pal/src/map/map.cpp index 796e76c3fdd54c..81cc8c1bd88de6 100644 --- a/src/coreclr/pal/src/map/map.cpp +++ b/src/coreclr/pal/src/map/map.cpp @@ -131,10 +131,7 @@ CObjectType CorUnix::otFileMapping( CFileMappingImmutableDataCopyRoutine, CFileMappingImmutableDataCleanupRoutine, sizeof(CFileMappingProcessLocalData), - NULL, // No process local data cleanup routine - CObjectType::UnwaitableObject, - CObjectType::SignalingNotApplicable, - CObjectType::ThreadReleaseNotApplicable + NULL // No process local data cleanup routine ); CAllowedObjectTypes aotFileMapping(otiFileMapping); diff --git a/src/coreclr/pal/src/objmgr/listedobject.cpp b/src/coreclr/pal/src/objmgr/listedobject.cpp index 349c76cdf62599..a8b2dad06e950f 100644 --- a/src/coreclr/pal/src/objmgr/listedobject.cpp +++ b/src/coreclr/pal/src/objmgr/listedobject.cpp @@ -247,302 +247,3 @@ CListedObject::GetObjectFromListLink(PLIST_ENTRY ple) return plo; } - -/*++ -Function: - CListedObject::GetSynchStateController - - Obtain a synchronization state controller for this object. Should - never be called. - -Parameters: - pthr -- thread data for calling thread - ppStateController -- on success, receives a pointer to the state controller - instance ---*/ - -PAL_ERROR -CListedObject::GetSynchStateController( - CPalThread *pthr, - ISynchStateController **ppStateController // OUT - ) -{ - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != ppStateController); - - // - // This is not a waitable object! - // - - ASSERT("Attempt to obtain a synch state controller on a non-waitable object\n"); - return ERROR_INVALID_HANDLE; -} - -/*++ -Function: - CListedObject::GetSynchWaitController - - Obtain a synchronization wait controller for this object. Should - never be called. - -Parameters: - pthr -- thread data for calling thread - ppWaitController -- on success, receives a pointer to the wait controller - instance ---*/ - -PAL_ERROR -CListedObject::GetSynchWaitController( - CPalThread *pthr, - ISynchWaitController **ppWaitController // OUT - ) -{ - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != ppWaitController); - - // - // This is not a waitable object!!! - // - - ASSERT("Attempt to obtain a synch wait controller on a non-waitable object\n"); - return ERROR_INVALID_HANDLE; -} - -/*++ -Function: - CListedObject::GetObjectSynchData - - Obtain the synchronization data for this object. Should - never be called. - -Parameters: - ppvSynchData -- on success, receives a pointer to the object's synch data ---*/ - -PAL_ERROR -CListedObject::GetObjectSynchData( - VOID **ppvSynchData // OUT - ) -{ - ASSERT("Attempt to obtain a synch data for a non-waitable object\n"); - return ERROR_INVALID_HANDLE; -} - -/*++ -Function: - CSharedMemoryWaitableObject::Initialize - - Performs possibly-failing initialization for a newly-constructed - object - -Parameters: - pthr -- thread data for calling thread - poa -- the object attributes (e.g., name) for the object ---*/ - -PAL_ERROR -CSharedMemoryWaitableObject::Initialize( - CPalThread *pthr, - CObjectAttributes *poa - ) -{ - PAL_ERROR palError = NO_ERROR; - - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != poa); - - ENTRY("CSharedMemoryWaitableObject::Initialize" - "(this = %p, pthr = %p, poa = %p)\n", - this, - pthr, - poa - ); - - palError = CListedObject::Initialize(pthr, poa); - if (NO_ERROR != palError) - { - goto InitializeExit; - } - - // - // Sanity check the passed in object type - // - - _ASSERTE(CObjectType::WaitableObject == m_pot->GetSynchronizationSupport()); - - palError = g_pSynchronizationManager->AllocateObjectSynchData( - m_pot, - &m_pvSynchData - ); - -InitializeExit: - - LOGEXIT("CSharedMemoryWaitableObject::Initialize returns %d\n", palError); - - return palError; -} - -/*++ -Function: - CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject - - Destructor; should only be called from ReleaseReference ---*/ - -CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject() -{ - ENTRY("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject" - "(this = %p)\n", - this - ); - - if (NULL != m_pvSynchData) - { - g_pSynchronizationManager->FreeObjectSynchData( - m_pot, - m_pvSynchData - ); - } - - LOGEXIT("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject\n"); -} - -/*++ -Function: - CSharedMemoryWaitableObject::GetSynchStateController - - Obtain a synchronization state controller for this object. - -Parameters: - pthr -- thread data for calling thread - ppStateController -- on success, receives a pointer to the state controller - instance ---*/ - -PAL_ERROR -CSharedMemoryWaitableObject::GetSynchStateController( - CPalThread *pthr, // IN, OPTIONAL - ISynchStateController **ppStateController // OUT - ) -{ - PAL_ERROR palError = NO_ERROR; - - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != ppStateController); - - ENTRY("CSharedMemoryWaitableObject::GetSynchStateController" - "(this = %p, pthr = %p, ppStateController = %p", - this, - pthr, - ppStateController - ); - - // - // We need to grab the local synch lock before creating the controller - // (otherwise we could get promoted after passing in our parameters) - // - - g_pSynchronizationManager->AcquireProcessLock(pthr); - - palError = g_pSynchronizationManager->CreateSynchStateController( - pthr, - m_pot, - m_pvSynchData, - ppStateController - ); - - g_pSynchronizationManager->ReleaseProcessLock(pthr); - - LOGEXIT("CSharedMemoryWaitableObject::GetSynchStateController returns %d\n", - palError - ); - - return palError; -} - -/*++ -Function: - CSharedMemoryWaitableObject::GetSynchWaitController - - Obtain a synchronization wait controller for this object. - -Parameters: - pthr -- thread data for calling thread - ppWaitController -- on success, receives a pointer to the wait controller - instance ---*/ - -PAL_ERROR -CSharedMemoryWaitableObject::GetSynchWaitController( - CPalThread *pthr, // IN, OPTIONAL - ISynchWaitController **ppWaitController // OUT - ) -{ - PAL_ERROR palError = NO_ERROR; - - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != ppWaitController); - - ENTRY("CSharedMemoryWaitableObject::GetSynchWaitController" - "(this = %p, pthr = %p, ppWaitController = %p", - this, - pthr, - ppWaitController - ); - - // - // We need to grab the local synch lock before creating the controller - // (otherwise we could get promoted after passing in our parameters) - // - - g_pSynchronizationManager->AcquireProcessLock(pthr); - - palError = g_pSynchronizationManager->CreateSynchWaitController( - pthr, - m_pot, - m_pvSynchData, - ppWaitController - ); - - g_pSynchronizationManager->ReleaseProcessLock(pthr); - - LOGEXIT("CSharedMemoryWaitableObject::GetSynchWaitController returns %d\n", - palError - ); - - return palError; -} - -/*++ -Function: - CSharedMemoryWaitableObject::GetObjectSynchData - - Obtain the synchronization data for this object. This method should only - be called by the synchronization manager - -Parameters: - ppvSynchData -- on success, receives a pointer to the object's synch data ---*/ - -PAL_ERROR -CSharedMemoryWaitableObject::GetObjectSynchData( - VOID **ppvSynchData // OUT - ) -{ - _ASSERTE(NULL != ppvSynchData); - - ENTRY("CSharedMemoryWaitableObject::GetObjectSynchData" - "(this = %p, ppvSynchData = %p)\n", - this, - ppvSynchData - ); - - *ppvSynchData = m_pvSynchData; - - LOGEXIT("CSharedMemoryWaitableObject::GetObjectSynchData returns %d\n", - NO_ERROR - ); - - return NO_ERROR; -} - diff --git a/src/coreclr/pal/src/objmgr/listedobject.hpp b/src/coreclr/pal/src/objmgr/listedobject.hpp index 11e346e4c3979f..4b149a792c1cb6 100644 --- a/src/coreclr/pal/src/objmgr/listedobject.hpp +++ b/src/coreclr/pal/src/objmgr/listedobject.hpp @@ -106,84 +106,8 @@ namespace CorUnix CListedObject* GetObjectFromListLink(PLIST_ENTRY pLink); - // - // IPalObject routines - // - - virtual - PAL_ERROR - GetSynchStateController( - CPalThread *pthr, - ISynchStateController **ppStateController - ); - - virtual - PAL_ERROR - GetSynchWaitController( - CPalThread *pthr, - ISynchWaitController **ppWaitController - ); - - virtual - PAL_ERROR - GetObjectSynchData( - VOID **ppvSynchData - ); - - }; - - class CSharedMemoryWaitableObject : public CListedObject - { - protected: - - VOID *m_pvSynchData; - - virtual ~CSharedMemoryWaitableObject(); - - public: - - CSharedMemoryWaitableObject( - CObjectType *pot, - minipal_mutex *pcsObjListLock - ) - : - CListedObject(pot, pcsObjListLock) - { - }; - - virtual - PAL_ERROR - Initialize( - CPalThread *pthr, - CObjectAttributes *poa - ); - - // - // IPalObject routines - // - - virtual - PAL_ERROR - GetSynchStateController( - CPalThread *pthr, - ISynchStateController **ppStateController - ); - - virtual - PAL_ERROR - GetSynchWaitController( - CPalThread *pthr, - ISynchWaitController **ppWaitController - ); - - virtual - PAL_ERROR - GetObjectSynchData( - VOID **ppvSynchData - ); }; } #endif // _PAL_SHMOBJECT_HPP - diff --git a/src/coreclr/pal/src/objmgr/listedobjectmanager.cpp b/src/coreclr/pal/src/objmgr/listedobjectmanager.cpp index 5e00282c0a4a5e..5b7dc46efffd4a 100644 --- a/src/coreclr/pal/src/objmgr/listedobjectmanager.cpp +++ b/src/coreclr/pal/src/objmgr/listedobjectmanager.cpp @@ -157,14 +157,7 @@ CListedObjectManager::AllocateObject( ppobjNew ); - if (CObjectType::WaitableObject == pot->GetSynchronizationSupport()) - { - pshmobj = new(std::nothrow) CSharedMemoryWaitableObject(pot, &m_csListLock); - } - else - { - pshmobj = new(std::nothrow) CListedObject(pot, &m_csListLock); - } + pshmobj = new(std::nothrow) CListedObject(pot, &m_csListLock); if (NULL != pshmobj) { @@ -621,121 +614,6 @@ CListedObjectManager::ReferenceObjectByHandle( return palError; } -/*++ -Function: - CListedObjectManager::ReferenceObjectByHandleArray - - Returns the referenced object instances that an array of handles - refer to. - -Parameters: - pthr -- thread data for calling thread - rgHandlesToReference -- the array of handles to reference - dwHandleCount -- the number of handles in the arrayu - paot -- acceptable types for the underlying objects - rgpobjs -- on success, receives references to the object instances; will - be empty on failures ---*/ - -PAL_ERROR -CListedObjectManager::ReferenceMultipleObjectsByHandleArray( - CPalThread *pthr, - HANDLE rghHandlesToReference[], - DWORD dwHandleCount, - CAllowedObjectTypes *paot, - IPalObject *rgpobjs[] // OUT (caller allocated) - ) -{ - PAL_ERROR palError = NO_ERROR; - IPalObject *pobj = NULL; - DWORD dw; - - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != rghHandlesToReference); - _ASSERTE(0 < dwHandleCount); - _ASSERTE(NULL != paot); - _ASSERTE(NULL != rgpobjs); - - ENTRY("CListedObjectManager::ReferenceMultipleObjectsByHandleArray " - "(this=%p, pthr=%p, rghHandlesToReference=%p, dwHandleCount=%d, " - "pAllowedTyped=%d, rgpobjs=%p)\n", - this, - pthr, - rghHandlesToReference, - dwHandleCount, - paot, - rgpobjs - ); - - m_HandleManager.Lock(pthr); - - for (dw = 0; dw < dwHandleCount; dw += 1) - { - palError = m_HandleManager.GetObjectFromHandle( - pthr, - rghHandlesToReference[dw], - &pobj - ); - - if (NO_ERROR == palError) - { - palError = CheckObjectTypeAndRights( - pobj, - paot - ); - - if (NO_ERROR == palError) - { - // - // Transfer reference to out array - // - - rgpobjs[dw] = pobj; - pobj = NULL; - } - } - - if (NO_ERROR != palError) - { - break; - } - } - - // - // The handle manager lock must be released before releasing - // any object references, as ReleaseReference will acquire - // the object manager list lock (which needs to be acquired before - // the handle manager lock) - // - - m_HandleManager.Unlock(pthr); - - if (NO_ERROR != palError) - { - // - // dw's current value is the failing index, so we want - // to free from dw - 1. - // - - while (dw > 0) - { - rgpobjs[--dw]->ReleaseReference(pthr); - } - - if (NULL != pobj) - { - pobj->ReleaseReference(pthr); - } - } - - LOGEXIT("CListedObjectManager::ReferenceMultipleObjectsByHandleArray" - " returns %d\n", - palError - ); - - return palError; -} - /*++ Function: CheckObjectTypeAndRights @@ -776,5 +654,3 @@ CheckObjectTypeAndRights( return palError; } - - diff --git a/src/coreclr/pal/src/objmgr/listedobjectmanager.hpp b/src/coreclr/pal/src/objmgr/listedobjectmanager.hpp index ffe98cb04d4c18..c711f07b3ced75 100644 --- a/src/coreclr/pal/src/objmgr/listedobjectmanager.hpp +++ b/src/coreclr/pal/src/objmgr/listedobjectmanager.hpp @@ -115,17 +115,7 @@ namespace CorUnix IPalObject **ppobj ); - virtual - PAL_ERROR - ReferenceMultipleObjectsByHandleArray( - CPalThread *pthr, - HANDLE rghHandlesToReference[], - DWORD dwHandleCount, - CAllowedObjectTypes *paot, - IPalObject *rgpobjs[] - ); }; } #endif // _PAL_SHMOBJECTMANAGER_HPP_ - diff --git a/src/coreclr/pal/src/synchmgr/synchcontrollers.cpp b/src/coreclr/pal/src/synchmgr/synchcontrollers.cpp deleted file mode 100644 index 63e8fb57053f06..00000000000000 --- a/src/coreclr/pal/src/synchmgr/synchcontrollers.cpp +++ /dev/null @@ -1,1084 +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: - - synchcontrollers.cpp - -Abstract: - Implementation of Synchronization Controllers and related objects - - - ---*/ - -#include "pal/dbgmsg.h" - -SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first - -#include "synchmanager.hpp" - -#include -#include -#include -#include -#include -#include -#include - -namespace CorUnix -{ -#ifdef SYNCH_STATISTICS - LONG g_rglStatWaitCount[ObjectTypeIdCount] = { 0 }; - LONG g_rglStatContentionCount[ObjectTypeIdCount] = { 0 }; -#endif // SYNCH_STATISTICS - //////////////////////////// - // // - // CSynchControllerBase // - // // - //////////////////////////// - - /*++ - Method: - CSynchControllerBase::Init - - Initializes a generic controller - --*/ - PAL_ERROR CSynchControllerBase::Init( - CPalThread * pthrCurrent, - ControllerType ctCtrlrType, - CObjectType *potObjectType, - CSynchData * psdSynchData) - { - VALIDATEOBJECT(psdSynchData); - - _ASSERTE(InternalGetCurrentThread() == pthrCurrent); - - // Initialize internal controller data - m_pthrOwner = pthrCurrent; - m_ctCtrlrType = ctCtrlrType; - m_potObjectType = potObjectType; - m_psdSynchData = psdSynchData; - - // Add reference to target synch data - m_psdSynchData->AddRef(); - - // Acquire lock implied by the controller - CPalSynchronizationManager::AcquireLocalSynchLock(m_pthrOwner); - - return NO_ERROR; - } - - /*++ - Method: - CSynchControllerBase::Release - - Releases a generic controller a return it to the appropriate cache - --*/ - void CSynchControllerBase::Release() - { - VALIDATEOBJECT(m_psdSynchData); - -#ifdef _DEBUG - ThreadWaitInfo * ptwiWaitInfo = - CPalSynchronizationManager::GetThreadWaitInfo(m_pthrOwner); -#endif // _DEBUG - - CPalSynchronizationManager * pSynchManager = - CPalSynchronizationManager::GetInstance(); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner); - - // Release reference to target synch data - m_psdSynchData->Release(m_pthrOwner); - - // Release lock implied by the controller - CPalSynchronizationManager::ReleaseLocalSynchLock(m_pthrOwner); - - // Return controller to the appropriate cache - if (WaitController == m_ctCtrlrType) - { - // The cast here must be static_cast and not reinterpet_cast. - // In fact in general static_cast(this) is - // equal to this-sizeof(void*), given that CSynchWaitController - // has a virtual table, while CSynchControllerBase doesn't. - pSynchManager->CacheAddWaitCtrlr(m_pthrOwner, - static_cast(this)); - } - else - { - // The cast here must be static_cast and not reinterpet_cast - pSynchManager->CacheAddStateCtrlr(m_pthrOwner, - static_cast(this)); - } - } - - //////////////////////////// - // // - // CSynchWaitController // - // // - //////////////////////////// - - /*++ - Method: - CSynchWaitController::CanThreadWaitWithoutBlocking - - Returns whether or not the thread owning this controller can - wait on the target object without blocking (i.e. the objet is - signaled) - --*/ - PAL_ERROR CSynchWaitController::CanThreadWaitWithoutBlocking( - bool * pfCanWaitWithoutBlocking) - { - VALIDATEOBJECT(m_psdSynchData); - - bool fRetVal = false; - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - _ASSERTE(NULL != pfCanWaitWithoutBlocking); - - fRetVal = m_psdSynchData->CanWaiterWaitWithoutBlocking(m_pthrOwner); - - *pfCanWaitWithoutBlocking = fRetVal; - return NO_ERROR; - } - - /*++ - Method: - CSynchWaitController::ReleaseWaitingThreadWithoutBlocking - - Performs all the steps needed to be done by the controller's owner - thread in order to wait on the target object without blocking - (e.g. modifying the object signal count accordingly with its - thread release semantics) - This method should be called only after having received positive - response from CanThreadWaitWithoutBlocking called on the same - controller. - --*/ - PAL_ERROR CSynchWaitController::ReleaseWaitingThreadWithoutBlocking() - { - VALIDATEOBJECT(m_psdSynchData); - - PAL_ERROR palErr = NO_ERROR; - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - - palErr = m_psdSynchData->ReleaseWaiterWithoutBlocking(m_pthrOwner, m_pthrOwner); - -#ifdef SYNCH_STATISTICS - if (NO_ERROR == palErr) - { - m_psdSynchData->IncrementStatWaitCount(); - } -#endif - return palErr; - } - - /*++ - Method: - CSynchWaitController::RegisterWaitingThread - - Registers the controller's owner thread for waiting on the target - object - --*/ - PAL_ERROR CSynchWaitController::RegisterWaitingThread( - WaitType wtWaitType, - DWORD dwIndex) - { - VALIDATEOBJECT(m_psdSynchData); - - PAL_ERROR palErr = NO_ERROR; - WaitingThreadsListNode * pwtlnNewNode = NULL; - SharedID shridNewNode = NULL; - ThreadWaitInfo * ptwiWaitInfo; - DWORD * pdwWaitState; - bool fEarlyDeath = false; - bool fSynchDataRefd = false; - CPalSynchronizationManager * pSynchManager = - CPalSynchronizationManager::GetInstance(); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - - ptwiWaitInfo = CPalSynchronizationManager::GetThreadWaitInfo( - m_pthrOwner); - - _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner); - - pdwWaitState = SharedIDToTypePointer(DWORD, - m_pthrOwner->synchronizationInfo.m_shridWaitAwakened); - - pwtlnNewNode = pSynchManager->CacheGetLocalWTListNode(m_pthrOwner); - - if (!pwtlnNewNode) - { - ERROR("Out of memory\n"); - palErr = ERROR_NOT_ENOUGH_MEMORY; - goto RWT_exit; - } - - if (ptwiWaitInfo->lObjCount >= MAXIMUM_WAIT_OBJECTS) - { - ASSERT("Too many objects"); - palErr = ERROR_INTERNAL_ERROR; - goto RWT_exit; - } - - if (0 == ptwiWaitInfo->lObjCount) - { - ptwiWaitInfo->wtWaitType = wtWaitType; - } - - pwtlnNewNode->ptwiWaitInfo = ptwiWaitInfo; - pwtlnNewNode->dwObjIndex = dwIndex; - pwtlnNewNode->dwThreadId = m_pthrOwner->GetThreadId(); - pwtlnNewNode->dwFlags = (MultipleObjectsWaitAll == wtWaitType) ? - WTLN_FLAG_WAIT_ALL : 0; - pwtlnNewNode->shridWaitingState = m_pthrOwner->synchronizationInfo.m_shridWaitAwakened; - pwtlnNewNode->ptrOwnerObjSynchData.ptr = m_psdSynchData; - - // AddRef the synch data (will be released in UnregisterWait) - m_psdSynchData->AddRef(); - fSynchDataRefd = true; - - ptwiWaitInfo->rgpWTLNodes[ptwiWaitInfo->lObjCount] = pwtlnNewNode; - - if (0 == ptwiWaitInfo->lObjCount) - { - DWORD dwWaitState; - - // Setting the thread in wait state - dwWaitState = TWS_WAITING; - - TRACE("Switching my wait state [%p] from TWS_ACTIVE to %u \n", - pdwWaitState, dwWaitState); - - dwWaitState = InterlockedCompareExchange( - (LONG *)pdwWaitState, (LONG)dwWaitState, TWS_ACTIVE); - if ((DWORD)TWS_ACTIVE != dwWaitState) - { - if ((DWORD)TWS_EARLYDEATH == dwWaitState) - { - // Process is terminating, this thread will soon be - // suspended (by SuspendOtherThreads). - WARN("Thread is about to get suspended by " - "TerminateProcess\n"); - - fEarlyDeath = true; - palErr = WAIT_FAILED; - } - else - { - ASSERT("Unexpected thread wait state %d\n", dwWaitState); - palErr = ERROR_INTERNAL_ERROR; - } - goto RWT_exit; - } - } - - // Add new node to queue - m_psdSynchData->WaiterEnqueue(pwtlnNewNode); - - // Succeeded: update object count - ptwiWaitInfo->lObjCount++; - - RWT_exit: - if (palErr != NO_ERROR) - { - // Unregister any partial wait registration - pSynchManager->UnRegisterWait(m_pthrOwner, ptwiWaitInfo); - - if (fSynchDataRefd) - { - m_psdSynchData->Release(m_pthrOwner); - } - if (NULL != pwtlnNewNode) - { - pSynchManager->CacheAddLocalWTListNode(m_pthrOwner, pwtlnNewNode); - } - - if (fEarlyDeath) - { - // Early death detected, i.e. the process is about to exit. - // We need to completely release the synch lock(s) before - // going to sleep - LONG lLocalSynchLockCount; - - lLocalSynchLockCount = CPalSynchronizationManager::ResetLocalSynchLock(m_pthrOwner); - - _ASSERTE(0 < lLocalSynchLockCount); - - // Sleep for ever - CPalSynchronizationManager::ThreadPrepareForShutdown(); - } - } -#ifdef SYNCH_STATISTICS - else - { - m_psdSynchData->IncrementStatWaitCount(); - m_psdSynchData->IncrementStatContentionCount(); - } -#endif - return palErr; - } - - /*++ - Method: - CSynchWaitController::ReleaseController - - Releases the current controller - --*/ - void CSynchWaitController::ReleaseController() - { - VALIDATEOBJECT(m_psdSynchData); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - - Release(); - } - - ///////////////////////////// - // // - // CSynchStateController // - // // - ///////////////////////////// - - /*++ - Method: - CSynchStateController::GetSignalCount - - Returns the current signal count of the target object - --*/ - PAL_ERROR CSynchStateController::GetSignalCount(LONG *plSignalCount) - { - VALIDATEOBJECT(m_psdSynchData); - - PAL_ERROR palErr = NO_ERROR; - LONG lCount = m_psdSynchData->GetSignalCount(); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - _ASSERTE(NULL != plSignalCount); - _ASSERT_MSG(0 <= lCount, - "Internal error: negative signal count [signal count=%d]", - lCount); - - *plSignalCount = lCount; - return palErr; - } - - /*++ - Method: - CSynchStateController::SetSignalCount - - Sets the signal count of the target object, possibly triggering - waiting threads awakening. - --*/ - PAL_ERROR CSynchStateController::SetSignalCount(LONG lNewCount) - { - VALIDATEOBJECT(m_psdSynchData); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - _ASSERTE(lNewCount >= 0); - - m_psdSynchData->Signal(m_pthrOwner, lNewCount); - - return NO_ERROR; - } - - /*++ - Method: - CSynchStateController::IncrementSignalCount - - Increments the signal count of the target object, possibly triggering - waiting threads awakening. - --*/ - PAL_ERROR CSynchStateController::IncrementSignalCount( - LONG lAmountToIncrement) - { - VALIDATEOBJECT(m_psdSynchData); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - _ASSERTE(lAmountToIncrement > 0); - - LONG lOldCount = m_psdSynchData->GetSignalCount(); - LONG lNewCount = lOldCount + lAmountToIncrement; - - _ASSERT_MSG(lNewCount > lOldCount, - "Signal count increment %d would make current signal count %d to " - "wrap around\n", lAmountToIncrement, lOldCount); - - m_psdSynchData->Signal(m_pthrOwner, lNewCount); - - return NO_ERROR; - } - - /*++ - Method: - CSynchStateController::DecrementSignalCount - - Decrements the signal count of the target object. - --*/ - PAL_ERROR CSynchStateController::DecrementSignalCount( - LONG lAmountToDecrement) - { - VALIDATEOBJECT(m_psdSynchData); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - _ASSERTE(lAmountToDecrement > 0); - - PAL_ERROR palErr = NO_ERROR; - LONG lCount = m_psdSynchData->GetSignalCount(); - _ASSERTE(lAmountToDecrement <= lCount); - - m_psdSynchData->SetSignalCount(lCount - lAmountToDecrement); - - return palErr; - } - - /*++ - Method: - CSynchStateController::ReleaseController - - Releases the controller. - --*/ - void CSynchStateController::ReleaseController(void) - { - VALIDATEOBJECT(m_psdSynchData); - - _ASSERTE(InternalGetCurrentThread() == m_pthrOwner); - - Release(); - } - - ////////////////// - // // - // CSynchData // - // // - ////////////////// - - /*++ - Method: - CSynchData::Release - - Decremnt the reference count of the target synchdata and retrurns - it to the appropriate cache if the reference count reaches zero. - --*/ - LONG CSynchData::Release(CPalThread * pthrCurrent) - { - VALIDATEOBJECT(this); - - LONG lCount = InterlockedDecrement(&m_lRefCount); - - _ASSERT_MSG(0 <= lCount, - "CSynchData %p with negative reference count [%d]\n", - this, lCount); - - if (0 == lCount) - { - CPalSynchronizationManager * pSynchManager = - CPalSynchronizationManager::GetInstance(); - - _ASSERT_MSG((NULL == m_ptrWTLHead.ptr), - "Final Release on CSynchData with threads still in " - "the waiting list\n"); - - TRACE("Disposing %s waitable object with SynchData @ " - "p=%p}\n", - "local", - this); - - -#ifdef SYNCH_STATISTICS - LONG lStatWaitCount = GetStatWaitCount(); - LONG lStatContentionCount = GetStatContentionCount(); - LONG lCount, lNewCount; - - TRACE("Statistical data for SynchData of otiType=%u @ %p: WaitCount=%d " - "ContentionCount=%d\n", m_otiObjectTypeId, this, lStatWaitCount, - lStatContentionCount); - - do { - lCount = g_rglStatWaitCount[m_otiObjectTypeId]; - lNewCount = lCount + lStatWaitCount; - lNewCount = InterlockedCompareExchange(&(g_rglStatWaitCount[m_otiObjectTypeId]), - lNewCount, lCount); - } while (lCount != lNewCount); - - lStatWaitCount = lNewCount; - - do { - lCount = g_rglStatContentionCount[m_otiObjectTypeId]; - lNewCount = lCount + lStatContentionCount; - lNewCount = InterlockedCompareExchange(&(g_rglStatContentionCount[m_otiObjectTypeId]), - lNewCount, lCount); - } while (lCount != lNewCount); - - lStatContentionCount = lNewCount; - - TRACE("Total current statistical data for otiType=%u objects: WaitCount=%d " - "ContentionCount=%d\n", m_otiObjectTypeId, lStatWaitCount, - lStatContentionCount); -#endif // SYNCH_STATISTICS - - pSynchManager->CacheAddLocalSynchData(pthrCurrent, this); - } - - return lCount; - } - - /*++ - Method: - CSynchData::ReleaseWaiterWithoutBlocking - - Performs all the steps needed to be done by the target thread in order - to wait without blocking on the object associated with the current - SynchData (e.g. modifying the object signal count accordingly with its - thread release semantics) - - Note: this method must be called while holding the local process synch lock. - --*/ - PAL_ERROR CSynchData::ReleaseWaiterWithoutBlocking( - CPalThread * pthrCurrent, - CPalThread * pthrTarget) - { - VALIDATEOBJECT(this); - - PAL_ERROR palErr = NO_ERROR; - CObjectType * potObjectType = GetObjectType(); -#ifdef _DEBUG - CObjectType::SignalingSemantics ssSignalingSemantics = - potObjectType->GetSignalingSemantics(); -#endif // _DEBUG - CObjectType::ThreadReleaseSemantics trsThreadReleaseSemantics = - potObjectType->GetThreadReleaseSemantics(); - - _ASSERT_MSG(CObjectType::SignalingNotApplicable != ssSignalingSemantics, - "Signaling not applicable"); - _ASSERT_MSG(CObjectType::ThreadReleaseNotApplicable != - trsThreadReleaseSemantics, - "Thread releasing not applicable"); - _ASSERT_MSG(CObjectType::SingleTransitionObject != ssSignalingSemantics || - CObjectType::ThreadReleaseHasNoSideEffects == trsThreadReleaseSemantics, - "Conflicting object synchronization attributes " - "[SignalingSemantics=%u " - "ThreadReleaseSemantics=%u]\n", - ssSignalingSemantics, - trsThreadReleaseSemantics); - - if (CObjectType::ThreadReleaseAltersSignalCount == trsThreadReleaseSemantics) - { - _ASSERT_MSG(0 < GetSignalCount(), - "Internal error: operation would make signal count " - "negative - object should be signaled at this time " - "[signal count=%d]", GetSignalCount()); - - // Unsignal the object - DecrementSignalCount(); - } - -#ifdef SYNCH_STATISTICS - if (NO_ERROR == palErr) - { - IncrementStatWaitCount(); - } -#endif - return palErr; - - } - - /*++ - Method: - CSynchData::CanWaiterWaitWithoutBlocking - - Returns whether or not the waiter thread can wait on the target object - without blocking (i.e. the objet is signaled) - - Note: this method must be called while holding the appropriate - synchronization locks (the local process synch lock if the target - object is local, both local and shared one if the object is shared). - --*/ - bool CSynchData::CanWaiterWaitWithoutBlocking( - CPalThread * pWaiterThread) - { - VALIDATEOBJECT(this); - - return 0 < GetSignalCount(); - } - - /*++ - Method: - CSynchData::Signal - - Sets the signal count of the object owning the target SynchData, - possibly triggering awakening of waiting threads. - - Note: this method must be called while holding the appropriate - synchronization locks (the local process synch lock if the target - object is local, both local and shared one if the object is shared). - --*/ - void CSynchData::Signal( - CPalThread * pthrCurrent, - LONG lSignalCount) - { - VALIDATEOBJECT(this); - - bool fThreadReleased = false; - bool fReleaseAltersSignalCount = - (CObjectType::ThreadReleaseAltersSignalCount == - GetObjectType()->GetThreadReleaseSemantics()); - - _ASSERTE(0 <= lSignalCount); - - // Preset the signal count to the new value, so that it can be used - // by ReleaseFirstWaiter when delegating signaling to another process - m_lSignalCount = lSignalCount; - - while (m_lSignalCount > 0) - { - fThreadReleased = ReleaseFirstWaiter(pthrCurrent); - if (!fThreadReleased) - { - // No more threads to release: break out of the loop - // keeping the current signal count - break; - } - if (fReleaseAltersSignalCount) - { - // Adjust signal count - m_lSignalCount--; - } - } - - return; - } - - /*++ - Method: - CSynchData::ReleaseFirstWaiter - - Releases the first thread from the front of the list of waiting threads - whose wait is fully satisfied, possibly triggering remote awakening (if - the target thread lives in a different process) or object signaling - delegation (if the target thread lives in a different processing and it - is blocked on a wait-all). - - Note: this method must be called while holding the appropriate - synchronization locks (the local process synch lock if the target - object is local, both local and shared one if the object is shared). - --*/ - bool CSynchData::ReleaseFirstWaiter( - CPalThread * pthrCurrent) - { - PAL_ERROR palErr = NO_ERROR; - bool fThreadAwakened = false; - DWORD * pdwWaitState; - DWORD dwObjIdx; - SharedID shridItem = NULL, shridNextItem = NULL; - WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem; - CPalSynchronizationManager * pSynchManager = - CPalSynchronizationManager::GetInstance(); - - VALIDATEOBJECT(this); - - pwtlnItem = GetWTLHeadPtr(); - - while (pwtlnItem) - { - VALIDATEOBJECT(pwtlnItem); - - WaitCompletionState wcsWaitCompletionState; - bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags)); - pdwWaitState = SharedIDToTypePointer(DWORD, - pwtlnItem->shridWaitingState); - - pwtlnNextItem = pwtlnItem->ptrNext.ptr; - - if (fWaitAll) - { - // Wait All: we need to find out whether the wait is satisfied, - // or it is not. - wcsWaitCompletionState = IsRestOfWaitAllSatisfied(pwtlnItem); - } - else - { - // Normal Wait: the wait is satisfied by definition - wcsWaitCompletionState = WaitIsSatisfied; - } - - if (WaitIsSatisfied == wcsWaitCompletionState) - { - // - // Target wait is satisfied - // - TRACE("Trying to switch wait state [%p] from WAIT " - "to ACTIVE for thread=%u\n", - pdwWaitState, pwtlnItem->dwThreadId); - - if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState)) - { - TRACE("Succeeded switching wait state [%p] from WAIT " - "to TWS_ACTIVE for trhead=%u\n", - pdwWaitState, pwtlnItem->dwThreadId); - - dwObjIdx = pwtlnItem->dwObjIndex; - - ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo; - - if (fWaitAll) - { - // Wait all satisfied: unsignal other objects - // involved in the wait - CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll( - pthrCurrent, - ptwiWaitInfo->pthrOwner, - pwtlnItem, - this); - } - - TRACE("Unregistering wait for thread %u and waking it up " - "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId, - pdwWaitState); - - // Unregister the wait - pSynchManager->UnRegisterWait(pthrCurrent, - ptwiWaitInfo); - - // After UnRegisterWait pwtlnItem is invalid - pwtlnItem = NULL; - - palErr = CPalSynchronizationManager::WakeUpLocalThread( - pthrCurrent, - ptwiWaitInfo->pthrOwner, - WaitSucceeded, - dwObjIdx); - - if (NO_ERROR != palErr) - { - ERROR("Failed to wakeup local thread %#x: " - "object signaling may be " - "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId()); - } - - // A thread has been awakened - fThreadAwakened = true; - - // break out of the while loop - break; - } - } - - // Go to the next item - shridItem = shridNextItem; - pwtlnItem = pwtlnNextItem; - } - - return fThreadAwakened; - } - - /*++ - Method: - CSynchData::Signal - - Releases all the threads waiting on this object and living in the current - process. - - Note: this method must be called while holding the appropriate - synchronization locks (the local process synch lock if the target - object is local, both local and shared one if the object is shared). - --*/ - LONG CSynchData::ReleaseAllLocalWaiters( - CPalThread * pthrCurrent) - { - PAL_ERROR palErr = NO_ERROR; - LONG lAwakenedCount = 0; - DWORD * pdwWaitState; - DWORD dwObjIdx; - SharedID shridItem = NULL, shridNextItem = NULL; - WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem; - CPalSynchronizationManager * pSynchManager = - CPalSynchronizationManager::GetInstance(); - - VALIDATEOBJECT(this); - - pwtlnItem = GetWTLHeadPtr(); - - while (pwtlnItem) - { - VALIDATEOBJECT(pwtlnItem); - - bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags)); - pdwWaitState = SharedIDToTypePointer(DWORD, - pwtlnItem->shridWaitingState); - - pwtlnNextItem = pwtlnItem->ptrNext.ptr; - - // See note in similar spot in ReleaseFirstWaiter - - if(!fWaitAll || WaitIsSatisfied == IsRestOfWaitAllSatisfied(pwtlnItem)) - { - // - // Target wait is satisfied - // - TRACE("Trying to switch wait state [%p] from WAIT " - "to ACTIVE for thread=%u\n", - pdwWaitState, pwtlnItem->dwThreadId); - - if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState)) - { - TRACE("Succeeded switching wait state [%p] from WAIT " - "to TWS_ACTIVE for trhead=%u\n", - pdwWaitState, pwtlnItem->dwThreadId); - - dwObjIdx = pwtlnItem->dwObjIndex; - - ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo; - - if (fWaitAll) - { - // Wait all satisfied: unsignal other objects - // involved in the wait - CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll( - pthrCurrent, - ptwiWaitInfo->pthrOwner, - pwtlnItem, - this); - } - - TRACE("Unregistering wait for thread %u and waking it up " - "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId, - pdwWaitState); - - // Unregister the wait - pSynchManager->UnRegisterWait(pthrCurrent, - ptwiWaitInfo); - - // After UnRegisterWait pwtlnItem is invalid - pwtlnItem = NULL; - - palErr = CPalSynchronizationManager::WakeUpLocalThread( - pthrCurrent, - ptwiWaitInfo->pthrOwner, - WaitSucceeded, - dwObjIdx); - - if (NO_ERROR != palErr) - { - ERROR("Failed to wakeup local thread %#x: " - "object signaling may be " - "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId()); - } - else - { - // A thread has been awakened - lAwakenedCount++; - } - } - } - - // Go to the next item - shridItem = shridNextItem; - pwtlnItem = pwtlnNextItem; - } - - return lAwakenedCount; - } - - /*++ - Method: - CSynchData::IsRestOfWaitAllSatisfied - - Returns whether or not the current wait-all operation is fully satisfied, - assuming the current target object as signaled (i.e. whether or not all the - involved object, except the current one, are signaled). - It returns: - - WaitIsNotSatisfied if the wait-all is not fully satisfied. - - WaitIsSatisfied if the wait-all is fully satisfied. - - Note: this method must be called while holding the synchronization locks - appropriate to all the objects involved in the wait-all. If any - of the objects is shared, the caller must own both local and - shared synch locks; if no shared object is involved in the wait, - only the local synch lock is needed. - --*/ - WaitCompletionState CSynchData::IsRestOfWaitAllSatisfied( - WaitingThreadsListNode * pwtlnNode) - { - int iSignaledObjCount = 0; - int iTgtCount = 0; - int i; - WaitCompletionState wcsWaitCompletionState = WaitIsNotSatisfied; - CSynchData * psdSynchDataItem = NULL; - ThreadWaitInfo * ptwiWaitInfo = NULL; - - VALIDATEOBJECT(this); - VALIDATEOBJECT(pwtlnNode); - - _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags), - "IsRestOfWaitAllSatisfied() called on a normal " - "(non wait all) wait"); - - /////////////////////////// - // - // Local Thread Awakening - // - /////////////////////////// - - ptwiWaitInfo = pwtlnNode->ptwiWaitInfo; - - iTgtCount = ptwiWaitInfo->lObjCount; - for (i=0; i < iTgtCount; i++) - { - WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i]; - bool fRetVal; - - VALIDATEOBJECT(pwtlnItem); - - psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr; - - VALIDATEOBJECT(psdSynchDataItem); - - if (pwtlnItem == pwtlnNode) - { - _ASSERT_MSG (this == psdSynchDataItem, - "pwtlnNode and pwtlnItem match, but this " - "and psdSynchDataItem don't\n"); - - // The target object (the one related to pwtlnNode) is counted as - // signaled/owned without checking it (also if it is not, as - // it normally happens when this method is called) - iSignaledObjCount++; - continue; - } - - fRetVal = psdSynchDataItem->CanWaiterWaitWithoutBlocking( - ptwiWaitInfo->pthrOwner); - - if (fRetVal) - { - iSignaledObjCount++; - } - else - { - break; - } - } - - if (iSignaledObjCount < iTgtCount) - { - wcsWaitCompletionState = WaitIsNotSatisfied; - } - else - { - wcsWaitCompletionState = WaitIsSatisfied; - } - - TRACE("IsRestOfWaitAllSatisfied() returning %u \n", wcsWaitCompletionState); - - return wcsWaitCompletionState; - } - - /*++ - Method: - CSynchData::WaiterEnqueue - - Adds the WaitingThreadsListNode passed as argument at the end of the - list of WaitingThreadsListNode for the current object, representing - the threads waiting on the current object. The target SynchData is - assumed to be local to the current process - - Note: this method must be called while holding the local process - synchronization lock. - --*/ - void CSynchData::WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode) - { - VALIDATEOBJECT(this); - VALIDATEOBJECT(pwtlnNewNode); - - // Enqueue normally to the end of the queue - WaitingThreadsListNode * pwtlnCurrLast = m_ptrWTLTail.ptr; - - pwtlnNewNode->ptrNext.ptr = NULL; - if (NULL == pwtlnCurrLast) - { - _ASSERT_MSG(NULL == m_ptrWTLHead.ptr, - "Corrupted waiting list on local CSynchData @ %p\n", - this); - - pwtlnNewNode->ptrPrev.ptr = NULL; - m_ptrWTLHead.ptr = pwtlnNewNode; - m_ptrWTLTail.ptr = pwtlnNewNode; - } - else - { - VALIDATEOBJECT(pwtlnCurrLast); - - pwtlnNewNode->ptrPrev.ptr = pwtlnCurrLast; - pwtlnCurrLast->ptrNext.ptr = pwtlnNewNode; - m_ptrWTLTail.ptr = pwtlnNewNode; - } - - m_ulcWaitingThreads += 1; - - return; - } - -#ifdef SYNCH_OBJECT_VALIDATION - CSynchData::~CSynchData() - { - ValidateObject(true); - InvalidateObject(); - } - /*++ - Method: - CSynchData::ValidateObject - - Makes sure that the signature at the beginning and at the end of the - current object are those of a currently alive object (i.e. the object - has been constructed and does not appear to have been overwritten) - --*/ - void CSynchData::ValidateObject(bool fDestructor) - { - TRACE("Verifying in-use CSynchData @ %p\n", this); - _ASSERT_MSG(HeadSignature == m_dwDebugHeadSignature, - "CSynchData header signature corruption [p=%p]", this); - _ASSERT_MSG(TailSignature == m_dwDebugTailSignature, - "CSynchData trailer signature corruption [p=%p]", this); - _ASSERT_MSG((fDestructor && 0 == m_lRefCount) || - (!fDestructor && 0 < m_lRefCount), - "CSynchData %p with NULL reference count\n", this); - } - /*++ - Method: - CSynchData::ValidateEmptyObject - - Makes sure that the signature at the beginning and at the end of the - current object are not those of a currently alive object (i.e. the - object has not yet been constructed or it has alread been destructed) - --*/ - void CSynchData::ValidateEmptyObject() - { - TRACE("Verifying empty CSynchData @ %p\n", this); - _ASSERT_MSG(HeadSignature != m_dwDebugHeadSignature, - "CSynchData header previously signed [p=%p]", this); - _ASSERT_MSG(TailSignature != m_dwDebugTailSignature, - "CSynchData trailer previously signed [p=%p]", this); - } - /*++ - Method: - CSynchData::InvalidateObject - - Turns signatures from alive object to destructed object - --*/ - void CSynchData::InvalidateObject() - { - TRACE("Invalidating CSynchData @ %p\n", this); - m_dwDebugHeadSignature = EmptySignature; - m_dwDebugTailSignature = EmptySignature; - } -#endif // SYNCH_OBJECT_VALIDATION -} - diff --git a/src/coreclr/pal/src/synchmgr/synchmanager.cpp b/src/coreclr/pal/src/synchmgr/synchmanager.cpp deleted file mode 100644 index 1aa1c15f3f15f0..00000000000000 --- a/src/coreclr/pal/src/synchmgr/synchmanager.cpp +++ /dev/null @@ -1,1642 +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: - - synchmanager.cpp - -Abstract: - Implementation of Synchronization Manager and related objects - - - ---*/ - -#include "pal/dbgmsg.h" - -SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first - -#include "synchmanager.hpp" -#include "pal/file.hpp" - -#include -#include -#include -#if !defined(TARGET_WASI) -#include -#endif -#include -#include -#include -#include -#include -#include -#if HAVE_POLL -#include -#else -#include "pal/fakepoll.h" -#endif // HAVE_POLL - -#include -#include - -const int CorUnix::CThreadSynchronizationInfo::PendingSignalingsArraySize; - -namespace CorUnix -{ - ///////////////////////////////// - // // - // WaitingThreadsListNode // - // // - ///////////////////////////////// -#ifdef SYNCH_OBJECT_VALIDATION - _WaitingThreadsListNode::_WaitingThreadsListNode() - { - ValidateEmptyObject(); - dwDebugHeadSignature = HeadSignature; - dwDebugTailSignature = TailSignature; - } - _WaitingThreadsListNode::~_WaitingThreadsListNode() - { - ValidateObject(); - InvalidateObject(); - } - void _WaitingThreadsListNode::ValidateObject() - { - TRACE("Verifying WaitingThreadsListNode @ %p\n", this); - _ASSERT_MSG(HeadSignature == dwDebugHeadSignature, - "WaitingThreadsListNode header signature corruption [p=%p]", - this); - _ASSERT_MSG(TailSignature == dwDebugTailSignature, - "WaitingThreadsListNode trailer signature corruption [p=%p]", - this); - } - void _WaitingThreadsListNode::ValidateEmptyObject() - { - _ASSERT_MSG(HeadSignature != dwDebugHeadSignature, - "WaitingThreadsListNode header previously signed [p=%p]", - this); - _ASSERT_MSG(TailSignature != dwDebugTailSignature, - "WaitingThreadsListNode trailer previously signed [p=%p]", - this); - } - void _WaitingThreadsListNode::InvalidateObject() - { - TRACE("Invalidating WaitingThreadsListNode @ %p\n", this); - dwDebugHeadSignature = EmptySignature; - dwDebugTailSignature = EmptySignature; - } -#endif // SYNCH_OBJECT_VALIDATION - - ////////////////////////////// - // // - // CPalSynchMgrController // - // // - ////////////////////////////// - - /*++ - Method: - CPalSynchMgrController::CreatePalSynchronizationManager - - Creates the Synchronization Manager. It must be called once per process. - --*/ - IPalSynchronizationManager * CPalSynchMgrController::CreatePalSynchronizationManager() - { - return CPalSynchronizationManager::CreatePalSynchronizationManager(); - }; - - /*++ - Method: - CPalSynchMgrController::PrepareForShutdown - - This method performs the part of Synchronization Manager's shutdown that - needs to be carried out when core PAL subsystems are still active - --*/ - PAL_ERROR CPalSynchMgrController::PrepareForShutdown() - { - return CPalSynchronizationManager::PrepareForShutdown(); - } - - ////////////////////////////////// - // // - // CPalSynchronizationManager // - // // - ////////////////////////////////// - - IPalSynchronizationManager * g_pSynchronizationManager = NULL; - - CPalSynchronizationManager * CPalSynchronizationManager::s_pObjSynchMgr = NULL; - Volatile CPalSynchronizationManager::s_lInitStatus = SynchMgrStatusIdle; - minipal_mutex CPalSynchronizationManager::s_csSynchProcessLock; - - CPalSynchronizationManager::CPalSynchronizationManager() - : m_cacheWaitCtrlrs(CtrlrsCacheMaxSize), - m_cacheStateCtrlrs(CtrlrsCacheMaxSize), - m_cacheSynchData(SynchDataCacheMaxSize), - m_cacheSHRSynchData(SynchDataCacheMaxSize), - m_cacheWTListNodes(WTListNodeCacheMaxSize), - m_cacheSHRWTListNodes(WTListNodeCacheMaxSize) - { - } - - CPalSynchronizationManager::~CPalSynchronizationManager() - { - } - - /*++ - Method: - CPalSynchronizationManager::BlockThread - - Called by a thread to go to sleep for a wait or a sleep - - NOTE: This method must must be called without holding any - synchronization lock (as well as other locks) - --*/ - PAL_ERROR CPalSynchronizationManager::BlockThread( - CPalThread *pthrCurrent, - DWORD dwTimeout, - bool fIsSleep, - ThreadWakeupReason *ptwrWakeupReason, - DWORD * pdwSignaledObject) - { - PAL_ERROR palErr = NO_ERROR; - ThreadWakeupReason twrWakeupReason = WaitFailed; - DWORD * pdwWaitState; - DWORD dwWaitState = 0; - DWORD dwSigObjIdx = 0; - bool fEarlyDeath = false; - - pdwWaitState = SharedIDToTypePointer(DWORD, - pthrCurrent->synchronizationInfo.m_shridWaitAwakened); - - _ASSERT_MSG(NULL != pdwWaitState, - "Got NULL pdwWaitState from m_shridWaitAwakened=%p\n", - (VOID *)pthrCurrent->synchronizationInfo.m_shridWaitAwakened); - - if (fIsSleep) - { - // Setting the thread in wait state - dwWaitState = TWS_WAITING; - - TRACE("Switching my wait state [%p] from TWS_ACTIVE to %u [current *pdwWaitState=%u]\n", - pdwWaitState, dwWaitState, *pdwWaitState); - - dwWaitState = InterlockedCompareExchange((LONG *)pdwWaitState, - dwWaitState, - TWS_ACTIVE); - - if ((DWORD)TWS_ACTIVE != dwWaitState) - { - if ((DWORD)TWS_EARLYDEATH == dwWaitState) - { - // Process is terminating, this thread will soon be suspended (by SuspendOtherThreads). - WARN("Thread is about to get suspended by TerminateProcess\n"); - - fEarlyDeath = true; - palErr = WAIT_FAILED; - } - else - { - ASSERT("Unexpected thread wait state %u\n", dwWaitState); - palErr = ERROR_INTERNAL_ERROR; - } - - goto BT_exit; - } - } - - TRACE("Current thread is about to block for waiting\n"); - - palErr = ThreadNativeWait( - &pthrCurrent->synchronizationInfo.m_tnwdNativeData, - dwTimeout, - &twrWakeupReason, - &dwSigObjIdx); - - if (NO_ERROR != palErr) - { - ERROR("ThreadNativeWait() failed [palErr=%d]\n", palErr); - twrWakeupReason = WaitFailed; - goto BT_exit; - } - - TRACE("ThreadNativeWait returned {WakeupReason=%u " - "dwSigObjIdx=%u}\n", twrWakeupReason, dwSigObjIdx); - - if (WaitTimeout == twrWakeupReason) - { - // timeout reached. set wait state back to 'active' - dwWaitState = TWS_WAITING; - - TRACE("Current thread awakened for timeout: switching wait " - "state [%p] from %u to TWS_ACTIVE [current *pdwWaitState=%u]\n", - pdwWaitState, dwWaitState, *pdwWaitState); - - DWORD dwOldWaitState = InterlockedCompareExchange( - (LONG *)pdwWaitState, - TWS_ACTIVE, (LONG)dwWaitState); - - switch (dwOldWaitState) - { - case TWS_ACTIVE: - // We were already ACTIVE; someone decided to wake up this - // thread sometime between the moment the native wait - // timed out and here. Since the signaling side succeeded - // its InterlockedCompareExchange, it will signal the - // condition/predicate pair (we just raced overtaking it); - // therefore we need to clear the condition/predicate - // by waiting on it one more time. - // That will also cause this method to report a signal - // rather than a timeout. - // In the remote signaling scenario, this second wait - // also makes sure that the shared id passed over the - // process pipe is valid for the entire duration of time - // in which the worker thread deals with it - TRACE("Current thread already ACTIVE: a signaling raced " - "with the timeout: re-waiting natively to clear the " - "predicate\n"); - - palErr = ThreadNativeWait( - &pthrCurrent->synchronizationInfo.m_tnwdNativeData, - SecondNativeWaitTimeout, - &twrWakeupReason, - &dwSigObjIdx); - - if (NO_ERROR != palErr) - { - ERROR("ThreadNativeWait() failed [palErr=%d]\n", - palErr); - twrWakeupReason = WaitFailed; - } - - if (WaitTimeout == twrWakeupReason) - { - ERROR("Second native wait timed out\n"); - } - - break; - case TWS_EARLYDEATH: - // Thread is about to be suspended by TerminateProcess. - // Anyway, if the wait timed out, we still want to - // (try to) unregister the wait (especially if it - // involves shared objects) - WARN("Thread is about to be suspended by TerminateProcess\n"); - fEarlyDeath = true; - palErr = WAIT_FAILED; - break; - case TWS_WAITING: - default: - _ASSERT_MSG(dwOldWaitState == dwWaitState, - "Unexpected wait status: actual=%u, expected=%u\n", - dwOldWaitState, dwWaitState); - break; - } - } - - switch (twrWakeupReason) - { - case WaitTimeout: - { - // Awakened for timeout: we need to unregister the wait - ThreadWaitInfo * ptwiWaitInfo; - - TRACE("Current thread awakened for timeout: unregistering the wait\n"); - - // Local lock - AcquireLocalSynchLock(pthrCurrent); - - ptwiWaitInfo = GetThreadWaitInfo(pthrCurrent); - - // Unregister the wait - UnRegisterWait(pthrCurrent, ptwiWaitInfo); - - // Unlock - ReleaseLocalSynchLock(pthrCurrent); - - break; - } - case WaitSucceeded: - *pdwSignaledObject = dwSigObjIdx; - break; - default: - // 'WaitFailed' goes through this case - break; - } - - // Set the returned wakeup reason - *ptwrWakeupReason = twrWakeupReason; - - TRACE("Current thread is now active [WakeupReason=%u SigObjIdx=%u]\n", - twrWakeupReason, dwSigObjIdx); - - _ASSERT_MSG(TWS_ACTIVE == VolatileLoad(pdwWaitState) || - TWS_EARLYDEATH == VolatileLoad(pdwWaitState), - "Unexpected thread wait state %u\n", VolatileLoad(pdwWaitState)); - - BT_exit: - if (fEarlyDeath) - { - ThreadPrepareForShutdown(); - } - - return palErr; - } - - PAL_ERROR CPalSynchronizationManager::ThreadNativeWait( - ThreadNativeWaitData * ptnwdNativeWaitData, - DWORD dwTimeout, - ThreadWakeupReason * ptwrWakeupReason, - DWORD * pdwSignaledObject) - { - PAL_ERROR palErr = NO_ERROR; - int iRet, iWaitRet = 0; - struct timespec tsAbsTmo; - - TRACE("ThreadNativeWait(ptnwdNativeWaitData=%p, dwTimeout=%u, ...)\n", - ptnwdNativeWaitData, dwTimeout); - - if (dwTimeout != INFINITE) - { - // Calculate absolute timeout - palErr = GetAbsoluteTimeout(dwTimeout, &tsAbsTmo); - if (NO_ERROR != palErr) - { - ERROR("Failed to convert timeout to absolute timeout\n"); - goto TNW_exit; - } - } - - // Lock the mutex - iRet = pthread_mutex_lock(&ptnwdNativeWaitData->mutex); - if (0 != iRet) - { - ERROR("Internal Error: cannot lock mutex\n"); - palErr = ERROR_INTERNAL_ERROR; - *ptwrWakeupReason = WaitFailed; - goto TNW_exit; - } - -#ifndef FEATURE_MULTITHREADING - // In single-threaded WASM, if the object is not already signaled (iPred == FALSE), - // we cannot wait because there is no other thread to signal us - this would deadlock. - // This is a programming error in single-threaded WASM. - _ASSERT_MSG(FALSE != ptnwdNativeWaitData->iPred, "Cannot wait in single-threaded mode\n"); - if (FALSE == ptnwdNativeWaitData->iPred) - { - iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex); - palErr = ERROR_NOT_SUPPORTED; - *ptwrWakeupReason = WaitFailed; - } -#else // !FEATURE_MULTITHREADING - - while (FALSE == ptnwdNativeWaitData->iPred) - { - if (INFINITE == dwTimeout) - { - iWaitRet = pthread_cond_wait(&ptnwdNativeWaitData->cond, - &ptnwdNativeWaitData->mutex); - } - else - { - iWaitRet = pthread_cond_timedwait(&ptnwdNativeWaitData->cond, - &ptnwdNativeWaitData->mutex, - &tsAbsTmo); - } - - if (ETIMEDOUT == iWaitRet) - { - _ASSERT_MSG(INFINITE != dwTimeout, - "Got ETIMEDOUT despite timeout being INFINITE\n"); - break; - } - else if (0 != iWaitRet) - { - ERROR("pthread_cond_%swait returned %d [errno=%d (%s)]\n", - (INFINITE == dwTimeout) ? "" : "timed", - iWaitRet, errno, strerror(errno)); - palErr = ERROR_INTERNAL_ERROR; - break; - } - } - - // Reset the predicate - if (0 == iWaitRet) - { - // We don't want to reset the predicate if pthread_cond_timedwait - // timed out racing with a pthread_cond_signal. When - // pthread_cond_timedwait times out, it needs to grab the mutex - // before returning. At timeout time, it may happen that the - // signaling thread just grabbed the mutex, but it hasn't called - // pthread_cond_signal yet. In this scenario pthread_cond_timedwait - // will have to wait for the signaling side to release the mutex. - // As a result it will return with error timeout, but the predicate - // will be set. Since pthread_cond_timedwait timed out, the - // predicate value is intended for the next signal. In case of a - // object signaling racing with a wait timeout this predicate value - // will be picked up by the 'second native wait' (see comments in - // BlockThread). - - ptnwdNativeWaitData->iPred = FALSE; - } - - // Unlock the mutex - iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex); - if (0 != iRet) - { - ERROR("Cannot unlock mutex [err=%d]\n", iRet); - palErr = ERROR_INTERNAL_ERROR; - goto TNW_exit; - } - - _ASSERT_MSG(ETIMEDOUT != iRet || INFINITE != dwTimeout, "Got timeout return code with INFINITE timeout\n"); - - if (0 == iWaitRet) - { - *ptwrWakeupReason = ptnwdNativeWaitData->twrWakeupReason; - *pdwSignaledObject = ptnwdNativeWaitData->dwObjectIndex; - } - else if (ETIMEDOUT == iWaitRet) - { - *ptwrWakeupReason = WaitTimeout; - } - -#endif // !FEATURE_MULTITHREADING - TNW_exit: - TRACE("ThreadNativeWait: returning %u [WakeupReason=%u]\n", palErr, *ptwrWakeupReason); - return palErr; - } - - /*++ - Method: - CPalSynchronizationManager::GetSynchWaitControllersForObjects - - Returns an array of wait controllers, one for each of the objects - in rgObjects - --*/ - PAL_ERROR CPalSynchronizationManager::GetSynchWaitControllersForObjects( - CPalThread *pthrCurrent, - IPalObject *rgObjects[], - DWORD dwObjectCount, - ISynchWaitController * rgControllers[]) - { - return GetSynchControllersForObjects(pthrCurrent, - rgObjects, - dwObjectCount, - (void **)rgControllers, - CSynchControllerBase::WaitController); - } - - /*++ - Method: - CPalSynchronizationManager::GetSynchStateControllersForObjects - - Returns an array of state controllers, one for each of the objects - in rgObjects - --*/ - PAL_ERROR CPalSynchronizationManager::GetSynchStateControllersForObjects( - CPalThread *pthrCurrent, - IPalObject *rgObjects[], - DWORD dwObjectCount, - ISynchStateController *rgControllers[]) - { - return GetSynchControllersForObjects(pthrCurrent, - rgObjects, - dwObjectCount, - (void **)rgControllers, - CSynchControllerBase::StateController); - } - - /*++ - Method: - CPalSynchronizationManager::GetSynchControllersForObjects - - Internal common implementation for GetSynchWaitControllersForObjects and - GetSynchStateControllersForObjects - --*/ - PAL_ERROR CPalSynchronizationManager::GetSynchControllersForObjects( - CPalThread *pthrCurrent, - IPalObject *rgObjects[], - DWORD dwObjectCount, - void ** ppvControllers, - CSynchControllerBase::ControllerType ctCtrlrType) - { - PAL_ERROR palErr = NO_ERROR; - unsigned int uIdx, uCount = 0, uSharedObjectCount = 0; - CObjectType * potObjectType = NULL; - unsigned int uErrCleanupIdxFirstNotInitializedCtrlr = 0; - unsigned int uErrCleanupIdxLastCtrlr = 0; - bool fLocalSynchLock = false; - - union - { - CSynchWaitController * pWaitCtrlrs[MAXIMUM_WAIT_OBJECTS]; - CSynchStateController * pStateCtrlrs[MAXIMUM_WAIT_OBJECTS]; - } Ctrlrs; - - if ((dwObjectCount <= 0) || (dwObjectCount > MAXIMUM_WAIT_OBJECTS)) - { - palErr = ERROR_INVALID_PARAMETER; - goto GSCFO_exit; - } - - if (CSynchControllerBase::WaitController == ctCtrlrType) - { - uCount = (unsigned int)m_cacheWaitCtrlrs.Get(pthrCurrent, - dwObjectCount, - Ctrlrs.pWaitCtrlrs); - } - else - { - uCount = (unsigned int)m_cacheStateCtrlrs.Get(pthrCurrent, - dwObjectCount, - Ctrlrs.pStateCtrlrs); - } - - if (uCount < dwObjectCount) - { - // We got less controllers (uCount) than we asked for (dwObjectCount), - // probably because of low memory. - // None of these controllers is initialized, so they must be all - // returned directly to the cache - uErrCleanupIdxLastCtrlr = uCount; - - palErr = ERROR_NOT_ENOUGH_MEMORY; - goto GSCFO_error_cleanup; - } - - // - // We need to acquire the local synch lock before evaluating object domains - // - AcquireLocalSynchLock(pthrCurrent); - fLocalSynchLock = true; - - for (uIdx=0;uIdxGetObjectSynchData((void **)&pvSData); - if (NO_ERROR != palErr) - { - break; - } - - psdSynchData = static_cast(pvSData); - - VALIDATEOBJECT(psdSynchData); - - potObjectType = rgObjects[uIdx]->GetObjectType(); - - if (CSynchControllerBase::WaitController == ctCtrlrType) - { - Ctrlrs.pWaitCtrlrs[uIdx]->Init(pthrCurrent, - ctCtrlrType, - potObjectType, - psdSynchData); - } - else - { - Ctrlrs.pStateCtrlrs[uIdx]->Init(pthrCurrent, - ctCtrlrType, - potObjectType, - psdSynchData); - } - } - if (NO_ERROR != palErr) - { - // An error occurred while initializing the (uIdx+1)-th controller, - // i.e. the one at index uIdx; therefore the first uIdx controllers - // must be Release'd, while the remaining uCount-uIdx must be returned - // directly to the cache. - uErrCleanupIdxFirstNotInitializedCtrlr = uIdx; - uErrCleanupIdxLastCtrlr = dwObjectCount; - - goto GSCFO_error_cleanup; - } - - // Succeeded - if (CSynchControllerBase::WaitController == ctCtrlrType) - { - for (uIdx=0;uIdx( - static_cast(Ctrlrs.pWaitCtrlrs[uIdx])); - } - } - else - { - for (uIdx=0;uIdx( - static_cast(Ctrlrs.pStateCtrlrs[uIdx])); - } - } - - // Succeeded: skip error cleanup - goto GSCFO_exit; - - GSCFO_error_cleanup: - if (CSynchControllerBase::WaitController == ctCtrlrType) - { - // Release already initialized wait controllers - for (uIdx=0; uIdxRelease(); - } - - // Return to the cache not yet initialized wait controllers - for (uIdx=uErrCleanupIdxFirstNotInitializedCtrlr; uIdxRelease(); - } - - // Return to the cache not yet initialized state controllers - for (uIdx=uErrCleanupIdxFirstNotInitializedCtrlr; uIdxSetWTLHeadPtr(NULL); - psdSynchData->SetWTLTailPtr(NULL); - - *ppvSynchData = static_cast(psdSynchData); - - // Initialize object domain and object type; - psdSynchData->SetObjectType(potObjectType); - - return palErr; - } - - /*++ - Method: - CPalSynchronizationManager::FreeObjectSynchData - - Called to return a no longer used SynchData to the Synchronization Manager. - The SynchData may actually survive this call, since it is a ref-counted - object and at FreeObjectSynchData time it may still be used from within - the Synchronization Manager itself (e.g. the worker thread). - --*/ - void CPalSynchronizationManager::FreeObjectSynchData( - CObjectType *potObjectType, - VOID *pvSynchData) - { - CSynchData * psdSynchData; - CPalThread * pthrCurrent = InternalGetCurrentThread(); - - psdSynchData = static_cast(pvSynchData); - - psdSynchData->Release(pthrCurrent); - } - - /*++ - Method: - CPalSynchronizationManager::CreateSynchStateController - - Creates a state controller for the given object - --*/ - PAL_ERROR CPalSynchronizationManager::CreateSynchStateController( - CPalThread *pthrCurrent, - CObjectType *potObjectType, - VOID *pvSynchData, - ISynchStateController **ppStateController) - { - PAL_ERROR palErr = NO_ERROR; - CSynchStateController * pCtrlr = NULL; - CSynchData * psdSynchData; - - psdSynchData = static_cast(pvSynchData); - - VALIDATEOBJECT(psdSynchData); - - pCtrlr = m_cacheStateCtrlrs.Get(pthrCurrent); - if (NULL == pCtrlr) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - pCtrlr->Init(pthrCurrent, - CSynchControllerBase::StateController, - potObjectType, - psdSynchData); - - // Succeeded - *ppStateController = (ISynchStateController *)pCtrlr; - - if (NO_ERROR != palErr) - { - m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr); - } - - return palErr; - } - - /*++ - Method: - CPalSynchronizationManager::CreateSynchWaitController - - Creates a wait controller for the given object - --*/ - PAL_ERROR CPalSynchronizationManager::CreateSynchWaitController( - CPalThread *pthrCurrent, - CObjectType *potObjectType, - VOID *pvSynchData, - ISynchWaitController **ppWaitController) - { - CSynchWaitController * pCtrlr = NULL; - CSynchData * psdSynchData; - - psdSynchData = static_cast(pvSynchData); - - VALIDATEOBJECT(psdSynchData); - - pCtrlr = m_cacheWaitCtrlrs.Get(pthrCurrent); - if (NULL == pCtrlr) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - pCtrlr->Init(pthrCurrent, - CSynchControllerBase::WaitController, - potObjectType, - psdSynchData); - - // Succeeded - *ppWaitController = (ISynchWaitController *)pCtrlr; - - return NO_ERROR; - } - - /*++ - Method: - CPalSynchronizationManager::CreatePalSynchronizationManager - - Creates the Synchronization Manager. - Private method, it is called only by CPalSynchMgrController. - --*/ - IPalSynchronizationManager * CPalSynchronizationManager::CreatePalSynchronizationManager() - { - if (s_pObjSynchMgr != NULL) - { - ASSERT("Multiple PAL Synchronization manager initializations\n"); - return NULL; - } - - Initialize(); - return static_cast(s_pObjSynchMgr); - } - - /*++ - Method: - CPalSynchronizationManager::Initialize - - Internal Synchronization Manager initialization - --*/ - PAL_ERROR CPalSynchronizationManager::Initialize() - { - PAL_ERROR palErr = NO_ERROR; - LONG lInit; - CPalSynchronizationManager * pSynchManager = NULL; - - lInit = InterlockedCompareExchange(&s_lInitStatus, - (LONG)SynchMgrStatusInitializing, - (LONG)SynchMgrStatusIdle); - - if ((LONG)SynchMgrStatusIdle != lInit) - { - ASSERT("Synchronization Manager already being initialized"); - palErr = ERROR_INTERNAL_ERROR; - goto I_exit; - } - - minipal_mutex_init(&s_csSynchProcessLock); - - pSynchManager = new(std::nothrow) CPalSynchronizationManager(); - if (NULL == pSynchManager) - { - ERROR("Failed to allocate memory for Synchronization Manager"); - palErr = ERROR_NOT_ENOUGH_MEMORY; - goto I_exit; - } - - s_pObjSynchMgr = pSynchManager; - - // Initialization was successful - g_pSynchronizationManager = - static_cast(pSynchManager); - s_lInitStatus = (LONG)SynchMgrStatusRunning; - - I_exit: - if (NO_ERROR != palErr) - { - s_lInitStatus = (LONG)SynchMgrStatusError; - - s_pObjSynchMgr = NULL; - g_pSynchronizationManager = NULL; - delete pSynchManager; - } - - return palErr; - } - - /*++ - Method: - CPalSynchronizationManager::PrepareForShutdown - - This method performs the part of Synchronization Manager's shutdown that - needs to be carried out when core PAL subsystems are still active. - Private method, it is called only by CPalSynchMgrController. - --*/ - PAL_ERROR CPalSynchronizationManager::PrepareForShutdown() - { - PAL_ERROR palErr = NO_ERROR; - - LONG lInit = InterlockedCompareExchange(&s_lInitStatus, - (LONG)SynchMgrStatusShuttingDown, (LONG)SynchMgrStatusRunning); - - if ((LONG)SynchMgrStatusRunning != lInit) - { - ASSERT("Unexpected initialization status found " - "in PrepareForShutdown [expected=%d current=%d]\n", - SynchMgrStatusRunning, lInit); - // We intentionally do not set s_lInitStatus to SynchMgrStatusError - // because this could interfere with a previous thread already - // executing shutdown. - return ERROR_INTERNAL_ERROR; - } - - // Ready for process shutdown. - s_lInitStatus = SynchMgrStatusReadyForProcessShutDown; - return palErr; - } - - /*++ - Method: - CPalSynchronizationManager::WakeUpLocalThread - - Wakes up a local thead currently sleeping for a wait or a sleep - --*/ - PAL_ERROR CPalSynchronizationManager::WakeUpLocalThread( - CPalThread * pthrCurrent, - CPalThread * pthrTarget, - ThreadWakeupReason twrWakeupReason, - DWORD dwObjectIndex) - { - PAL_ERROR palErr = NO_ERROR; - ThreadNativeWaitData * ptnwdNativeWaitData = - pthrTarget->synchronizationInfo.GetNativeData(); - - TRACE("Waking up a local thread [WakeUpReason=%u ObjectIndex=%u " - "ptnwdNativeWaitData=%p]\n", twrWakeupReason, dwObjectIndex, - ptnwdNativeWaitData); - - // Set wakeup reason and signaled object index - ptnwdNativeWaitData->twrWakeupReason = twrWakeupReason; - ptnwdNativeWaitData->dwObjectIndex = dwObjectIndex; - -#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - if (0 < GetLocalSynchLockCount(pthrCurrent)) - { - // Defer the actual thread signaling to right after - // releasing the synch lock(s), so that signaling - // can happen from a thread-suspension safe area - palErr = DeferThreadConditionSignaling(pthrCurrent, pthrTarget); - } - else - { - // Signal the target thread's condition - palErr = SignalThreadCondition(ptnwdNativeWaitData); - } -#else // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - // Signal the target thread's condition - palErr = SignalThreadCondition(ptnwdNativeWaitData); -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - - return palErr; - } - -#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - /*++ - Method: - CPalSynchronizationManager::DeferThreadConditionSignaling - - Defers thread signaling to the final release of synchronization - lock(s), so that condition signaling can happen when the signaling - thread is marked as safe for thread suspension. - --*/ - PAL_ERROR CPalSynchronizationManager::DeferThreadConditionSignaling( - CPalThread * pthrCurrent, - CPalThread * pthrTarget) - { - PAL_ERROR palErr = NO_ERROR; - LONG lCount = pthrCurrent->synchronizationInfo.m_lPendingSignalingCount; - - _ASSERTE(pthrTarget != pthrCurrent); - - if (CThreadSynchronizationInfo::PendingSignalingsArraySize > lCount) - { - // If there is available room, add the target thread object to - // the array of pending thread signalings. - pthrCurrent->synchronizationInfo.m_rgpthrPendingSignalings[lCount] = pthrTarget; - } - else - { - // If the array is full, add the target thread object at the end - // of the overflow list - DeferredSignalingListNode * pdsln = - new(std::nothrow) DeferredSignalingListNode(); - - if (pdsln) - { - pdsln->pthrTarget = pthrTarget; - - // Add the note to the end of the list. - // Note: no need to synchronize the access to this list since - // it is meant to be accessed only by the owner thread. - InsertTailList(&pthrCurrent->synchronizationInfo.m_lePendingSignalingsOverflowList, - &pdsln->Link); - } - else - { - palErr = ERROR_NOT_ENOUGH_MEMORY; - } - } - - if (NO_ERROR == palErr) - { - // Increment the count of pending signalings - pthrCurrent->synchronizationInfo.m_lPendingSignalingCount += 1; - - // Add a reference to the target CPalThread object; this is - // needed since deferring signaling after releasing the synch - // locks implies accessing the target thread object without - // holding the local synch lock. In rare circumstances, the - // target thread may have already exited while deferred signaling - // takes place, therefore invalidating the thread object. The - // reference added here ensures that the thread object is still - // good, even if the target thread has exited. - pthrTarget->AddThreadReference(); - } - - return palErr; - } -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - - /*++ - Method: - CPalSynchronizationManager::SignalThreadCondition - - Performs the actual condition signaling in to wake up the target thread - --*/ - PAL_ERROR CPalSynchronizationManager::SignalThreadCondition( - ThreadNativeWaitData * ptnwdNativeWaitData) - { - PAL_ERROR palErr = NO_ERROR; - int iRet; - - // Lock the mutex - iRet = pthread_mutex_lock(&ptnwdNativeWaitData->mutex); - if (0 != iRet) - { - ERROR("Cannot lock mutex [err=%d]\n", iRet); - return ERROR_INTERNAL_ERROR; - } - - // Set the predicate - ptnwdNativeWaitData->iPred = TRUE; - - // Signal the condition - iRet = pthread_cond_signal(&ptnwdNativeWaitData->cond); - if (0 != iRet) - { - ERROR("Failed to signal condition: pthread_cond_signal " - "returned %d [errno=%d (%s)]\n", iRet, errno, - strerror(errno)); - palErr = ERROR_INTERNAL_ERROR; - // Continue in order to unlock the mutex anyway - } - - // Unlock the mutex - iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex); - if (0 != iRet) - { - ERROR("Cannot unlock mutex [err=%d]\n", iRet); - return ERROR_INTERNAL_ERROR; - } - - return palErr; - } - - - /*++ - Method: - CPalSynchronizationManager::GetThreadWaitInfo - - Returns a pointer to the WaitInfo structure for the passed CPalThread object - --*/ - ThreadWaitInfo * CPalSynchronizationManager::GetThreadWaitInfo( - CPalThread * pthrCurrent) - { - return &pthrCurrent->synchronizationInfo.m_twiWaitInfo; - } - - /*++ - Method: - CPalSynchronizationManager::UnRegisterWait - - Unregister the wait described by ptwiWaitInfo that in general involves - a thread other than the current one (most of the times the deregistration - is performed by the signaling thread) - - Note: this method must be called while holding the local process - synchronization lock. - --*/ - void CPalSynchronizationManager::UnRegisterWait( - CPalThread * pthrCurrent, - ThreadWaitInfo * ptwiWaitInfo) - { - int i = 0; - CSynchData * psdSynchData = NULL; - - TRACE("Unregistering wait for thread=%u [ObjCount=%d WaitType=%u]\n", - ptwiWaitInfo->pthrOwner->GetThreadId(), - ptwiWaitInfo->lObjCount, ptwiWaitInfo->wtWaitType); - - for (i=0; i < ptwiWaitInfo->lObjCount; i++) - { - WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i]; - - VALIDATEOBJECT(pwtlnItem); - - psdSynchData = pwtlnItem->ptrOwnerObjSynchData.ptr; - - VALIDATEOBJECT(psdSynchData); - - if (pwtlnItem->ptrPrev.ptr) - { - VALIDATEOBJECT(pwtlnItem); - pwtlnItem->ptrPrev.ptr->ptrNext.ptr = pwtlnItem->ptrNext.ptr; - } - else - { - psdSynchData->SetWTLHeadPtr(pwtlnItem->ptrNext.ptr); - } - - if (pwtlnItem->ptrNext.ptr) - { - VALIDATEOBJECT(pwtlnItem); - pwtlnItem->ptrNext.ptr->ptrPrev.ptr = pwtlnItem->ptrPrev.ptr; - } - else - { - psdSynchData->SetWTLTailPtr(pwtlnItem->ptrPrev.ptr); - } - - m_cacheWTListNodes.Add(pthrCurrent, pwtlnItem); - - // Release the node's refcount on the synch data, and decerement - // waiting thread count - psdSynchData->DecrementWaitingThreadCount(); - psdSynchData->Release(pthrCurrent); - } - - // Reset wait data in ThreadWaitInfo structure: it is enough - // to reset lObjCount. - ptwiWaitInfo->lObjCount = 0; - - return; - } - - /*++ - Method: - CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll - - Unsignals all the objects involved in a wait all, except the target - one (i.e. psdTgtObjectSynchData) - - Note: this method must be called while holding the synchronization locks - appropriate to all the objects involved in the wait-all. If any - of the objects is shared, the caller must own both local and - shared synch locks; if no shared object is involved in the wait, - only the local synch lock is needed. - --*/ - void CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll( - CPalThread * pthrCurrent, - CPalThread * pthrTarget, - WaitingThreadsListNode * pwtlnNode, - CSynchData * psdTgtObjectSynchData) - { - PAL_ERROR palErr = NO_ERROR; - CSynchData * psdSynchDataItem = NULL; - -#ifdef _DEBUG - bool bOriginatingNodeFound = false; -#endif - - VALIDATEOBJECT(psdTgtObjectSynchData); - VALIDATEOBJECT(pwtlnNode); - - _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags), - "UnsignalRestOfLocalAwakeningWaitAll() called on a normal (non wait all) wait"); - - ThreadWaitInfo *ptwiWaitInfo = pwtlnNode->ptwiWaitInfo; - - int iObjCount = ptwiWaitInfo->lObjCount; - for (int i = 0; i < iObjCount; i++) - { - WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i]; - - VALIDATEOBJECT(pwtlnItem); - - psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr; - - VALIDATEOBJECT(psdSynchDataItem); - - // Skip originating node - if (psdTgtObjectSynchData == psdSynchDataItem) - { -#ifdef _DEBUG - bOriginatingNodeFound = true; -#endif - continue; - } - - palErr = psdSynchDataItem->ReleaseWaiterWithoutBlocking(pthrCurrent, pthrTarget); - if (NO_ERROR != palErr) - { - ERROR("ReleaseWaiterWithoutBlocking failed on SynchData @ %p [palErr = %u]\n", psdSynchDataItem, palErr); - } - } - - _ASSERT_MSG(bOriginatingNodeFound, "Couldn't find originating node while unsignaling rest of the wait all\n"); - } - - - - /*++ - Method: - CPalSynchronizationManager::ThreadPrepareForShutdown - - Used to hijack thread execution from known spots within the - Synchronization Manager in case a PAL shutdown is initiated - or the thread is being terminated by another thread. - --*/ - void CPalSynchronizationManager::ThreadPrepareForShutdown() - { - TRACE("The Synchronization Manager hijacked the current thread " - "for process shutdown or thread termination\n"); - while (true) - { - poll(NULL, 0, INFTIM); - sched_yield(); - } - - ASSERT("This code should never be executed\n"); - } - - - - /*++ - Method: - CPalSynchronizationManager::AcquireProcessLock - - Acquires the local Process Lock (which currently is the same as the - the local Process Synch Lock) - --*/ - void CPalSynchronizationManager::AcquireProcessLock(CPalThread * pthrCurrent) - { - AcquireLocalSynchLock(pthrCurrent); - } - - /*++ - Method: - CPalSynchronizationManager::ReleaseProcessLock - - Releases the local Process Lock (which currently is the same as the - the local Process Synch Lock) - --*/ - void CPalSynchronizationManager::ReleaseProcessLock(CPalThread * pthrCurrent) - { - ReleaseLocalSynchLock(pthrCurrent); - } - - ///////////////////////////// - // // - // _ThreadNativeWaitData // - // // - ///////////////////////////// - - _ThreadNativeWaitData::~_ThreadNativeWaitData() - { - if (fInitialized) - { - fInitialized = false; - pthread_cond_destroy(&cond); - pthread_mutex_destroy(&mutex); - } - } - - - ////////////////////////////////// - // // - // CThreadSynchronizationInfo // - // // - ////////////////////////////////// - - CThreadSynchronizationInfo::CThreadSynchronizationInfo() : - m_tsThreadState(TS_IDLE), - m_shridWaitAwakened(NULL), - m_lLocalSynchLockCount(0) - { - InitializeListHead(&m_leOwnedObjsList); - -#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - m_lPendingSignalingCount = 0; - InitializeListHead(&m_lePendingSignalingsOverflowList); -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - } - - CThreadSynchronizationInfo::~CThreadSynchronizationInfo() - { - if (NULL != m_shridWaitAwakened) - { - free(m_shridWaitAwakened); - } - } - - void CThreadSynchronizationInfo::AcquireNativeWaitLock() - { -#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - int iRet; - iRet = pthread_mutex_lock(&m_tnwdNativeData.mutex); - _ASSERT_MSG(0 == iRet, "pthread_mutex_lock failed with error=%d\n", iRet); -#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - } - - void CThreadSynchronizationInfo::ReleaseNativeWaitLock() - { -#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - int iRet; - iRet = pthread_mutex_unlock(&m_tnwdNativeData.mutex); - _ASSERT_MSG(0 == iRet, "pthread_mutex_unlock failed with error=%d\n", iRet); -#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - } - - bool CThreadSynchronizationInfo::TryAcquireNativeWaitLock() - { - bool fRet = true; -#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - int iRet; - iRet = pthread_mutex_trylock(&m_tnwdNativeData.mutex); - _ASSERT_MSG(0 == iRet || EBUSY == iRet, - "pthread_mutex_trylock failed with error=%d\n", iRet); - fRet = (0 == iRet); -#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - return fRet; - } - - /*++ - Method: - CThreadSynchronizationInfo::InitializePreCreate - - Part of CThreadSynchronizationInfo's initialization to be carried out - before actual thread creation - --*/ - PAL_ERROR CThreadSynchronizationInfo::InitializePreCreate(void) - { - PAL_ERROR palErr = NO_ERROR; - DWORD * pdwWaitState = NULL; - int iRet; - const int MaxUnavailableResourceRetries = 10; - int iEagains; - pthread_condattr_t attrs; - pthread_condattr_t *attrsPtr = nullptr; - - m_shridWaitAwakened = malloc(sizeof(DWORD)); - if (NULL == m_shridWaitAwakened) - { - ERROR("Fail allocating thread wait status shared object\n"); - palErr = ERROR_NOT_ENOUGH_MEMORY; - goto IPrC_exit; - } - - pdwWaitState = SharedIDToTypePointer(DWORD, - m_shridWaitAwakened); - - _ASSERT_MSG(NULL != pdwWaitState, - "Unable to map shared wait state: bad shared ID [shrid=%p]\n", (VOID*)m_shridWaitAwakened); - - VolatileStore(pdwWaitState, TWS_ACTIVE); - m_tsThreadState = TS_STARTING; - -#if HAVE_PTHREAD_CONDATTR_SETCLOCK - attrsPtr = &attrs; - iRet = pthread_condattr_init(&attrs); - if (0 != iRet) - { - ERROR("Failed to initialize thread synchronization condition attribute " - "[error=%d (%s)]\n", iRet, strerror(iRet)); - if (ENOMEM == iRet) - { - palErr = ERROR_NOT_ENOUGH_MEMORY; - } - else - { - palErr = ERROR_INTERNAL_ERROR; - } - goto IPrC_exit; - } - - // Ensure that the pthread_cond_timedwait will use CLOCK_MONOTONIC - iRet = pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); - if (0 != iRet) - { - ERROR("Failed set thread synchronization condition timed wait clock " - "[error=%d (%s)]\n", iRet, strerror(iRet)); - palErr = ERROR_INTERNAL_ERROR; - pthread_condattr_destroy(&attrs); - goto IPrC_exit; - } -#endif // HAVE_PTHREAD_CONDATTR_SETCLOCK - - iEagains = 0; - Mutex_retry: - iRet = pthread_mutex_init(&m_tnwdNativeData.mutex, NULL); - if (0 != iRet) - { - ERROR("Failed creating thread synchronization mutex [error=%d (%s)]\n", iRet, strerror(iRet)); - if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains) - { - poll(NULL, 0, std::min(100,10*iEagains)); - goto Mutex_retry; - } - else if (ENOMEM == iRet) - { - palErr = ERROR_NOT_ENOUGH_MEMORY; - } - else - { - palErr = ERROR_INTERNAL_ERROR; - } - - goto IPrC_exit; - } - - iEagains = 0; - Cond_retry: - - iRet = pthread_cond_init(&m_tnwdNativeData.cond, attrsPtr); - - if (0 != iRet) - { - ERROR("Failed creating thread synchronization condition " - "[error=%d (%s)]\n", iRet, strerror(iRet)); - if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains) - { - poll(NULL, 0, std::min(100,10*iEagains)); - goto Cond_retry; - } - else if (ENOMEM == iRet) - { - palErr = ERROR_NOT_ENOUGH_MEMORY; - } - else - { - palErr = ERROR_INTERNAL_ERROR; - } - pthread_mutex_destroy(&m_tnwdNativeData.mutex); - goto IPrC_exit; - } - - m_tnwdNativeData.fInitialized = true; - - IPrC_exit: - if (attrsPtr != nullptr) - { - pthread_condattr_destroy(attrsPtr); - } - if (NO_ERROR != palErr) - { - m_tsThreadState = TS_FAILED; - } - return palErr; - } - - /*++ - Method: - CThreadSynchronizationInfo::InitializePostCreate - - Part of CThreadSynchronizationInfo's initialization to be carried out - after actual thread creation - --*/ - PAL_ERROR CThreadSynchronizationInfo::InitializePostCreate( - CPalThread *pthrCurrent, - SIZE_T threadId, - DWORD dwLwpId) - { - PAL_ERROR palErr = NO_ERROR; - - if (TS_FAILED == m_tsThreadState) - { - palErr = ERROR_INTERNAL_ERROR; - } - - m_twiWaitInfo.pthrOwner = pthrCurrent; - - return palErr; - } - -#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - - /*++ - Method: - CThreadSynchronizationInfo::RunDeferredThreadConditionSignalings - - Carries out all the pending condition signalings for the current thread. - --*/ - PAL_ERROR CThreadSynchronizationInfo::RunDeferredThreadConditionSignalings() - { - PAL_ERROR palErr = NO_ERROR; - - _ASSERTE(0 <= m_lPendingSignalingCount); - - if (0 < m_lPendingSignalingCount) - { - LONG lArrayPendingSignalingCount = std::min(PendingSignalingsArraySize, m_lPendingSignalingCount); - LONG lIdx = 0; - PAL_ERROR palTempErr; - - // Signal all the pending signalings from the array - for (lIdx = 0; lIdx < lArrayPendingSignalingCount; lIdx++) - { - // Do the actual signaling - palTempErr = CPalSynchronizationManager::SignalThreadCondition( - m_rgpthrPendingSignalings[lIdx]->synchronizationInfo.GetNativeData()); - if (NO_ERROR != palTempErr) - { - palErr = palTempErr; - } - - // Release the thread reference - m_rgpthrPendingSignalings[lIdx]->ReleaseThreadReference(); - } - - // Signal any pending signalings from the array overflow list - if (m_lPendingSignalingCount > PendingSignalingsArraySize) - { - PLIST_ENTRY pLink; - DeferredSignalingListNode * pdsln; - - while (!IsListEmpty(&m_lePendingSignalingsOverflowList)) - { - // Remove a node from the head of the queue - // Note: no need to synchronize the access to this list since - // it is meant to be accessed only by the owner thread. - pLink = RemoveHeadList(&m_lePendingSignalingsOverflowList); - pdsln = CONTAINING_RECORD(pLink, - DeferredSignalingListNode, - Link); - - // Do the actual signaling - palTempErr = CPalSynchronizationManager::SignalThreadCondition( - pdsln->pthrTarget->synchronizationInfo.GetNativeData()); - if (NO_ERROR != palTempErr) - { - palErr = palTempErr; - } - - // Release the thread reference - pdsln->pthrTarget->ReleaseThreadReference(); - - // Delete the node - delete pdsln; - - lIdx += 1; - } - - _ASSERTE(lIdx == m_lPendingSignalingCount); - } - - // Reset the counter of pending signalings for this thread - m_lPendingSignalingCount = 0; - } - - return palErr; - } - -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - - - /*++ - Method: - CPalSynchronizationManager::InterlockedAwaken - - Tries to change the target wait status to 'active' in an interlocked fashion - --*/ - bool CPalSynchronizationManager::InterlockedAwaken( - DWORD *pWaitState) - { - return InterlockedCompareExchange((LONG *)pWaitState, TWS_ACTIVE, TWS_WAITING) == TWS_WAITING; - } - - /*++ - Method: - CPalSynchronizationManager::GetAbsoluteTimeout - - Converts a relative timeout to an absolute one. - --*/ - PAL_ERROR CPalSynchronizationManager::GetAbsoluteTimeout(DWORD dwTimeout, struct timespec * ptsAbsTmo) - { - PAL_ERROR palErr = NO_ERROR; - int iRet; - -#if HAVE_PTHREAD_CONDATTR_SETCLOCK - iRet = clock_gettime(CLOCK_MONOTONIC, ptsAbsTmo); -#elif HAVE_WORKING_CLOCK_GETTIME - // Not every platform implements a (working) clock_gettime - iRet = clock_gettime(CLOCK_REALTIME, ptsAbsTmo); -#elif HAVE_WORKING_GETTIMEOFDAY - // Not every platform implements a (working) gettimeofday - struct timeval tv; - iRet = gettimeofday(&tv, NULL); - if (0 == iRet) - { - ptsAbsTmo->tv_sec = tv.tv_sec; - ptsAbsTmo->tv_nsec = tv.tv_usec * tccMicroSecondsToNanoSeconds; - } -#else -#ifdef DBI_COMPONENT_MONO - return ERROR_INTERNAL_ERROR; -#else - #error "Don't know how to get hi-res current time on this platform" -#endif -#endif // HAVE_WORKING_CLOCK_GETTIME, HAVE_WORKING_GETTIMEOFDAY - if (0 == iRet) - { - ptsAbsTmo->tv_sec += dwTimeout / tccSecondsToMilliSeconds; - ptsAbsTmo->tv_nsec += (dwTimeout % tccSecondsToMilliSeconds) * tccMilliSecondsToNanoSeconds; - while (ptsAbsTmo->tv_nsec >= tccSecondsToNanoSeconds) - { - ptsAbsTmo->tv_sec += 1; - ptsAbsTmo->tv_nsec -= tccSecondsToNanoSeconds; - } - } - else - { - palErr = ERROR_INTERNAL_ERROR; - } - - return palErr; - } -} diff --git a/src/coreclr/pal/src/synchmgr/synchmanager.hpp b/src/coreclr/pal/src/synchmgr/synchmanager.hpp deleted file mode 100644 index 361cd2d3362488..00000000000000 --- a/src/coreclr/pal/src/synchmgr/synchmanager.hpp +++ /dev/null @@ -1,675 +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: - - synchmanager.hpp - -Abstract: - Private header file for synchronization manager and - controllers implementation - - - ---*/ -#ifndef _SYNCHMANAGER_HPP_ -#define _SYNCHMANAGER_HPP_ - -#include "pal/synchobjects.hpp" -#include "pal/synchcache.hpp" -#include "pal/corunix.hpp" -#include "pal/thread.hpp" -#include "pal/procobj.hpp" -#include "pal/init.h" -#include "pal/process.h" - -#include -#include -#include "pal/dbgmsg.h" - -#ifdef _DEBUG -// #define SYNCH_OBJECT_VALIDATION -// #define SYNCH_STATISTICS -#endif - -#ifdef SYNCH_OBJECT_VALIDATION -#define VALIDATEOBJECT(obj) ((obj)->ValidateObject()) -#else -#define VALIDATEOBJECT(obj) -#endif - -namespace CorUnix -{ - const DWORD WTLN_FLAG_WAIT_ALL = 1<<1; - -#ifdef SYNCH_OBJECT_VALIDATION - const DWORD HeadSignature = 0x48454144; - const DWORD TailSignature = 0x5441494C; - const DWORD EmptySignature = 0xBAADF00D; -#endif - - enum THREAD_WAIT_STATE - { - TWS_ACTIVE, - TWS_WAITING, - TWS_EARLYDEATH, - }; - - enum WaitCompletionState - { - WaitIsNotSatisfied, - WaitIsSatisfied - }; - - typedef union _SynchDataGenrPtr - { - SharedID shrid; - CSynchData * ptr; - } SynchDataGenrPtr; - - typedef union _WTLNodeGenrPtr - { - SharedID shrid; - struct _WaitingThreadsListNode * ptr; - } WTLNodeGenrPtr; - - typedef struct _WaitingThreadsListNode - { -#ifdef SYNCH_OBJECT_VALIDATION - DWORD dwDebugHeadSignature; -#endif - WTLNodeGenrPtr ptrNext; - WTLNodeGenrPtr ptrPrev; - - // Data - DWORD dwThreadId; - DWORD dwObjIndex; - DWORD dwFlags; - - // Pointers to related objects - SharedID shridWaitingState; - SynchDataGenrPtr ptrOwnerObjSynchData; - struct _ThreadWaitInfo * ptwiWaitInfo; // valid only in the - // target process -#ifdef SYNCH_OBJECT_VALIDATION - _WaitingThreadsListNode(); - ~_WaitingThreadsListNode(); - void ValidateObject(void); - void ValidateEmptyObject(void); - void InvalidateObject(void); - - DWORD dwDebugTailSignature; -#endif - } WaitingThreadsListNode; - - typedef struct _DeferredSignalingListNode - { - LIST_ENTRY Link; - CPalThread * pthrTarget; - } DeferredSignalingListNode; - - class CPalSynchronizationManager; // fwd declaration - class CProcProcessLocalData; // fwd declaration - - class CSynchData - { -#ifdef SYNCH_OBJECT_VALIDATION - DWORD m_dwDebugHeadSignature; -#endif - // NB: For perforformance purposes this class is supposed - // to have no virtual methods, and no destructor. - - WTLNodeGenrPtr m_ptrWTLHead; - WTLNodeGenrPtr m_ptrWTLTail; - ULONG m_ulcWaitingThreads; - PalObjectTypeId m_otiObjectTypeId; - LONG m_lRefCount; - LONG m_lSignalCount; - -#ifdef SYNCH_STATISTICS - ULONG m_lStatWaitCount; - ULONG m_lStatContentionCount; -#endif - - public: - CSynchData() - : m_ulcWaitingThreads(0), m_lRefCount(1), - m_lSignalCount(0) - { - // m_ptrWTLHead, m_ptrWTLTail - // and m_otiObjectTypeId are initialized by - // CPalSynchronizationManager::AllocateObjectSynchData -#ifdef SYNCH_STATISTICS - m_lStatWaitCount = 0; - m_lStatContentionCount = 0; -#endif -#ifdef SYNCH_OBJECT_VALIDATION - ValidateEmptyObject(); - m_dwDebugHeadSignature = HeadSignature;; - m_dwDebugTailSignature = TailSignature; -#endif - } - - LONG AddRef() - { - return InterlockedIncrement(&m_lRefCount); - } - - LONG Release(CPalThread * pthrCurrent); - - bool CanWaiterWaitWithoutBlocking( - CPalThread * pWaiterThread); - - PAL_ERROR ReleaseWaiterWithoutBlocking( - CPalThread * pthrCurrent, - CPalThread * pthrTarget); - - void WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode); - - // Object Type accessor methods - CObjectType * GetObjectType(void) - { - return CObjectType::GetObjectTypeById(m_otiObjectTypeId); - } - PalObjectTypeId GetObjectTypeId(void) - { - return m_otiObjectTypeId; - } - void SetObjectType(CObjectType * pot) - { - m_otiObjectTypeId = pot->GetId(); - } - void SetObjectType(PalObjectTypeId oti) - { - m_otiObjectTypeId = oti; - } - - void Signal( - CPalThread * pthrCurrent, - LONG lSignalCount); - - bool ReleaseFirstWaiter( - CPalThread * pthrCurrent); - - LONG ReleaseAllLocalWaiters( - CPalThread * pthrCurrent); - - WaitCompletionState IsRestOfWaitAllSatisfied( - WaitingThreadsListNode * pwtlnNode); - - // Object signal count accessor methods - LONG GetSignalCount(void) - { - _ASSERTE(m_lSignalCount >= 0); - return m_lSignalCount; - } - void SetSignalCount(LONG lSignalCount) - { - _ASSERTE(m_lSignalCount >= 0); - _ASSERTE(lSignalCount >= 0); - m_lSignalCount = lSignalCount; - } - LONG DecrementSignalCount(void) - { - _ASSERTE(m_lSignalCount > 0); - return --m_lSignalCount; - } - - void IncrementWaitingThreadCount(void) - { - m_ulcWaitingThreads += 1; - } - void DecrementWaitingThreadCount(void) - { - m_ulcWaitingThreads -= 1; - } - ULONG GetWaitingThreadCount(void) - { - return m_ulcWaitingThreads; - } - - -#ifdef SYNCH_STATISTICS - void IncrementStatWaitCount(void) - { - m_lStatWaitCount++; - } - LONG GetStatWaitCount(void) - { - return m_lStatWaitCount; - } - void IncrementStatContentionCount(void) - { - m_lStatContentionCount++; - } - LONG GetStatContentionCount(void) - { - return m_lStatContentionCount; - } -#endif - // - // Wating threads list access methods - // - WaitingThreadsListNode * GetWTLHeadPtr(void) - { - return m_ptrWTLHead.ptr; - } - WaitingThreadsListNode * GetWTLTailPtr(void) - { - return m_ptrWTLTail.ptr; - } - SharedID GetWTLHeadShmPtr(void) - { - return m_ptrWTLHead.shrid; - } - SharedID GetWTLTailShmPtr(void) - { - return m_ptrWTLTail.shrid; - } - void SetWTLHeadPtr(WaitingThreadsListNode * p) - { - m_ptrWTLHead.ptr = p; - } - void SetWTLTailPtr(WaitingThreadsListNode * p) - { - m_ptrWTLTail.ptr = p; - } - void SetWTLHeadShrPtr(SharedID shrid) - { - m_ptrWTLHead.shrid = shrid; - } - void SetWTLTailShrPtr(SharedID shrid) - { - m_ptrWTLTail.shrid = shrid; - } -#ifdef SYNCH_OBJECT_VALIDATION - ~CSynchData(); - void ValidateObject(bool fDestructor = false); - void ValidateEmptyObject(void); - void InvalidateObject(void); - - DWORD m_dwDebugTailSignature; -#endif - }; - - - class CSynchControllerBase - { - friend class CPalSynchronizationManager; - - // NB: For perforformance purposes this class is supposed - // to have no virtual methods, constructor and - // destructor - public: - enum ControllerType { WaitController, StateController }; - - protected: - CPalThread * m_pthrOwner; - ControllerType m_ctCtrlrType; - CObjectType * m_potObjectType; - CSynchData * m_psdSynchData; - - PAL_ERROR Init( - CPalThread * pthrCurrent, - ControllerType ctCtrlrType, - CObjectType *potObjectType, - CSynchData * psdSynchData); - - void Release(void); - - void SetSynchData(CSynchData * psdSynchData) - { - m_psdSynchData = psdSynchData; - } - CSynchData * GetSynchData() - { - return m_psdSynchData; - } - }; - - class CSynchWaitController : public CSynchControllerBase, - public ISynchWaitController - { - public: - CSynchWaitController() = default; - virtual ~CSynchWaitController() = default; - - // - // ISynchWaitController methods - // - virtual PAL_ERROR CanThreadWaitWithoutBlocking( - bool * pfCanWaitWithoutBlocking); - - virtual PAL_ERROR ReleaseWaitingThreadWithoutBlocking(void); - - virtual PAL_ERROR RegisterWaitingThread( - WaitType wtWaitType, - DWORD dwIndex); - - virtual void ReleaseController(void); - }; - - class CSynchStateController : public CSynchControllerBase, - public ISynchStateController - { - public: - // NB: For perforformance purposes this class is supposed - // to have no constructor - virtual ~CSynchStateController() = default; - - // - // ISynchStateController methods - // - virtual PAL_ERROR GetSignalCount(LONG *plSignalCount); - virtual PAL_ERROR SetSignalCount(LONG lNewCount); - virtual PAL_ERROR IncrementSignalCount(LONG lAmountToIncrement); - virtual PAL_ERROR DecrementSignalCount(LONG lAmountToDecrement); - virtual void ReleaseController(void); - }; - - class CPalSynchronizationManager : public IPalSynchronizationManager - { - friend class CPalSynchMgrController; - - public: - // types - typedef CSynchCache CSynchWaitControllerCache; - typedef CSynchCache CSynchStateControllerCache; - typedef CSynchCache CSynchDataCache; - typedef CSHRSynchCache CSHRSynchDataCache; - typedef CSynchCache CWaitingThreadsListNodeCache; - typedef CSHRSynchCache CSHRWaitingThreadsListNodeCache; - - private: - // types - enum InitStatus - { - SynchMgrStatusIdle, - SynchMgrStatusInitializing, - SynchMgrStatusRunning, - SynchMgrStatusShuttingDown, - SynchMgrStatusReadyForProcessShutDown, - SynchMgrStatusError - }; - - // constants - static const int CtrlrsCacheMaxSize = 256; - static const int SynchDataCacheMaxSize = 256; - static const int WTListNodeCacheMaxSize = 256; - static const DWORD SecondNativeWaitTimeout = INFINITE; - - // static members - static CPalSynchronizationManager * s_pObjSynchMgr; - static Volatile s_lInitStatus; - static minipal_mutex s_csSynchProcessLock; - - // caches - CSynchWaitControllerCache m_cacheWaitCtrlrs; - CSynchStateControllerCache m_cacheStateCtrlrs; - CSynchDataCache m_cacheSynchData; - CSHRSynchDataCache m_cacheSHRSynchData; - CWaitingThreadsListNodeCache m_cacheWTListNodes; - CSHRWaitingThreadsListNodeCache m_cacheSHRWTListNodes; - - // static methods - static PAL_ERROR Initialize(); - - protected: - CPalSynchronizationManager(); - - PAL_ERROR GetSynchControllersForObjects( - CPalThread *pthrCurrent, - IPalObject *rgObjects[], - DWORD dwObjectCount, - void ** ppvControllers, - CSynchControllerBase::ControllerType ctCtrlrType); - - private: - static IPalSynchronizationManager * CreatePalSynchronizationManager(); - static PAL_ERROR PrepareForShutdown(void); - - public: - virtual ~CPalSynchronizationManager(); - - static CPalSynchronizationManager * GetInstance(void) - { - // No need here to check for NULL and in case create the - // singleton, since its creation is enforced by the PAL - // initialization code. - return s_pObjSynchMgr; - } - - // - // Inline utility methods - // - static void AcquireLocalSynchLock(CPalThread * pthrCurrent) - { - _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); - - if (1 == ++pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount) - { - minipal_mutex_enter(&s_csSynchProcessLock); - } - } - static void ReleaseLocalSynchLock(CPalThread * pthrCurrent) - { - _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); - if (0 == --pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount) - { - minipal_mutex_leave(&s_csSynchProcessLock); - -#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings(); -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - } - } - static LONG ResetLocalSynchLock(CPalThread * pthrCurrent) - { - LONG lRet = pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount; - - _ASSERTE(0 <= lRet); - if (0 < lRet) - { - pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount = 0; - minipal_mutex_leave(&s_csSynchProcessLock); - -#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings(); -#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING - } - return lRet; - } - static LONG GetLocalSynchLockCount(CPalThread * pthrCurrent) - { - _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); - return pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount; - } - - CSynchWaitController * CacheGetWaitCtrlr(CPalThread * pthrCurrent) - { - return m_cacheWaitCtrlrs.Get(pthrCurrent); - } - int CacheGetWaitCtrlr( - CPalThread * pthrCurrent, - int n, - CSynchWaitController * prgCtrlrs[]) - { - return m_cacheWaitCtrlrs.Get(pthrCurrent, n, prgCtrlrs); - } - void CacheAddWaitCtrlr( - CPalThread * pthrCurrent, - CSynchWaitController * pCtrlr) - { - m_cacheWaitCtrlrs.Add(pthrCurrent, pCtrlr); - } - CSynchStateController * CacheGetStateCtrlr(CPalThread * pthrCurrent) - { - return m_cacheStateCtrlrs.Get(pthrCurrent); - } - int CacheGetStateCtrlr( - CPalThread * pthrCurrent, - int n, - CSynchStateController * prgCtrlrs[]) - { - return m_cacheStateCtrlrs.Get(pthrCurrent, n, prgCtrlrs); - } - void CacheAddStateCtrlr( - CPalThread * pthrCurrent, - CSynchStateController * pCtrlr) - { - m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr); - } - - CSynchData * CacheGetLocalSynchData(CPalThread * pthrCurrent) - { - return m_cacheSynchData.Get(pthrCurrent); - } - void CacheAddLocalSynchData( - CPalThread * pthrCurrent, - CSynchData * psdSynchData) - { - m_cacheSynchData.Add(pthrCurrent, psdSynchData); - } - SharedID CacheGetSharedSynchData(CPalThread * pthrCurrent) - { - return m_cacheSHRSynchData.Get(pthrCurrent); - } - void CacheAddSharedSynchData( - CPalThread * pthrCurrent, - SharedID shridSData) - { - m_cacheSHRSynchData.Add(pthrCurrent, shridSData); - } - - WaitingThreadsListNode * CacheGetLocalWTListNode( - CPalThread * pthrCurrent) - { - return m_cacheWTListNodes.Get(pthrCurrent); - } - void CacheAddLocalWTListNode( - CPalThread * pthrCurrent, - WaitingThreadsListNode * pWTLNode) - { - m_cacheWTListNodes.Add(pthrCurrent, pWTLNode); - } - SharedID CacheGetSharedWTListNode(CPalThread * pthrCurrent) - { - return m_cacheSHRWTListNodes.Get(pthrCurrent); - } - void CacheAddSharedWTListNode( - CPalThread * pthrCurrent, - SharedID shridWTLNode) - { - m_cacheSHRWTListNodes.Add(pthrCurrent, shridWTLNode); - } - - // - // IPalSynchronizationManager methods - // - virtual PAL_ERROR BlockThread( - CPalThread *pthrCurrent, - DWORD dwTimeout, - bool fIsSleep, - ThreadWakeupReason *ptwrWakeupReason, - DWORD *pdwSignaledObject); - - virtual PAL_ERROR GetSynchWaitControllersForObjects( - CPalThread *pthrCurrent, - IPalObject *rgObjects[], - DWORD dwObjectCount, - ISynchWaitController *rgControllers[]); - - virtual PAL_ERROR GetSynchStateControllersForObjects( - CPalThread *pthrCurrent, - IPalObject *rgObjects[], - DWORD dwObjectCount, - ISynchStateController *rgControllers[]); - - virtual PAL_ERROR AllocateObjectSynchData( - CObjectType *potObjectType, - VOID **ppvSynchData); - - virtual void FreeObjectSynchData( - CObjectType *potObjectType, - VOID *pvSynchData); - - virtual PAL_ERROR CreateSynchStateController( - CPalThread *pthrCurrent, - CObjectType *potObjectType, - VOID *pvSynchData, - ISynchStateController **ppStateController); - - virtual PAL_ERROR CreateSynchWaitController( - CPalThread *pthrCurrent, - CObjectType *potObjectType, - VOID *pvSynchData, - ISynchWaitController **ppWaitController); - - virtual void AcquireProcessLock(CPalThread *pthrCurrent); - - virtual void ReleaseProcessLock(CPalThread *pthrCurrent); - - // - // Static helper methods - // - public: - static PAL_ERROR WakeUpLocalThread( - CPalThread * pthrCurrent, - CPalThread * pthrTarget, - ThreadWakeupReason twrWakeupReason, - DWORD dwObjectIndex); - - static PAL_ERROR SignalThreadCondition( - ThreadNativeWaitData * ptnwdNativeWaitData); - - static PAL_ERROR DeferThreadConditionSignaling( - CPalThread * pthrCurrent, - CPalThread * pthrTarget); - - static ThreadWaitInfo * GetThreadWaitInfo( - CPalThread * pthrCurrent); - - // - // The following methods must be called only by a Sync*Controller or - // while holding the required synchronization global locks - // - static void UnsignalRestOfLocalAwakeningWaitAll( - CPalThread * pthrCurrent, - CPalThread * pthrTarget, - WaitingThreadsListNode * pwtlnNode, - CSynchData * psdTgtObjectSynchData); - - static PAL_ERROR ThreadNativeWait( - ThreadNativeWaitData * ptnwdNativeWaitData, - DWORD dwTimeout, - ThreadWakeupReason * ptwrWakeupReason, - DWORD * pdwSignaledObject); - - static void ThreadPrepareForShutdown(void); - - public: - // - // The following methods must be called only by a Sync*Controller or - // while holding the required synchronization global locks - // - void UnRegisterWait( - CPalThread * pthrCurrent, - ThreadWaitInfo * ptwiWaitInfo); - - // - // Utility static methods, no lock required - // - static bool InterlockedAwaken( - DWORD *pWaitState); - - static PAL_ERROR GetAbsoluteTimeout( - DWORD dwTimeout, - struct timespec * ptsAbsTmo); - }; -} - -#endif // _SYNCHMANAGER_HPP_ diff --git a/src/coreclr/pal/src/synchmgr/wait.cpp b/src/coreclr/pal/src/synchmgr/wait.cpp deleted file mode 100644 index 0821e496f7d87e..00000000000000 --- a/src/coreclr/pal/src/synchmgr/wait.cpp +++ /dev/null @@ -1,520 +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: - - wait.cpp - -Abstract: - - Implementation of waiting functions as described in - the WIN32 API - -Revision History: - - - ---*/ - -#include "pal/thread.hpp" -#include "pal/synchobjects.hpp" -#include "pal/handlemgr.hpp" -#include "pal/event.hpp" -#include "pal/dbgmsg.h" -#include - -SET_DEFAULT_DEBUG_CHANNEL(SYNC); - -#define MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE (MAXIMUM_WAIT_OBJECTS / 4) - -using namespace CorUnix; - -static PalObjectTypeId sg_rgWaitObjectsIds[] = - { - otiAutoResetEvent, - otiManualResetEvent, - otiThread - }; -static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds, - sizeof(sg_rgWaitObjectsIds)/sizeof(sg_rgWaitObjectsIds[0])); - -static PalObjectTypeId sg_rgSignalableObjectIds[] = -{ - otiAutoResetEvent, - otiManualResetEvent -}; -static CAllowedObjectTypes sg_aotSignalableObject(sg_rgSignalableObjectIds, ARRAY_SIZE(sg_rgSignalableObjectIds)); - -/*++ -Function: - WaitForSingleObject - -See MSDN doc. ---*/ -DWORD -PALAPI -WaitForSingleObject(IN HANDLE hHandle, - IN DWORD dwMilliseconds) -{ - DWORD dwRet; - - PERF_ENTRY(WaitForSingleObject); - ENTRY("WaitForSingleObject(hHandle=%p, dwMilliseconds=%u)\n", - hHandle, dwMilliseconds); - - CPalThread * pThread = InternalGetCurrentThread(); - - dwRet = InternalWaitForMultipleObjectsEx(pThread, 1, &hHandle, FALSE, - dwMilliseconds); - - LOGEXIT("WaitForSingleObject returns DWORD %u\n", dwRet); - PERF_EXIT(WaitForSingleObject); - return dwRet; -} - -/*++ -Function: - WaitForSingleObjectEx - -See MSDN doc. ---*/ -DWORD -PALAPI -WaitForSingleObjectEx(IN HANDLE hHandle, - IN DWORD dwMilliseconds, - IN BOOL bAlertable) -{ - DWORD dwRet; - - PERF_ENTRY(WaitForSingleObjectEx); - ENTRY("WaitForSingleObjectEx(hHandle=%p, dwMilliseconds=%u, bAlertable=%s)\n", - hHandle, dwMilliseconds, bAlertable ? "TRUE" : "FALSE"); - - CPalThread * pThread = InternalGetCurrentThread(); - - dwRet = InternalWaitForMultipleObjectsEx(pThread, 1, &hHandle, FALSE, - dwMilliseconds); - - LOGEXIT("WaitForSingleObjectEx returns DWORD %u\n", dwRet); - PERF_EXIT(WaitForSingleObjectEx); - return dwRet; -} - - -/*++ -Function: - WaitForMultipleObjectsEx - -See MSDN doc for info about this function. ---*/ -DWORD -PALAPI -WaitForMultipleObjectsEx(IN DWORD nCount, - IN CONST HANDLE *lpHandles, - IN BOOL bWaitAll, - IN DWORD dwMilliseconds, - IN BOOL bAlertable) -{ - DWORD dwRet; - - PERF_ENTRY(WaitForMultipleObjectsEx); - ENTRY("WaitForMultipleObjectsEx(nCount=%d, lpHandles=%p," - " bWaitAll=%d, dwMilliseconds=%u, bAlertable=%s)\n", - nCount, lpHandles, bWaitAll, dwMilliseconds, bAlertable ? "TRUE" : "FALSE"); - - CPalThread * pThread = InternalGetCurrentThread(); - - dwRet = InternalWaitForMultipleObjectsEx(pThread, nCount, lpHandles, bWaitAll, - dwMilliseconds); - - LOGEXIT("WaitForMultipleObjectsEx returns DWORD %u\n", dwRet); - PERF_EXIT(WaitForMultipleObjectsEx); - return dwRet; -} - -/*++ -Function: - Sleep - -See MSDN doc. ---*/ -VOID -PALAPI -Sleep(IN DWORD dwMilliseconds) -{ - PERF_ENTRY(Sleep); - ENTRY("Sleep(dwMilliseconds=%u)\n", dwMilliseconds); - - CPalThread * pThread = InternalGetCurrentThread(); - - DWORD internalSleepRet = InternalSleepEx(pThread, dwMilliseconds); - - if (internalSleepRet != 0) - { - ERROR("Sleep(dwMilliseconds=%u) failed [error=%u]\n", dwMilliseconds, internalSleepRet); - pThread->SetLastError(internalSleepRet); - } - - LOGEXIT("Sleep returns VOID\n"); - PERF_EXIT(Sleep); -} - - -/*++ -Function: - SleepEx - -See MSDN doc. ---*/ -DWORD -PALAPI -SleepEx(IN DWORD dwMilliseconds, - IN BOOL bAlertable) -{ - DWORD dwRet; - - PERF_ENTRY(SleepEx); - ENTRY("SleepEx(dwMilliseconds=%u, bAlertable=%d)\n", dwMilliseconds, bAlertable); - - CPalThread * pThread = InternalGetCurrentThread(); - - dwRet = InternalSleepEx(pThread, dwMilliseconds); - - LOGEXIT("SleepEx returns DWORD %u\n", dwRet); - PERF_EXIT(SleepEx); - - return dwRet; -} - -DWORD CorUnix::InternalWaitForMultipleObjectsEx( - CPalThread * pThread, - DWORD nCount, - CONST HANDLE *lpHandles, - BOOL bWaitAll, - DWORD dwMilliseconds) -{ - DWORD dwRet = WAIT_FAILED; - PAL_ERROR palErr = NO_ERROR; - int i, iSignaledObjCount, iSignaledObjIndex = -1; - bool fWAll = (bool)bWaitAll, fNeedToBlock = false; - WaitType wtWaitType; - - IPalObject * pIPalObjStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL }; - ISynchWaitController * pISyncStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL }; - IPalObject ** ppIPalObjs = pIPalObjStackArray; - ISynchWaitController ** ppISyncWaitCtrlrs = pISyncStackArray; - - if ((nCount == 0) || (nCount > MAXIMUM_WAIT_OBJECTS)) - { - ppIPalObjs = NULL; // make delete at the end safe - ppISyncWaitCtrlrs = NULL; // make delete at the end safe - ERROR("Invalid object count=%d [range: 1 to %d]\n", - nCount, MAXIMUM_WAIT_OBJECTS) - pThread->SetLastError(ERROR_INVALID_PARAMETER); - goto WFMOExIntExit; - } - else if (nCount == 1) - { - fWAll = false; // makes no difference when nCount is 1 - wtWaitType = SingleObject; - } - else - { - wtWaitType = fWAll ? MultipleObjectsWaitAll : MultipleObjectsWaitOne; - if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE) - { - ppIPalObjs = new(std::nothrow) IPalObject*[nCount]; - ppISyncWaitCtrlrs = new(std::nothrow) ISynchWaitController*[nCount]; - if ((NULL == ppIPalObjs) || (NULL == ppISyncWaitCtrlrs)) - { - ERROR("Out of memory allocating internal structures\n"); - pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto WFMOExIntExit; - } - } - } - - palErr = g_pObjectManager->ReferenceMultipleObjectsByHandleArray(pThread, - (VOID **)lpHandles, - nCount, - &sg_aotWaitObject, - ppIPalObjs); - if (NO_ERROR != palErr) - { - ERROR("Unable to obtain object for some or all of the handles [error=%u]\n", - palErr); - if (palErr == ERROR_INVALID_HANDLE) - pThread->SetLastError(ERROR_INVALID_HANDLE); - else - pThread->SetLastError(ERROR_INTERNAL_ERROR); - goto WFMOExIntExit; - } - - if (fWAll) - { - // For a wait-all operation, check for duplicate wait objects in the array. This just uses a brute-force O(n^2) - // algorithm, but since MAXIMUM_WAIT_OBJECTS is small, the worst case is not so bad, and the average case would involve - // significantly fewer items. - for (DWORD i = 0; i < nCount - 1; ++i) - { - IPalObject *const objectToCheck = ppIPalObjs[i]; - for (DWORD j = i + 1; j < nCount; ++j) - { - if (ppIPalObjs[j] == objectToCheck) - { - ERROR("Duplicate handle provided for a wait-all operation [error=%u]\n", ERROR_INVALID_PARAMETER); - pThread->SetLastError(ERROR_INVALID_PARAMETER); - goto WFMOExIntCleanup; - } - } - } - } - - palErr = g_pSynchronizationManager->GetSynchWaitControllersForObjects( - pThread, ppIPalObjs, nCount, ppISyncWaitCtrlrs); - if (NO_ERROR != palErr) - { - ERROR("Unable to obtain ISynchWaitController interface for some or all " - "of the objects [error=%u]\n", palErr); - pThread->SetLastError(ERROR_INTERNAL_ERROR); - goto WFMOExIntCleanup; - } - - iSignaledObjCount = 0; - iSignaledObjIndex = -1; - for (i=0;i<(int)nCount;i++) - { - bool fValue; - palErr = ppISyncWaitCtrlrs[i]->CanThreadWaitWithoutBlocking(&fValue); - if (NO_ERROR != palErr) - { - ERROR("ISynchWaitController::CanThreadWaitWithoutBlocking() failed for " - "%d-th object [handle=%p error=%u]\n", i, lpHandles[i], palErr); - pThread->SetLastError(ERROR_INTERNAL_ERROR); - goto WFMOExIntReleaseControllers; - } - if (fValue) - { - iSignaledObjCount++; - iSignaledObjIndex = i; - if (!fWAll) - break; - } - } - - fNeedToBlock = (iSignaledObjCount == 0) || (fWAll && (iSignaledObjCount < (int)nCount)); - if (!fNeedToBlock) - { - // At least one object signaled, or bWaitAll==TRUE and all object signaled. - // No need to wait, let's unsignal the object(s) and return without blocking - int iStartIdx, iEndIdx; - - if (fWAll) - { - iStartIdx = 0; - iEndIdx = nCount; - } - else - { - iStartIdx = iSignaledObjIndex; - iEndIdx = iStartIdx + 1; - } - - // Unsignal objects - if( iStartIdx < 0 ) - { - ERROR("Buffer underflow due to iStartIdx < 0"); - pThread->SetLastError(ERROR_INTERNAL_ERROR); - dwRet = WAIT_FAILED; - goto WFMOExIntCleanup; - } - for (i = iStartIdx; i < iEndIdx; i++) - { - palErr = ppISyncWaitCtrlrs[i]->ReleaseWaitingThreadWithoutBlocking(); - if (NO_ERROR != palErr) - { - ERROR("ReleaseWaitingThreadWithoutBlocking() failed for %d-th " - "object [handle=%p error=%u]\n", - i, lpHandles[i], palErr); - pThread->SetLastError(palErr); - goto WFMOExIntReleaseControllers; - } - } - - dwRet = WAIT_OBJECT_0; - } - else if (0 == dwMilliseconds) - { - // Not enough objects signaled, but timeout is zero: no actual wait - dwRet = WAIT_TIMEOUT; - fNeedToBlock = false; - } - else - { - // Register the thread for waiting on all objects - for (i=0;i<(int)nCount;i++) - { - palErr = ppISyncWaitCtrlrs[i]->RegisterWaitingThread( - wtWaitType, - i); - if (NO_ERROR != palErr) - { - ERROR("RegisterWaitingThread() failed for %d-th object " - "[handle=%p error=%u]\n", i, lpHandles[i], palErr); - pThread->SetLastError(palErr); - goto WFMOExIntReleaseControllers; - } - } - } - -WFMOExIntReleaseControllers: - // Release all controllers before going to sleep - for (i = 0; i < (int)nCount; i++) - { - ppISyncWaitCtrlrs[i]->ReleaseController(); - ppISyncWaitCtrlrs[i] = NULL; - } - if (NO_ERROR != palErr) - goto WFMOExIntCleanup; - - if (fNeedToBlock) - { -#ifndef FEATURE_MULTITHREADING - // In single-threaded WASM, blocking would deadlock because there is no other - // thread to signal the object. This is a programming error. - _ASSERT_MSG(false, "Cannot block on wait in single-threaded mode\n"); - pThread->SetLastError(ERROR_NOT_SUPPORTED); - dwRet = WAIT_FAILED; - goto WFMOExIntCleanup; -#else // !FEATURE_MULTITHREADING - ThreadWakeupReason twrWakeupReason; - - // - // Going to sleep - // - palErr = g_pSynchronizationManager->BlockThread(pThread, - dwMilliseconds, - false, - &twrWakeupReason, - (DWORD *)&iSignaledObjIndex); - // - // Awakened - // - if (NO_ERROR != palErr) - { - ERROR("IPalSynchronizationManager::BlockThread failed for thread " - "pThread=%p [error=%u]\n", pThread, palErr); - pThread->SetLastError(palErr); - goto WFMOExIntCleanup; - } - switch (twrWakeupReason) - { - case WaitSucceeded: - dwRet = WAIT_OBJECT_0; // offset added later - break; - case WaitTimeout: - dwRet = WAIT_TIMEOUT; - break; - case WaitFailed: - default: - ERROR("Thread %p awakened with some failure\n", pThread); - dwRet = WAIT_FAILED; - break; - } -#endif // !FEATURE_MULTITHREADING - } - - if (!fWAll && (WAIT_OBJECT_0 == dwRet)) - { - _ASSERT_MSG(0 <= iSignaledObjIndex, - "Failed to identify signaled object\n"); - _ASSERT_MSG(iSignaledObjIndex >= 0 && nCount > static_cast(iSignaledObjIndex), - "SignaledObjIndex object out of range " - "[index=%d obj_count=%u\n", - iSignaledObjIndex, nCount); - - if (iSignaledObjIndex < 0) - { - pThread->SetLastError(ERROR_INTERNAL_ERROR); - dwRet = WAIT_FAILED; - goto WFMOExIntCleanup; - } - dwRet += iSignaledObjIndex; - } - -WFMOExIntCleanup: - for (i = 0; i < (int)nCount; i++) - { - ppIPalObjs[i]->ReleaseReference(pThread); - ppIPalObjs[i] = NULL; - } - -WFMOExIntExit: - if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE) - { - delete[] ppIPalObjs; - delete[] ppISyncWaitCtrlrs; - } - - return dwRet; -} - -DWORD CorUnix::InternalSleepEx ( - CPalThread * pThread, - DWORD dwMilliseconds) -{ -#ifndef FEATURE_MULTITHREADING - // In single-threaded WASM, Sleep returns immediately. - // There's no other thread that could make progress while we sleep. - (void)pThread; - (void)dwMilliseconds; - return 0; -#else // !FEATURE_MULTITHREADING - PAL_ERROR palErr = NO_ERROR; - DWORD dwRet = WAIT_FAILED; - int iSignaledObjIndex; - - TRACE("Sleeping %u ms", dwMilliseconds); - - if (dwMilliseconds > 0) - { - ThreadWakeupReason twrWakeupReason; - palErr = g_pSynchronizationManager->BlockThread(pThread, - dwMilliseconds, - true, - &twrWakeupReason, - (DWORD *)&iSignaledObjIndex); - if (NO_ERROR != palErr) - { - ERROR("IPalSynchronizationManager::BlockThread failed for thread " - "pThread=%p [error=%u]\n", pThread, palErr); - return dwRet; - } - - switch (twrWakeupReason) - { - case WaitSucceeded: - case WaitTimeout: - dwRet = 0; - break; - - case WaitFailed: - default: - ERROR("Thread %p awakened with some failure\n", pThread); - break; - } - } - else - { - sched_yield(); - dwRet = 0; - } - - TRACE("Done sleeping %u ms", dwMilliseconds); - return dwRet; -#endif // !FEATURE_MULTITHREADING -} diff --git a/src/coreclr/pal/src/synchobj/event.cpp b/src/coreclr/pal/src/synchobj/event.cpp deleted file mode 100644 index c59ebf52a05946..00000000000000 --- a/src/coreclr/pal/src/synchobj/event.cpp +++ /dev/null @@ -1,463 +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: - - event.cpp - -Abstract: - - Implementation of event synchronization object as described in - the WIN32 API - -Revision History: - - - ---*/ - -#include "pal/event.hpp" -#include "pal/thread.hpp" -#include "pal/dbgmsg.h" - -using namespace CorUnix; - -/* ------------------- Definitions ------------------------------*/ -SET_DEFAULT_DEBUG_CHANNEL(SYNC); - -CObjectType CorUnix::otManualResetEvent( - otiManualResetEvent, - NULL, // No cleanup routine - 0, // No immutable data - 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::ThreadReleaseHasNoSideEffects - ); - -CObjectType CorUnix::otAutoResetEvent( - otiAutoResetEvent, - NULL, // No cleanup routine - 0, // No immutable data - 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 - ); - -PalObjectTypeId rgEventIds[] = {otiManualResetEvent, otiAutoResetEvent}; -CAllowedObjectTypes aotEvent(rgEventIds, sizeof(rgEventIds)/sizeof(rgEventIds[0])); - -/*++ -Function: - CreateEventW - -Note: - lpEventAttributes currently ignored: - -- Win32 object security not supported - -- handles to event objects are not inheritable - -Parameters: - See MSDN doc. ---*/ - -HANDLE -PALAPI -CreateEventW( - IN LPSECURITY_ATTRIBUTES lpEventAttributes, - IN BOOL bManualReset, - IN BOOL bInitialState, - IN LPCWSTR lpName) -{ - HANDLE hEvent = NULL; - PAL_ERROR palError; - CPalThread *pthr = NULL; - - PERF_ENTRY(CreateEventW); - ENTRY("CreateEventW(lpEventAttr=%p, bManualReset=%d, " - "bInitialState=%d, lpName=%p (%S)\n", lpEventAttributes, bManualReset, - bInitialState, lpName, lpName?lpName:W16_NULLSTRING); - - pthr = InternalGetCurrentThread(); - - palError = InternalCreateEvent( - pthr, - lpEventAttributes, - bManualReset, - bInitialState, - lpName, - &hEvent - ); - - // - // 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("CreateEventW returns HANDLE %p\n", hEvent); - PERF_EXIT(CreateEventW); - return hEvent; -} - -/*++ -Function: - CreateEventExW - -Note: - lpEventAttributes and dwDesiredAccess are currently ignored: - -- Win32 object security not supported - -- handles to event objects are not inheritable - -- Access rights are not supported - -Parameters: - See MSDN doc. ---*/ - -HANDLE -PALAPI -CreateEventExW( - IN LPSECURITY_ATTRIBUTES lpEventAttributes, - IN LPCWSTR lpName, - IN DWORD dwFlags, - IN DWORD dwDesiredAccess) -{ - return - CreateEventW( - lpEventAttributes, - (dwFlags & CREATE_EVENT_MANUAL_RESET) != 0, - (dwFlags & CREATE_EVENT_INITIAL_SET) != 0, - lpName); -} - -/*++ -Function: - InternalCreateEvent - -Note: - lpEventAttributes currently ignored: - -- Win32 object security not supported - -- handles to event objects are not inheritable - -Parameters: - pthr -- thread data for calling thread - phEvent -- on success, receives the allocated event handle - - See MSDN docs on CreateEvent for all other parameters ---*/ - -PAL_ERROR -CorUnix::InternalCreateEvent( - CPalThread *pthr, - LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, - BOOL bInitialState, - LPCWSTR lpName, - HANDLE *phEvent - ) -{ - CObjectAttributes oa(lpName, lpEventAttributes); - PAL_ERROR palError = NO_ERROR; - IPalObject *pobjEvent = NULL; - IPalObject *pobjRegisteredEvent = NULL; - - _ASSERTE(NULL != pthr); - _ASSERTE(NULL != phEvent); - - ENTRY("InternalCreateEvent(pthr=%p, lpEventAttributes=%p, bManualReset=%i, " - "bInitialState=%i, lpName=%p, phEvent=%p)\n", - pthr, - lpEventAttributes, - bManualReset, - bInitialState, - lpName, - phEvent - ); - - if (lpName != nullptr) - { - ASSERT("lpName: Cross-process named objects are not supported in PAL"); - palError = ERROR_NOT_SUPPORTED; - goto InternalCreateEventExit; - } - - palError = g_pObjectManager->AllocateObject( - pthr, - bManualReset ? &otManualResetEvent : &otAutoResetEvent, - &oa, - &pobjEvent - ); - - if (NO_ERROR != palError) - { - goto InternalCreateEventExit; - } - - if (bInitialState) - { - ISynchStateController *pssc; - - palError = pobjEvent->GetSynchStateController( - pthr, - &pssc - ); - - if (NO_ERROR == palError) - { - palError = pssc->SetSignalCount(1); - pssc->ReleaseController(); - } - - if (NO_ERROR != palError) - { - ASSERT("Unable to set new event state (%d)\n", palError); - goto InternalCreateEventExit; - } - } - - palError = g_pObjectManager->RegisterObject( - pthr, - pobjEvent, - &aotEvent, - phEvent, - &pobjRegisteredEvent - ); - - // - // pobjEvent 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. - // - - pobjEvent = NULL; - -InternalCreateEventExit: - - if (NULL != pobjEvent) - { - pobjEvent->ReleaseReference(pthr); - } - - if (NULL != pobjRegisteredEvent) - { - pobjRegisteredEvent->ReleaseReference(pthr); - } - - LOGEXIT("InternalCreateEvent returns %i\n", palError); - - return palError; -} - - -/*++ -Function: - SetEvent - -See MSDN doc. ---*/ - -BOOL -PALAPI -SetEvent( - IN HANDLE hEvent) -{ - PAL_ERROR palError = NO_ERROR; - CPalThread *pthr = NULL; - - PERF_ENTRY(SetEvent); - ENTRY("SetEvent(hEvent=%p)\n", hEvent); - - pthr = InternalGetCurrentThread(); - - palError = InternalSetEvent(pthr, hEvent, TRUE); - - if (NO_ERROR != palError) - { - pthr->SetLastError(palError); - } - - LOGEXIT("SetEvent returns BOOL %d\n", (NO_ERROR == palError)); - PERF_EXIT(SetEvent); - return (NO_ERROR == palError); -} - - -/*++ -Function: - ResetEvent - -See MSDN doc. ---*/ - -BOOL -PALAPI -ResetEvent( - IN HANDLE hEvent) -{ - PAL_ERROR palError = NO_ERROR; - CPalThread *pthr = NULL; - - PERF_ENTRY(ResetEvent); - ENTRY("ResetEvent(hEvent=%p)\n", hEvent); - - pthr = InternalGetCurrentThread(); - - palError = InternalSetEvent(pthr, hEvent, FALSE); - - if (NO_ERROR != palError) - { - pthr->SetLastError(palError); - } - - LOGEXIT("ResetEvent returns BOOL %d\n", (NO_ERROR == palError)); - PERF_EXIT(ResetEvent); - return (NO_ERROR == palError); -} - -/*++ -Function: - InternalCreateEvent - -Parameters: - pthr -- thread data for calling thread - hEvent -- handle to the event to set - fSetEvent -- if TRUE, set the event; if FALSE, reset it ---*/ - -PAL_ERROR -CorUnix::InternalSetEvent( - CPalThread *pthr, - HANDLE hEvent, - BOOL fSetEvent - ) -{ - PAL_ERROR palError = NO_ERROR; - IPalObject *pobjEvent = NULL; - ISynchStateController *pssc = NULL; - - _ASSERTE(NULL != pthr); - - ENTRY("InternalSetEvent(pthr=%p, hEvent=%p, fSetEvent=%i\n", - pthr, - hEvent, - fSetEvent - ); - - palError = g_pObjectManager->ReferenceObjectByHandle( - pthr, - hEvent, - &aotEvent, - &pobjEvent - ); - - if (NO_ERROR != palError) - { - ERROR("Unable to obtain object for handle %p (error %d)!\n", hEvent, palError); - goto InternalSetEventExit; - } - - palError = pobjEvent->GetSynchStateController( - pthr, - &pssc - ); - - if (NO_ERROR != palError) - { - ASSERT("Error %d obtaining synch state controller\n", palError); - goto InternalSetEventExit; - } - - palError = pssc->SetSignalCount(fSetEvent ? 1 : 0); - - if (NO_ERROR != palError) - { - ASSERT("Error %d setting event state\n", palError); - goto InternalSetEventExit; - } - -InternalSetEventExit: - - if (NULL != pssc) - { - pssc->ReleaseController(); - } - - if (NULL != pobjEvent) - { - pobjEvent->ReleaseReference(pthr); - } - - LOGEXIT("InternalSetEvent returns %d\n", palError); - - return palError; -} - -// TODO: Implementation of OpenEventA() doesn't exist, do we need it? More generally, do we need the A versions at all? - -/*++ -Function: - OpenEventW - -Note: - dwDesiredAccess is currently ignored (no Win32 object security support) - bInheritHandle is currently ignored (handles to events are not inheritable) - -Parameters: - See MSDN doc. ---*/ - -HANDLE -PALAPI -OpenEventW( - IN DWORD dwDesiredAccess, - IN BOOL bInheritHandle, - IN LPCWSTR lpName) -{ - HANDLE hEvent = NULL; - PAL_ERROR palError = NO_ERROR; - CPalThread *pthr = NULL; - - PERF_ENTRY(OpenEventW); - ENTRY("OpenEventW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n", - dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING); - - pthr = InternalGetCurrentThread(); - - /* validate parameters */ - if (lpName == nullptr) - { - ERROR("name is NULL\n"); - palError = ERROR_INVALID_PARAMETER; - goto OpenEventWExit; - } - else - { - ASSERT("lpName: Cross-process named objects are not supported in PAL"); - palError = ERROR_NOT_SUPPORTED; - } - -OpenEventWExit: - - if (NO_ERROR != palError) - { - pthr->SetLastError(palError); - } - - LOGEXIT("OpenEventW returns HANDLE %p\n", hEvent); - PERF_EXIT(OpenEventW); - - return hEvent; -} diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index 543665e21ed5b6..f4cbeac4f0b5a8 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -101,10 +101,7 @@ CObjectType CorUnix::otThread( NULL, // No immutable data copy routine NULL, // No immutable data cleanup routine sizeof(CThreadProcessLocalData), - NULL, // No process local data cleanup routine - CObjectType::WaitableObject, - CObjectType::SingleTransitionObject, - CObjectType::ThreadReleaseHasNoSideEffects + NULL // No process local data cleanup routine ); CAllowedObjectTypes aotThread(otiThread); @@ -683,9 +680,6 @@ CorUnix::InternalEndCurrentThread( CPalThread *pThread ) { - PAL_ERROR palError = NO_ERROR; - ISynchStateController *pSynchStateController = NULL; - // // Need to synchronize setting the thread state to TS_DONE since // this is checked for in InternalSuspendThreadFromData. @@ -693,33 +687,9 @@ CorUnix::InternalEndCurrentThread( // pThread->suspensionInfo.AcquireSuspensionLock(pThread); - pThread->synchronizationInfo.SetThreadState(TS_DONE); + pThread->SetThreadState(TS_DONE); pThread->suspensionInfo.ReleaseSuspensionLock(pThread); - // - // Mark the thread object as signaled - // - - palError = pThread->GetThreadObject()->GetSynchStateController( - pThread, - &pSynchStateController - ); - - if (NO_ERROR == palError) - { - palError = pSynchStateController->SetSignalCount(1); - if (NO_ERROR != palError) - { - ASSERT("Unable to mark thread object as signaled"); - } - - pSynchStateController->ReleaseController(); - } - else - { - ASSERT("Unable to obtain state controller for thread"); - } - // // Add a reference to the thread data before releasing the // thread object, so we can still use it @@ -918,7 +888,7 @@ CorUnix::InternalSetThreadPriority( } /* check if the thread is still running */ - if (TS_DONE == pTargetThread->synchronizationInfo.GetThreadState()) + if (TS_DONE == pTargetThread->GetThreadState()) { /* the thread has exited, set the priority in the thread structure and exit */ @@ -1513,7 +1483,7 @@ CPalThread::ThreadEntry( pThread->SetStartStatus(TRUE); } - pThread->synchronizationInfo.SetThreadState(TS_RUNNING); + pThread->SetThreadState(TS_RUNNING); /* Inform all loaded modules that a thread has been created */ /* note : no need to take a critical section to serialize here; the loader @@ -1539,7 +1509,7 @@ CPalThread::ThreadEntry( if (NULL != pThread) { - pThread->synchronizationInfo.SetThreadState(TS_FAILED); + pThread->SetThreadState(TS_FAILED); pThread->SetStartStatus(FALSE); } @@ -1970,12 +1940,6 @@ CPalThread::RunPreCreateInitializers( // Call the pre-create initializers for embedded classes // - palError = synchronizationInfo.InitializePreCreate(); - if (NO_ERROR != palError) - { - goto RunPreCreateInitializersExit; - } - palError = suspensionInfo.InitializePreCreate(); if (NO_ERROR != palError) { @@ -2056,12 +2020,6 @@ CPalThread::RunPostCreateInitializers( goto RunPostCreateInitializersExit; } - palError = synchronizationInfo.InitializePostCreate(this, m_threadId, m_dwLwpId); - if (NO_ERROR != palError) - { - goto RunPostCreateInitializersExit; - } - palError = suspensionInfo.InitializePostCreate(this, m_threadId, m_dwLwpId); if (NO_ERROR != palError) { diff --git a/src/coreclr/pal/src/thread/threadsusp.cpp b/src/coreclr/pal/src/thread/threadsusp.cpp index d9ac0a33923f08..9d630df346e68d 100644 --- a/src/coreclr/pal/src/thread/threadsusp.cpp +++ b/src/coreclr/pal/src/thread/threadsusp.cpp @@ -245,7 +245,7 @@ CThreadSuspensionInfo::InternalResumeThreadFromData( // Check target thread's state to ensure it hasn't died. // Setting a thread's state to TS_DONE is protected by the // target's suspension mutex. - if (pthrTarget->synchronizationInfo.GetThreadState() == TS_DONE) + if (pthrTarget->GetThreadState() == TS_DONE) { palError = ERROR_INVALID_HANDLE; ReleaseSuspensionLocks(pthrResumer, pthrTarget); @@ -431,30 +431,6 @@ CThreadSuspensionInfo::AcquireSuspensionLocks( } } while (fReacquire); - // Whenever the native implementation for the wait subsystem's thread - // blocking requires a lock as protection (as pthread conditions do with - // the associated mutex), we need to grab that lock to prevent the target - // thread from being suspended while holding the lock. - // Failing to do so can lead to a multiple threads deadlocking such as the - // one described in VSW 363793. - // In general, in similar scenarios, we need to grab the protecting lock - // every time suspension safety/unsafety is unbalanced on the two sides - // using the same condition (or any other native blocking support which - // needs an associated native lock), i.e. when either the signaling - // thread(s) is(are) signaling from an unsafe area and the waiting - // thread(s) is(are) waiting from a safe one, or vice versa (the scenario - // described in VSW 363793 is a good example of the first type of - // unbalanced suspension safety/unsafety). - // Instead, whenever signaling and waiting sides are both marked safe or - // unsafe, the deadlock cannot take place since either the suspending - // thread will suspend them anyway (regardless of the native lock), or it - // won't suspend any of them, since they are both marked unsafe. - // Such a balanced scenario applies, for instance, to critical sections - // where depending on whether the target CS is internal or not, both the - // signaling and the waiting side will access the mutex/condition from - // respectively an unsafe or safe region. - - pthrTarget->AcquireNativeWaitLock(); } /*++ @@ -472,9 +448,6 @@ CThreadSuspensionInfo::ReleaseSuspensionLocks( CPalThread *pthrTarget ) { - // See comment in AcquireSuspensionLocks - pthrTarget->ReleaseNativeWaitLock(); - ReleaseSuspensionLock(pthrTarget); ReleaseSuspensionLock(pthrSuspender); } diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index 0171e0b11fdf4b..74c39df378a723 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -3,6 +3,7 @@ project(PALTESTSUITE) set(CMAKE_INCLUDE_CURRENT_DIR ON) include_directories(${PALTESTSUITE_SOURCE_DIR}/common) +include_directories(${RUNTIME_DIR}) # All test will link against these libraries: # pthread and m are part of the Android C library (bionic), @@ -13,6 +14,7 @@ if(NOT CLR_CMAKE_TARGET_ANDROID) endif() list(APPEND COMMON_TEST_LIBRARIES coreclrpal) +list(APPEND COMMON_TEST_LIBRARIES coreclrminipal) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wno-incompatible-pointer-types-discards-qualifiers) @@ -348,8 +350,6 @@ add_executable_clr(paltests threading/CreateThread/test3/test3.cpp threading/DuplicateHandle/test1/test1.cpp threading/DuplicateHandle/test12/test12.cpp - threading/DuplicateHandle/test2/test2.cpp - threading/DuplicateHandle/test3/test3.cpp threading/DuplicateHandle/test7/test7.cpp threading/DuplicateHandle/test8/test8.cpp # threading/DuplicateHandle/test9/test9.cpp @@ -362,28 +362,14 @@ add_executable_clr(paltests threading/GetCurrentThread/test1/thread.cpp threading/GetCurrentThread/test2/test2.cpp threading/GetCurrentThreadId/test1/threadId.cpp - threading/OpenEventW/test1/test1.cpp - threading/OpenEventW/test2/test2.cpp - threading/OpenEventW/test5/test5.cpp threading/QueryThreadCycleTime/test1/test1.cpp - threading/ResetEvent/test1/test1.cpp - threading/ResetEvent/test2/test2.cpp - threading/ResetEvent/test3/test3.cpp - threading/ResetEvent/test4/test4.cpp threading/ResumeThread/test1/test1.cpp - threading/SetEvent/test1/test1.cpp - threading/SetEvent/test2/test2.cpp - threading/SetEvent/test3/test3.cpp - threading/SetEvent/test4/test4.cpp + threading/RuntimeEvent/test1/test1.cpp threading/Sleep/test1/Sleep.cpp threading/Sleep/test2/sleep.cpp - threading/SleepEx/test1/test1.cpp threading/SwitchToThread/test1/test1.cpp threading/TerminateProcess/test1/TerminateProcess.cpp threading/ThreadPriority/test1/ThreadPriority.cpp - threading/WaitForMultipleObjectsEx/test1/test1.cpp - threading/WaitForSingleObject/test1/test1.cpp - threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.cpp threading/YieldProcessor/test1/test1.cpp ) diff --git a/src/coreclr/pal/tests/palsuite/common/palsuite.h b/src/coreclr/pal/tests/palsuite/common/palsuite.h index 8e7336ca8e596c..4c7878ddffe5f1 100644 --- a/src/coreclr/pal/tests/palsuite/common/palsuite.h +++ b/src/coreclr/pal/tests/palsuite/common/palsuite.h @@ -26,6 +26,7 @@ typedef unsigned short char16_t; #include #include #include +#include "RuntimeEvent.h" #include #define PALTEST(testfunc, testname) \ @@ -65,6 +66,21 @@ inline void Fail(const char *format, ...) PAL_TerminateEx(FAIL); } +inline void WaitForThreadCompletion(LONG volatile* completedThreadCount, LONG expectedThreadCount) +{ + for (DWORD elapsed = 0; elapsed < 60000; elapsed++) + { + if (InterlockedCompareExchange(completedThreadCount, 0, 0) == expectedThreadCount) + { + return; + } + + PAL_Sleep(1); + } + + Fail("Timed out waiting for %d threads to complete\n", expectedThreadCount); +} + typedef int __cdecl(*PALTestEntrypoint)(int argc, char*[]); struct PALTest diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index b4409280d39c68..6b07778dc060b8 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -271,8 +271,6 @@ threading/CreateThread/test2/paltest_createthread_test2 threading/CreateThread/test3/paltest_createthread_test3 threading/DuplicateHandle/test1/paltest_duplicatehandle_test1 threading/DuplicateHandle/test12/paltest_duplicatehandle_test12 -threading/DuplicateHandle/test2/paltest_duplicatehandle_test2 -threading/DuplicateHandle/test3/paltest_duplicatehandle_test3 threading/DuplicateHandle/test7/paltest_duplicatehandle_test7 threading/DuplicateHandle/test8/paltest_duplicatehandle_test8 threading/DuplicateHandle/test9/paltest_duplicatehandle_test9 @@ -285,26 +283,12 @@ threading/GetCurrentProcessId/test1/paltest_getcurrentprocessid_test1 threading/GetCurrentThread/test1/paltest_getcurrentthread_test1 threading/GetCurrentThread/test2/paltest_getcurrentthread_test2 threading/GetCurrentThreadId/test1/paltest_getcurrentthreadid_test1 -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/ResetEvent/test1/paltest_resetevent_test1 -threading/ResetEvent/test2/paltest_resetevent_test2 -threading/ResetEvent/test3/paltest_resetevent_test3 -threading/ResetEvent/test4/paltest_resetevent_test4 threading/ResumeThread/test1/paltest_resumethread_test1 -threading/SetEvent/test1/paltest_setevent_test1 -threading/SetEvent/test2/paltest_setevent_test2 -threading/SetEvent/test3/paltest_setevent_test3 -threading/SetEvent/test4/paltest_setevent_test4 +threading/RuntimeEvent/test1/paltest_runtimeevent_test1 threading/Sleep/test1/paltest_sleep_test1 threading/Sleep/test2/paltest_sleep_test2 -threading/SleepEx/test1/paltest_sleepex_test1 threading/SwitchToThread/test1/paltest_switchtothread_test1 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/WFSOThreadTest/paltest_waitforsingleobject_wfsothreadtest threading/YieldProcessor/test1/paltest_yieldprocessor_test1 diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp index 664e5f942e56fb..0c7341ee553616 100644 --- a/src/coreclr/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp +++ b/src/coreclr/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp @@ -20,6 +20,7 @@ //Global Variable Declaration LONG g_Total = 0; LONG Lock=0; +LONG g_CompletedThreads = 0; void ModifyGlobalResource(void); @@ -73,16 +74,10 @@ PALTEST(miscellaneous_InterlockedCompareExchange_test2_paltest_interlockedcompar } - //Wait for all threads to finish + WaitForThreadCompletion(&g_CompletedThreads, MAX_THREADS); for (i=0;i HANDLE hThread_CreateThread_test3; -HANDLE hEvent_CreateThread_test3; DWORD PALAPI Thread_CreateThread_test3( LPVOID lpParameter) { - DWORD dwRet; - dwRet = WaitForSingleObject(hEvent_CreateThread_test3, INFINITE); + PAL_Sleep(INFINITE); /* if this thread continues beyond here, fail */ Fail(""); @@ -29,21 +27,11 @@ DWORD PALAPI Thread_CreateThread_test3( LPVOID lpParameter) PALTEST(threading_CreateThread_test3_paltest_createthread_test3, "threading/CreateThread/test3/paltest_createthread_test3") { DWORD dwThreadId; - DWORD dwRet; - if(0 != (PAL_Initialize(argc, argv))) { return (FAIL); } - hEvent_CreateThread_test3 = CreateEvent(NULL, TRUE, FALSE, NULL); - - if (hEvent_CreateThread_test3 == NULL) - { - Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError " - "returned %u.\n", GetLastError()); - } - /* pass the index as the thread argument */ hThread_CreateThread_test3 = CreateThread( NULL, 0, @@ -56,45 +44,17 @@ PALTEST(threading_CreateThread_test3_paltest_createthread_test3, "threading/Crea Trace("PALSUITE ERROR: CreateThread('%p' '%d' '%p' '%p' '%d' '%p') " "call failed.\nGetLastError returned '%u'.\n", NULL, 0, &Thread_CreateThread_test3, (LPVOID) 0, 0, &dwThreadId, GetLastError()); - if (0 == CloseHandle(hEvent_CreateThread_test3)) - { - Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " - "clean up.\nGetLastError returned '%u'.\n", hEvent_CreateThread_test3); - } Fail(""); } - dwRet = WaitForSingleObject(hThread_CreateThread_test3, 10000); - if (dwRet != WAIT_TIMEOUT) - { - Trace ("PALSUITE ERROR: WaitForSingleObject('%p' '%d') " - "call returned %d instead of WAIT_TIMEOUT ('%d').\n" - "GetLastError returned '%u'.\n", hThread_CreateThread_test3, 10000, - dwRet, WAIT_TIMEOUT, GetLastError()); - Fail(""); - } + PAL_Sleep(10); if (0 == CloseHandle(hThread_CreateThread_test3)) { Trace("PALSUITE ERROR: Unable to CloseHandle(%p) on a running thread." "\nGetLastError returned '%u'.\n", hThread_CreateThread_test3, GetLastError()); - if (0 == CloseHandle(hEvent_CreateThread_test3)) - { - Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " - "cleanup.\nGetLastError returned '%u'.\n", hEvent_CreateThread_test3, - GetLastError()); - } - Fail(""); - } - if (0 == CloseHandle(hEvent_CreateThread_test3)) - { - Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " - "cleanup.\nGetLastError returned '%u'.\n", hEvent_CreateThread_test3, - GetLastError()); Fail(""); } - PAL_Terminate(); return (PASS); } - diff --git a/src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.cpp deleted file mode 100644 index fad9e2b1c08111..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.cpp +++ /dev/null @@ -1,146 +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: test1.c -** -** Purpose: Tests that DisableThreadLibraryCalls actually stops thread -** attach/detach notifications to a library. Also tests how it -** handles an invalid module handle. -** -** -**===================================================================*/ - -#include - - -/* SHLEXT is defined only for Unix variants */ - -#if defined(SHLEXT) -#define LibName "testlib"SHLEXT -#define GETCALLCOUNT "GetCallCount" -#else -#define LibName "testlib" -#define GETCALLCOUNT "_GetCallCount@0" -#endif - -DWORD PALAPI ThreadFunc_DisableThreadLibraryCalls_test1(LPVOID lpParam); -int RunTest_DisableThreadLibraryCalls_test1(int DisableThreadCalls); - -int __cdecl threading_DisableThreadLibraryCalls_test1(int argc, char* argv[]); -static PALTest threading_DisableThreadLibraryCalls_test1_lookup(threading_DisableThreadLibraryCalls_test1, "threading/DisableThreadLibraryCalls/test1"); -int __cdecl threading_DisableThreadLibraryCalls_test1(int argc, char* argv[]) -{ - int ret; - - if ((PAL_Initialize(argc,argv)) != 0) - { - return (FAIL); - } - - - /* - * Although MSDN says that DisableThreadLibraryCalls will fail if passed - * an invalid handle, it actually returns success! - */ - ret = DisableThreadLibraryCalls(NULL); - if (!ret) - { - Fail("DisableThreadLibraryCalls failed on an invalid module " - "handle (it actually should pass)!\n"); - } - - - /* - * Test once without calling DisableThreadLibraryCalls and make sure we - * get expected results. - */ - ret = RunTest_DisableThreadLibraryCalls_test1(0); - if (ret != 2) - { - Fail("Expected to get 2 thread library calls, got %d!\n", ret); - } - - - /* - * Test again, this time calling DisableThreadLibraryCalls. - */ - ret = RunTest_DisableThreadLibraryCalls_test1(1); - if (ret != 0) - { - Fail("Expected to get 0 thread library calls, got %d!\n", ret); - } - - PAL_Terminate(); - return PASS; -} - -/* - * Thread entry point. Doesn't do anything. - */ -DWORD PALAPI ThreadFunc_DisableThreadLibraryCalls_test1(LPVOID lpParam) -{ - return 0; -} - - -int RunTest(int DisableThreadCalls) -{ - HMODULE LibMod; - HANDLE hThread; - DWORD threadID; - DWORD WaitRet; - int (*GetCallCount)(); - int count; - - LibMod = LoadLibrary(LibName); - if (LibMod == NULL) - { - Fail("Unable to load test library!\nGetLastError returned %d\n", - GetLastError()); - } - - GetCallCount = (int(*)())GetProcAddress(LibMod, GETCALLCOUNT); - if (GetCallCount == NULL) - { - Fail("Unable to get function GetCallCount from library!\n" - "GetLastError returned %d\n", GetLastError()); - } - - if (DisableThreadCalls) - { - if (!DisableThreadLibraryCalls(LibMod)) - { - Fail("DisabledThreadLibraryCalls failed!\n" - "GetLastError returned %d!\n", GetLastError()); - } - } - - hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc_DisableThreadLibraryCalls_test1, - NULL, 0, &threadID); - - if (hThread == NULL) - { - Fail("Unable to create a thread!\n"); - } - - WaitRet = WaitForSingleObject(hThread, INFINITE); - if (WaitRet == WAIT_FAILED) - { - Fail("Unable to wait on thread!\nGetLastError returned %d\n", - GetLastError()); - } - - count = GetCallCount(); - - CloseHandle(hThread); - - if (!FreeLibrary(LibMod)) - { - Fail("Failed freeing library!\nGetLastError returned %d\n", - GetLastError()); - } - - return count; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.cpp deleted file mode 100644 index 58fb4429f7a2f9..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.cpp +++ /dev/null @@ -1,236 +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: test2.c -** -** Purpose: Test to ensure DisableThreadLibraryCalls() called for one -** library will not disrupt THREAD_ATTACH notifications etc. by -** other loaded modules. -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** Fail -** CreateThread -** ResumeThread -** LoadLibrary -** FreeLibrary -** GetProcAddress -** WaitForSingleObject -** GetLastError -** -** -**===========================================================================*/ -#include - -/* SHLEXT is defined only for Unix variants */ - -#if defined(SHLEXT) -#define rgchLibraryFile1 "dllmain1"SHLEXT -#define rgchLibraryFile2 "dllmain2"SHLEXT -#define szFunction "GetAttachCount" -#else -#define rgchLibraryFile1 "dllmain1" -#define rgchLibraryFile2 "dllmain2" -#define szFunction "_GetAttachCount@0" -#endif - -/* define our test function type */ -typedef int ( PALAPI *LPTESTFUNC )( void ); - - - -/** - * ThreadFunc - * - * Dummy thread function for causing DLL thread notifications. - */ -DWORD PALAPI ThreadFunc_DisableThreadLibraryCalls_test2( LPVOID param ) -{ - /* simulate some brief "work" */ - int i; - for( i=0; i<100000; i++ ) - { - } - - return 0; -} - - -/* main program entry point */ -int __cdecl main( int argc, char **argv ) - -{ - /* local variables */ - - HANDLE hLib1 = NULL; - HANDLE hLib2 = NULL; - LPTESTFUNC pFunc1; - LPTESTFUNC pFunc2; - int attachCount1a = 0; - int attachCount1b = 0; - int attachCount2a = 0; - int attachCount2b = 0; - - HANDLE hThread = NULL; - DWORD IDThread; - DWORD dwRet; - - BOOL bResult = FAIL; - - /* initialize the PAL */ - if( PAL_Initialize(argc, argv) != 0 ) - { - return( FAIL ); - } - - /* Load the first test library */ - hLib1 = LoadLibrary( rgchLibraryFile1 ); - if(hLib1 == NULL) - { - Fail( "ERROR:%lu:LoadLibrary() call failed for %s\n", - GetLastError(), - rgchLibraryFile1 ); - } - - /* Load the second test library */ - hLib2 = LoadLibrary( rgchLibraryFile2 ); - if(hLib2 == NULL) - { - Trace( "ERROR:%lu:LoadLibrary() call failed for %s\n", - GetLastError(), - rgchLibraryFile2 ); - if( ! FreeLibrary( hLib1 ) ) - { - Trace( "ERROR:%lu:FreeLibrary() call failed\n", GetLastError() ); - } - Fail( "test failed\n" ); - } - - - /* Get the addresses of our test functions in the dlls */ - pFunc1 = (LPTESTFUNC)GetProcAddress( hLib1, szFunction ); - if( pFunc1 == NULL ) - { - Trace( "ERROR:%lu%:Unable to find \"%s\" in library \"%s\"\n", - GetLastError(), - szFunction, - rgchLibraryFile1 ); - goto cleanup; - } - - pFunc2 = (LPTESTFUNC)GetProcAddress( hLib2, szFunction ); - if( pFunc1 == NULL ) - { - Trace( "ERROR:%lu%:Unable to find \"%s\" in library \"%s\"\n", - GetLastError(), - szFunction, - rgchLibraryFile2 ); - goto cleanup; - } - - /* disable thread library calls for the first library */ - if( ! DisableThreadLibraryCalls( (HMODULE)hLib1 ) ) - { - Trace( "ERROR:%lu:DisableThreadLibraryCalls() call failed\n", - GetLastError() ); - goto cleanup; - } - - /* Execute the test function to get the attach count */ - attachCount1a = pFunc1(); - attachCount2a = pFunc2(); - - /* run another dummy thread to cause notification of the libraries */ - hThread = CreateThread( NULL, /* no security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE) ThreadFunc_DisableThreadLibraryCalls_test2, /* thread function */ - (LPVOID) NULL, /* pass thread index as */ - /* function argument */ - CREATE_SUSPENDED, /* create suspended */ - &IDThread ); /* returns thread id */ - - /* Check the return value for success. */ - if( hThread == NULL ) - { - /* error creating thread */ - Trace( "ERROR:%lu:CreateThread() call failed\n", - GetLastError() ); - goto cleanup; - } - - /* Resume the suspended thread */ - if( ResumeThread( hThread ) == -1 ) - { - Trace( "ERROR:%lu:ResumeThread() call failed\n", GetLastError() ); - goto cleanup; - } - - - /* wait for the thread to complete */ - dwRet = WaitForSingleObject( hThread, INFINITE ); - if( dwRet != WAIT_OBJECT_0 ) - { - Trace( "ERROR: WaitForSingleObject returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - - /* Execute the test function to get the new detach count */ - attachCount1b = pFunc1(); - attachCount2b = pFunc2(); - - /* validate the result */ - if( attachCount1b != attachCount1a ) - { - Trace( "FAIL: unexpected DLL attach count %d, expected %d\n", - attachCount1b, - attachCount1a ); - goto cleanup; - } - - /* validate the result */ - if( attachCount2b != (attachCount2a + 1) ) - { - Trace( "FAIL: unexpected DLL attach count %d, expected %d\n", - attachCount2b, - (attachCount2a + 1) ); - goto cleanup; - } - - bResult = PASS; - -cleanup: - /* Unload the test libraries */ - if( !FreeLibrary( hLib1 ) ) - { - Trace( "ERROR:%u:FreeLibrary() failed on library \"%s\"\n", - GetLastError(), - rgchLibraryFile1 ); - bResult = FAIL; - } - - if( !FreeLibrary( hLib2 ) ) - { - Trace( "ERROR:%u:FreeLibrary() failed on library \"%s\"\n", - GetLastError(), - rgchLibraryFile2 ); - bResult = FAIL; - } - - /* check for failure */ - if( bResult == FAIL ) - { - Fail( "test failed\n" ); - } - - /* terminate the PAL */ - PAL_Terminate(); - - /* return success */ - return PASS; -} - diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.cpp deleted file mode 100644 index 71abd9d95d84be..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.cpp +++ /dev/null @@ -1,95 +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: test2.c (DuplicateHandle) -** -** Purpose: Tests the PAL implementation of the DuplicateHandle function. -** This will test duplication of an CreateEvent handle. Test an -** event in a signaled state to wait, and then set the duplicate -** to nonsignaled state and perform the wait again. The wait on -** the event should fail. Test the duplication of closed and NULL -** events, these should fail. -** -** -**===================================================================*/ -#include - -PALTEST(threading_DuplicateHandle_test2_paltest_duplicatehandle_test2, "threading/DuplicateHandle/test2/paltest_duplicatehandle_test2") -{ - HANDLE hEvent; - HANDLE hDupEvent; - - /*Initialize the PAL.*/ - if ((PAL_Initialize(argc,argv)) != 0) - { - return (FAIL); - } - - /*Create an Event, and set it in the signaled state.*/ - hEvent = CreateEvent(0, TRUE, TRUE, 0); - if (hEvent == NULL) - { - Fail("ERROR: %u :unable to create event\n", - GetLastError()); - } - - /*Create a duplicate Event handle.*/ - if (!(DuplicateHandle(GetCurrentProcess(), - hEvent,GetCurrentProcess(), - &hDupEvent, - GENERIC_READ|GENERIC_WRITE, - FALSE, DUPLICATE_SAME_ACCESS))) - { - Trace("ERROR: %u :Fail to create the duplicate handle" - " to hEvent=0x%lx\n", - GetLastError(), - hEvent); - CloseHandle(hEvent); - Fail(""); - } - - /*Perform wait on Event that is in signaled state.*/ - if ((WaitForSingleObject(hEvent, 1000)) != WAIT_OBJECT_0) - { - Trace("ERROR: %u :WaitForSignalObject on Event=0x%lx set to " - " signaled state failed", - GetLastError(), - hEvent); - CloseHandle(hEvent); - CloseHandle(hDupEvent); - Fail(""); - } - - /*Set the Duplicate Event handle to nonsignaled state.*/ - if ((ResetEvent(hDupEvent)) == 0) - { - Trace("ERROR: %u :unable to reset dup event\n", - GetLastError()); - CloseHandle(hEvent); - CloseHandle(hDupEvent); - Fail(""); - } - - /*Perform wait on Event that is in signaled state.*/ - if ((WaitForSingleObject(hEvent, 1000)) == WAIT_OBJECT_0) - { - Trace("ERROR: %u: WaitForSignalObject succeeded on Event=0x%lx " - " when Duplicate Event=0x%lx set to nonsignaled state" - " succeeded\n", - GetLastError(), - hEvent, - hDupEvent); - CloseHandle(hEvent); - CloseHandle(hDupEvent); - Fail(""); - } - - /*Close handles to events.*/ - CloseHandle(hEvent); - CloseHandle(hDupEvent); - - PAL_Terminate(); - return (PASS); -} diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.cpp deleted file mode 100644 index 4852648471abcb..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.cpp +++ /dev/null @@ -1,122 +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: test3.c (DuplicateHandle) -** -** Purpose: Tests the PAL implementation of the DuplicateHandle function. -** This will test duplication of an OpenEvent handle. Test an -** event in a signaled state to wait, and then set the duplicate -** to nonsignaled state and perform the wait again. The wait on -** the event should fail. Test the duplication of closed and NULL -** events, these should fail. -** -** -**===================================================================*/ -#include - -PALTEST(threading_DuplicateHandle_test3_paltest_duplicatehandle_test3, "threading/DuplicateHandle/test3/paltest_duplicatehandle_test3") -{ - HANDLE hCreateEvent; - HANDLE hOpenEvent; - HANDLE hDupEvent; - WCHAR lpEventName[]={'E','v','e','n','t','\0'}; - - /*Initialize the PAL.*/ - if ((PAL_Initialize(argc,argv)) != 0) - { - return (FAIL); - } - - /*Create an Event, and set it in the signaled state.*/ - hCreateEvent = CreateEventW(0, - TRUE, - TRUE, - lpEventName); - if (hCreateEvent == NULL) - { - Fail("ERROR: %u :unable to create event %s\n", - GetLastError(), - lpEventName); - } - - /*Open another handle to hCreateHandle with OpenEvent*/ - hOpenEvent = OpenEventW(EVENT_ALL_ACCESS, - TRUE, - lpEventName); - if (hOpenEvent == NULL) - { - Trace("ERROR: %u :unable to create handle with OpenEvent to %s\n", - GetLastError(), - lpEventName); - CloseHandle(hCreateEvent); - Fail(""); - } - - /*Create a duplicate Event handle*/ - if (!(DuplicateHandle(GetCurrentProcess(), - hOpenEvent, - GetCurrentProcess(), - &hDupEvent, - GENERIC_READ|GENERIC_WRITE, - FALSE, - DUPLICATE_SAME_ACCESS))) - { - Trace("ERROR: %u :Fail to create the duplicate handle" - " to hCreateEvent=0x%lx\n", - GetLastError(), - hCreateEvent); - CloseHandle(hCreateEvent); - CloseHandle(hOpenEvent); - Fail(""); - } - - /*Perform wait on Event that is in signaled state*/ - if ((WaitForSingleObject(hOpenEvent, 1000)) != WAIT_OBJECT_0) - { - Trace("ERROR: %u :WaitForSignalObject on hOpenEvent=0x%lx set to " - " signaled state failed\n", - GetLastError(), - hOpenEvent); - CloseHandle(hCreateEvent); - CloseHandle(hOpenEvent); - CloseHandle(hDupEvent); - Fail(""); - } - - /*Set the Duplicate Event handle to nonsignaled state*/ - if ((ResetEvent(hDupEvent)) == 0) - { - Trace("ERROR: %u: unable to reset hDupEvent=0x%lx\n", - GetLastError(), - hDupEvent); - CloseHandle(hCreateEvent); - CloseHandle(hOpenEvent); - CloseHandle(hDupEvent); - Fail(""); - } - - /*Perform wait on Event that is in signaled state*/ - if ((WaitForSingleObject(hOpenEvent, 1000)) == WAIT_OBJECT_0) - { - Trace("ERROR: %u :WaitForSignalObject succeeded on hOpenEvent=0x%lx " - " when Duplicate hDupEvent=0x%lx set to nonsignaled state" - " succeeded\n", - GetLastError(), - hOpenEvent, - hDupEvent); - CloseHandle(hCreateEvent); - CloseHandle(hOpenEvent); - CloseHandle(hDupEvent); - Fail(""); - } - - /*Close handles the events*/ - CloseHandle(hCreateEvent); - CloseHandle(hOpenEvent); - CloseHandle(hDupEvent); - - PAL_Terminate(); - return (PASS); -} diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.cpp index d50b1bfb27c298..efa8751cb1d6fb 100644 --- a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.cpp @@ -17,6 +17,7 @@ #include DWORD PALAPI CreateTestThread_DuplicateHandle_test7(LPVOID lpParam); +LONG completedThreadCount_DuplicateHandle_test7 = 0; PALTEST(threading_DuplicateHandle_test7_paltest_duplicatehandle_test7, "threading/DuplicateHandle/test7/paltest_duplicatehandle_test7") { @@ -24,8 +25,6 @@ PALTEST(threading_DuplicateHandle_test7_paltest_duplicatehandle_test7, "threadin HANDLE hDupThread; DWORD dwThreadId = 0; LPTHREAD_START_ROUTINE lpStartAddress = &CreateTestThread_DuplicateHandle_test7; - HANDLE hSyncEvent; - int threadPriority; int duplicatePriority; int finalPriority; @@ -36,26 +35,12 @@ PALTEST(threading_DuplicateHandle_test7_paltest_duplicatehandle_test7, "threadin return (FAIL); } - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - hSyncEvent = CreateEvent(lpEventAttributes, - bManualReset, - bInitialState, - NULL); - - if (hSyncEvent == NULL) - { - Fail("ERROR:%u: Unable to create sync event.\n", - GetLastError()); - } - /* Create a thread.*/ hThread = CreateThread(NULL, /* SD*/ (DWORD)0, /* initial stack size*/ lpStartAddress, /* thread function*/ - (VOID*)hSyncEvent,/* thread argument*/ - (DWORD)0, /* creation option*/ + NULL, /* thread argument*/ + CREATE_SUSPENDED, /* creation option*/ &dwThreadId); /* thread identifier*/ if (hThread == NULL) { @@ -137,27 +122,16 @@ PALTEST(threading_DuplicateHandle_test7_paltest_duplicatehandle_test7, "threadin Fail(""); } - /* Signal the helper thread that it can shut down */ - if (!SetEvent(hSyncEvent)) + /* Let the helper thread run and shut down. */ + if (ResumeThread(hThread) == (DWORD)-1) { - Fail("ERROR:%u: Failed to set event.\n", + Fail("ERROR:%u: Failed to resume thread.\n", GetLastError()); } - /* Wait on the original thread.*/ - if((WaitForSingleObject(hThread, 100)) != WAIT_OBJECT_0) - { - Trace("ERROR:%u: hThread=0x%lx is in a non-signalled " - "mode, yet created signalled.\n", - GetLastError(), - hThread); - CloseHandle(hThread); - CloseHandle(hDupThread); - Fail(""); - } + WaitForThreadCompletion(&completedThreadCount_DuplicateHandle_test7, 1); /* Clean-up thread and Terminate the PAL.*/ - CloseHandle(hSyncEvent); CloseHandle(hThread); CloseHandle(hDupThread); PAL_Terminate(); @@ -167,11 +141,6 @@ PALTEST(threading_DuplicateHandle_test7_paltest_duplicatehandle_test7, "threadin /*Thread testing function*/ DWORD PALAPI CreateTestThread_DuplicateHandle_test7(LPVOID lpParam) { - HANDLE hSyncEvent = (HANDLE)lpParam; - - /* Wait until the main thread signals that this helper thread should shut down */ - WaitForSingleObject(hSyncEvent, INFINITE); - + InterlockedIncrement(&completedThreadCount_DuplicateHandle_test7); return (DWORD)0; } - diff --git a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.cpp b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.cpp index e90fcd43f4b76b..909094eab81d6c 100644 --- a/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.cpp @@ -17,6 +17,7 @@ #include DWORD PALAPI CreateTestThread_DuplicateHandle_test8(LPVOID lpParam); +LONG completedThreadCount_DuplicateHandle_test8 = 0; PALTEST(threading_DuplicateHandle_test8_paltest_duplicatehandle_test8, "threading/DuplicateHandle/test8/paltest_duplicatehandle_test8") { @@ -134,17 +135,7 @@ PALTEST(threading_DuplicateHandle_test8_paltest_duplicatehandle_test8, "threadin Fail(""); } - /* Wait on the original thread.*/ - if((WaitForSingleObject(hThread, 100)) != WAIT_OBJECT_0) - { - Trace("ERROR:%u: hCurrentThread=0x%lx is in a non-signalled " - "mode, yet created signalled.\n", - GetLastError(), - hThread); - CloseHandle(hThread); - CloseHandle(hDupThread); - Fail(""); - } + WaitForThreadCompletion(&completedThreadCount_DuplicateHandle_test8, 1); /* Clean-up thread and Terminate the PAL.*/ CloseHandle(hThread); @@ -159,5 +150,6 @@ PALTEST(threading_DuplicateHandle_test8_paltest_duplicatehandle_test8, "threadin /*Thread testing function, only return '0'*/ DWORD PALAPI CreateTestThread_DuplicateHandle_test8(LPVOID lpParam) { + InterlockedIncrement(&completedThreadCount_DuplicateHandle_test8); return (DWORD)0; } diff --git a/src/coreclr/pal/tests/palsuite/threading/ExitThread/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/ExitThread/test1/test1.cpp index 1b41b1364bbeea..4a628685461a51 100644 --- a/src/coreclr/pal/tests/palsuite/threading/ExitThread/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/ExitThread/test1/test1.cpp @@ -15,6 +15,7 @@ #include DWORD dwExitThreadTestParameter = 0; +LONG completedThreadCount_ExitThread_test1 = 0; DWORD PALAPI ExitThreadTestThread( LPVOID lpParameter) { @@ -22,6 +23,7 @@ DWORD PALAPI ExitThreadTestThread( LPVOID lpParameter) /* Save parameter for test */ dwExitThreadTestParameter = (DWORD)(SIZE_T)lpParameter; + InterlockedIncrement(&completedThreadCount_ExitThread_test1); /* Call the ExitThread function */ ExitThread(dwRet); @@ -42,8 +44,6 @@ DWORD PALAPI ExitThreadTestThread( LPVOID lpParameter) BOOL ExitThreadTest() { BOOL bRet = FALSE; - DWORD dwRet = 0; - LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL; DWORD dwStackSize = 0; LPTHREAD_START_ROUTINE lpStartAddress = &ExitThreadTestThread; @@ -64,29 +64,22 @@ BOOL ExitThreadTest() if (hThread != NULL) { - dwRet = WaitForSingleObject(hThread,INFINITE); + WaitForThreadCompletion(&completedThreadCount_ExitThread_test1, 1); - if (dwRet != WAIT_OBJECT_0) + /* Check to ensure that the parameter set in the Thread + function is correct. + */ + if (dwExitThreadTestParameter != (DWORD)(SIZE_T)lpParameter) { - Trace("ExitThreadTest:WaitForSingleObject failed " - "(%x)\n",GetLastError()); + Trace("ERROR: The parameter passed should have been " + "%d but turned up as %d.", + dwExitThreadTestParameter, lpParameter); } else { - /* Check to ensure that the parameter set in the Thread - function is correct. - */ - if (dwExitThreadTestParameter != (DWORD)(SIZE_T)lpParameter) - { - Trace("ERROR: The parameter passed should have been " - "%d but turned up as %d.", - dwExitThreadTestParameter, lpParameter); - } - else - { - bRet = TRUE; - } + bRet = TRUE; } + CloseHandle(hThread); } else { diff --git a/src/coreclr/pal/tests/palsuite/threading/ExitThread/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/threading/ExitThread/test3/test3.cpp deleted file mode 100644 index 473edde728e52b..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/ExitThread/test3/test3.cpp +++ /dev/null @@ -1,161 +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: test3.c -** -** Purpose: Test to ensure ExitThread() results in any loaded dynamic -** libraries having their entry point called with a THREAD_DETACH -** notification. -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** Fail -** GetCurrentDirectoryW -** CreateThread -** ResumeThread -** LoadLibrary -** FreeLibrary -** GetProcAddress -** WaitForSingleObject -** GetLastError -** strlen -** strncpy -** - -** -**===========================================================================*/ -#include - -/* SHLEXT is defined only for Unix variants */ - -#if defined(SHLEXT) -#define rgchLibraryFile "dllmain"SHLEXT -#define szFunction "GetDetachCount" -#else -#define rgchLibraryFile "dllmain" -#define szFunction "_GetDetachCount@0" -#endif - -/* define our test function type */ -typedef int ( PALAPI *LPTESTFUNC )( void ); - - -/** - * ThreadFunc - * - * Dummy thread function for causing DLL thread notifications. - */ -DWORD PALAPI ThreadFunc_ExitThread_test3( LPVOID param ) -{ - /* simulate some brief "work" */ - int i; - for( i=0; i<100000; i++ ) - ; - - ExitThread( 0 ); - return (0); -} - - -/* main program entry point */ -int __cdecl main( int argc, char **argv ) - -{ - /* local variables */ - - HANDLE hLib = NULL; - LPTESTFUNC pFunc; - int detachCount1 = 0; - int detachCount2 = 0; - - HANDLE hThread = NULL; - DWORD IDThread; - - /* initialize the PAL */ - if( PAL_Initialize(argc, argv) != 0 ) - { - return( FAIL ); - } - - /* Load the test library */ - hLib = LoadLibrary( rgchLibraryFile ); - if(hLib == NULL) - { - Fail("ERROR: Unable to load library %s\n", rgchLibraryFile ); - } - - - /* Get the address of our test function in the dll */ - pFunc = (LPTESTFUNC)GetProcAddress( hLib, szFunction ); - if( pFunc == NULL ) - { - Trace( "ERROR:%lu%:Unable to load function \"%s\" library \"%s\"\n", - GetLastError(), - szFunction, - rgchLibraryFile ); - if( ! FreeLibrary( hLib ) ) { - Trace( "FreeLibrary() failed with error code %lu\n", - GetLastError() ); - } - Fail( "Exiting\n" ); - } - - /* Execute the test function to get the detach count */ - detachCount1 = pFunc(); - - /* run another dummy thread to cause notification of the library */ - hThread = CreateThread( NULL, /* no security attributes */ - 0, /* use default stack size */ - (LPTHREAD_START_ROUTINE) ThreadFunc_ExitThread_test3, /* thread function */ - (LPVOID) NULL, /* pass thread index as */ - /* function argument */ - CREATE_SUSPENDED, /* create suspended */ - &IDThread ); /* returns thread id */ - - /* Check the return value for success. */ - if( hThread == NULL ) - { - /* error creating thread */ - Trace( "Unexpected CreateThread error %d\n", - GetLastError() ); - if( ! FreeLibrary( hLib ) ) { - Trace( "FreeLibrary() failed with error code %lu\n", - GetLastError() ); - } - Fail( "Exiting\n" ); - } - - /* Resume the suspended thread */ - ResumeThread( hThread ); - - /* wait for the thread to complete */ - WaitForSingleObject( hThread, INFINITE ); - - /* Execute the test function to get the new detach count */ - detachCount2 = pFunc(); - - /* Unload the test library */ - if( !FreeLibrary( hLib ) ) - { - Fail( "ERROR:%u: Unable to free library \"%s\"\n", - GetLastError(), - rgchLibraryFile ); - } - - /* validate the result */ - if( detachCount2 != (detachCount1 + 1) ) - { - Fail( "FAIL: unexpected DLL detach count %d, expected %d\n", - detachCount2, - (detachCount1 + 1) ); - } - - - /* terminate the PAL */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.cpp index ad5d5c27a385f2..c3e40f21348cfd 100644 --- a/src/coreclr/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.cpp @@ -12,7 +12,6 @@ ** SetThreadPriority ** GetThreadPriority ** ResumeThread -** WaitForSingleObject ** GetLastError ** ** Purpose: @@ -35,6 +34,7 @@ /* we're missing the GetExitCodeThread() API */ static int g_priority = 0; +static LONG g_completedThreadCount = 0; /** * ThreadFunc @@ -66,6 +66,7 @@ DWORD PALAPI ThreadFunc_GetCurrentThread_test2( LPVOID param ) /* store this globally because we don't have GetExitCodeThread() */ g_priority = priority; + InterlockedIncrement(&g_completedThreadCount); return (DWORD)priority; } @@ -79,8 +80,6 @@ PALTEST(threading_GetCurrentThread_test2_paltest_getcurrentthread_test2, "thread { HANDLE hThread = NULL; DWORD IDThread; - DWORD dwRet; - SIZE_T i = 0; /* PAL initialization */ @@ -121,13 +120,7 @@ PALTEST(threading_GetCurrentThread_test2_paltest_getcurrentthread_test2, "thread ResumeThread( hThread ); - /* wait for the thread to finish */ - dwRet = WaitForSingleObject( hThread, INFINITE ); - if( dwRet == WAIT_FAILED ) - { - /* ERROR */ - Fail( "ERROR:%lu:WaitForSingleObject call failed\n", GetLastError() ); - } + WaitForThreadCompletion(&g_completedThreadCount, 1); /* validate the thread's exit code */ if( g_priority != THREAD_PRIORITY_TIME_CRITICAL ) @@ -136,6 +129,7 @@ PALTEST(threading_GetCurrentThread_test2_paltest_getcurrentthread_test2, "thread Fail( "FAIL:Unexpected thread priority %d returned, expected %d\n", g_priority, THREAD_PRIORITY_TIME_CRITICAL ); } + CloseHandle(hThread); #endif PAL_Terminate(); diff --git a/src/coreclr/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.cpp b/src/coreclr/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.cpp index e8c90ebd955e3e..379d0777a6edf9 100644 --- a/src/coreclr/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.cpp @@ -20,11 +20,13 @@ #include DWORD dwThreadIdTF; +LONG completedThreadCount_GetCurrentThreadId_test1 = 0; DWORD PALAPI ThreadFunction ( LPVOID lpParam ) { Trace ("thread code executed\n"); dwThreadIdTF = GetCurrentThreadId(); + InterlockedIncrement(&completedThreadCount_GetCurrentThreadId_test1); return 0; } @@ -34,7 +36,6 @@ PALTEST(threading_GetCurrentThreadId_test1_paltest_getcurrentthreadid_test1, "th DWORD dwThreadIdCT; HANDLE hThread; DWORD dwThreadParam = 1; - DWORD dwThreadWait; if(0 != (PAL_Initialize(argc, argv))) { @@ -55,15 +56,14 @@ PALTEST(threading_GetCurrentThreadId_test1_paltest_getcurrentthreadid_test1, "th } else { - dwThreadWait = WaitForSingleObject( hThread, INFINITE ); - - Trace ("dwThreadWait returned %d\n", dwThreadWait ); + WaitForThreadCompletion(&completedThreadCount_GetCurrentThreadId_test1, 1); if ( dwThreadIdCT == dwThreadIdTF ) { Trace ( "ThreadId numbers match - GetCurrentThreadId" " works. dwThreadIdCT == dwThreadIdTF == %d\n", dwThreadIdTF ); + CloseHandle(hThread); PAL_Terminate(); return ( PASS ); } diff --git a/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test1/test1.cpp deleted file mode 100644 index c6c4c8cb12ac4f..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test1/test1.cpp +++ /dev/null @@ -1,133 +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: test1.c -** -** Purpose: Test for OpenEventW. This test creates an event, -** opens a handle to the same event, then waits on both handles -** in both a signalled and non-signalled state to verify they're. -** pointing to the same event object. -** -** -**==========================================================================*/ -#include - -PALTEST(threading_OpenEventW_test1_paltest_openeventw_test1, "threading/OpenEventW/test1/paltest_openeventw_test1") -{ - BOOL bRet = FAIL; - DWORD dwRet; - HANDLE hEvent; - HANDLE hOpenEvent; - WCHAR theName[] = {'E','v','e','n','t','\0'}; - LPCWSTR lpName = theName; - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - /* Create an event (with a 0 initial state!) and ensure that the - HANDLE is valid - */ - hEvent = CreateEventW( NULL, TRUE, FALSE, lpName ); - if( hEvent == NULL ) - { - Fail( "ERROR:%lu:CreateEvent call failed\n", GetLastError() ); - } - - - /* Call OpenEventW to get another HANDLE on - this event. Ensure the HANDLE is valid. - */ - hOpenEvent = OpenEventW( EVENT_ALL_ACCESS, TRUE, lpName ); - if( hOpenEvent == NULL ) - { - Trace( "ERROR:%lu:OpenEventW call failed\n", GetLastError() ); - goto cleanup2; - } - - /* wait on the original event to verify that it's not signalled */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - Trace( "ERROR:WaitForSingleObject returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - /* wait on the opened event to verify that it's not signalled either */ - dwRet = WaitForSingleObject( hOpenEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - Trace( "ERROR:WaitForSingleObject returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - - /* Set this opened HANDLE */ - if( ! SetEvent( hOpenEvent ) ) - { - Trace( "ERROR:%lu:SetEvent call failed\n", GetLastError() ); - goto cleanup; - } - - /* wait on the original event to verify that it's signalled */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - Trace( "ERROR:WaitForSingleObject returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - /* wait on the opened event to verify that it's signalled too */ - dwRet = WaitForSingleObject( hOpenEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - Trace( "ERROR:WaitForSingleObject returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - /* success if we get here */ - bRet = PASS; - -cleanup: - /* close the opened handle */ - if( ! CloseHandle( hOpenEvent ) ) - { - Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() ); - bRet = FAIL; - } - -cleanup2: - /* close the original event handle */ - if( ! CloseHandle( hEvent ) ) - { - Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() ); - bRet = FAIL; - } - - /* check for failure */ - if( bRet == FAIL ) - { - Fail( "test failed\n" ); - } - - - /* terminate the PAL */ - PAL_Terminate(); - - /* return success */ - return ( PASS ); - -} - diff --git a/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test2/test2.cpp deleted file mode 100644 index 4a2ac38e72ddbb..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test2/test2.cpp +++ /dev/null @@ -1,193 +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: test2.c -** -** Purpose: Positive test for OpenEventW. -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** WaitForSingleObject -** -** Purpose: -** -** Test to ensure proper operation of the OpenEventW() -** API by creating a new named event and verifying that -** it can be used interchangeably by setting the event -** with the original handle and waiting on it with the -** new one, then resetting it with the new one and waiting -** on it with the original one. -** -** -**===========================================================================*/ -#include - - - -PALTEST(threading_OpenEventW_test2_paltest_openeventw_test2, "threading/OpenEventW/test2/paltest_openeventw_test2") - -{ - /* local variables */ - BOOL ret = FAIL; - DWORD dwRet = 0; - HANDLE hEvent = NULL; - HANDLE hTestEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - WCHAR wcName[] = {'W','o','o','B','a','b','y','\0'}; - LPWSTR lpName = wcName; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with SetEvent */ - hEvent = CreateEventW( lpEventAttributes, - bManualReset, - bInitialState, - lpName ); - - if( hEvent == NULL ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* open a new handle to our event */ - hTestEvent = OpenEventW(EVENT_ALL_ACCESS, /* we want all rights */ - FALSE, /* no inherit */ - lpName ); - - if( hTestEvent == NULL ) - { - /* ERROR */ - Trace( "ERROR:%lu:OpenEventW() call failed\n", GetLastError() ); - goto cleanup; - } - - /* verify that the event isn't signalled yet by waiting on both */ - /* handles to the event object */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - dwRet = WaitForSingleObject( hTestEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - - /* set the event using the original handle */ - if( ! SetEvent( hEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() ); - goto cleanup; - } - - /* verify that the event is signalled by waiting on both handles */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - dwRet = WaitForSingleObject( hTestEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - /* reset the event using the new handle */ - if( ! ResetEvent( hTestEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:ResetEvent() call failed\n", GetLastError() ); - goto cleanup; - } - - /* verify that the event isn't signalled by waiting on both handles */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - dwRet = WaitForSingleObject( hTestEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - - /* test was successful */ - ret = PASS; - - -cleanup: - /* close the new event handle */ - if( hTestEvent != NULL ) - { - if( ! CloseHandle( hTestEvent ) ) - { - ret = FAIL; - Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - } - - /* close the original event handle */ - if( ! CloseHandle( hEvent ) ) - { - ret = FAIL; - Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - - /* failure message */ - if( ret != PASS ) - { - Fail( "Test failed\n" ); - } - - - /* PAL termination */ - PAL_Terminate(); - - /* return success or failure */ - return ret; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test5/test5.cpp b/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test5/test5.cpp deleted file mode 100644 index 6c692ba3b9b923..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/OpenEventW/test5/test5.cpp +++ /dev/null @@ -1,195 +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: test5.c -** -** Purpose: Positive test for OpenEventW. -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** WaitForSingleObject -** -** Purpose: -** -** Test to ensure proper operation of the OpenEventW() -** API by creating a new named event with CreateEventW() -** and verifying that it can be opened with OpenEventW(). -** It should be possible to use the event handles -** interchangeably, we test by setting the event with the -** original handle and waiting on it with the new one, -** then resetting it with the new one and waiting -** on it with the original one. -** -** -**===========================================================================*/ -#include - - - -PALTEST(threading_OpenEventW_test5_paltest_openeventw_test5, "threading/OpenEventW/test5/paltest_openeventw_test5") - -{ - /* local variables */ - BOOL ret = FAIL; - DWORD dwRet = 0; - HANDLE hEvent = NULL; - HANDLE hTestEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - WCHAR wcName[] = {'S','h','a','k','e','I','t','\0'}; - LPWSTR lpNameW = wcName; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with SetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - lpNameW ); - - if( hEvent == NULL ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* open a new handle to our event */ - hTestEvent = OpenEventW(EVENT_ALL_ACCESS, /* we want all rights */ - FALSE, /* no inherit */ - lpNameW ); - - if( hTestEvent == NULL ) - { - /* ERROR */ - Trace( "ERROR:%lu:OpenEventW() call failed\n", GetLastError() ); - goto cleanup; - } - - /* verify that the event isn't signalled yet by waiting on both */ - /* handles to the event object */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - dwRet = WaitForSingleObject( hTestEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - - /* set the event using the original handle */ - if( ! SetEvent( hEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() ); - goto cleanup; - } - - /* verify that the event is signalled by waiting on both handles */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - dwRet = WaitForSingleObject( hTestEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - goto cleanup; - } - - /* reset the event using the new handle */ - if( ! ResetEvent( hTestEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:ResetEvent() call failed\n", GetLastError() ); - goto cleanup; - } - - /* verify that the event isn't signalled by waiting on both handles */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - dwRet = WaitForSingleObject( hTestEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - goto cleanup; - } - - - /* test was successful */ - ret = PASS; - - -cleanup: - /* close the new event handle */ - if( hTestEvent != NULL ) - { - if( ! CloseHandle( hTestEvent ) ) - { - ret = FAIL; - Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - } - - /* close the original event handle */ - if( ! CloseHandle( hEvent ) ) - { - ret = FAIL; - Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - - /* failure message */ - if( ret != PASS ) - { - Fail( "Test failed\n" ); - } - - - /* PAL termination */ - PAL_TerminateEx(ret); - - /* return success or failure */ - return ret; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp index 9e57294b85a06d..93d309a28947f8 100644 --- a/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.cpp @@ -47,7 +47,7 @@ PALTEST(threading_QueryThreadCycleTime_test1_paltest_querythreadcycletime_test1, ULONG64 FirstCount, SecondCount; LONG64 Init; - Sleep(1); + PAL_Sleep(1); /* Grab a FirstCount, then loop for a bit to make the clock increase */ if (!QueryThreadCycleTime(cThread, (PULONG64)&FirstCount)) diff --git a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test1/test1.cpp deleted file mode 100644 index 2190c9a8e29384..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test1/test1.cpp +++ /dev/null @@ -1,98 +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: test1.c -** -** Purpose: Test for ResetEvent. Create an event with an initial -** state signaled. Then reset that signal, and check to see that -** the event is now not signaled. -** -** -**=========================================================*/ - -#include - -BOOL ResetEventTest() -{ - BOOL bRet = FALSE; - DWORD dwRet = 0; - - LPSECURITY_ATTRIBUTES lpEventAttributes = 0; - BOOL bManualReset = TRUE; - BOOL bInitialState = TRUE; - - /* Create an Event, ensure it is valid */ - HANDLE hEvent = CreateEvent( lpEventAttributes, - bManualReset, bInitialState, NULL); - - if (hEvent != INVALID_HANDLE_VALUE) - { - /* Check that WaitFor returns WAIT_OBJECT_0, indicating that - the event is signaled. - */ - - dwRet = WaitForSingleObject(hEvent,0); - - if (dwRet != WAIT_OBJECT_0) - { - Fail("ResetEventTest:WaitForSingleObject failed (%x)\n", GetLastError()); - } - else - { - /* Call ResetEvent, which will reset the signal */ - bRet = ResetEvent(hEvent); - - if (!bRet) - { - Fail("ResetEventTest:ResetEvent failed (%x)\n", GetLastError()); - } - else - { - /* Call WaitFor again, and since it has been reset, - the return value should now be WAIT_TIMEOUT - */ - dwRet = WaitForSingleObject(hEvent,0); - - if (dwRet != WAIT_TIMEOUT) - { - Fail("ResetEventTest:WaitForSingleObject %s failed (%x)\n", GetLastError()); - } - else - { - bRet = CloseHandle(hEvent); - - if (!bRet) - { - Fail("ResetEventTest:CloseHandle failed (%x)\n", GetLastError()); - } - } - } - } - } - else - { - Fail("ResetEventTest:CreateEvent failed (%x)\n", GetLastError()); - } - - return bRet; -} - -PALTEST(threading_ResetEvent_test1_paltest_resetevent_test1, "threading/ResetEvent/test1/paltest_resetevent_test1") -{ - - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - if(!ResetEventTest()) - { - Fail ("Test failed\n"); - } - - PAL_Terminate(); - return ( PASS ); - -} diff --git a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test2/test2.cpp deleted file mode 100644 index 2e04bec000910e..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test2/test2.cpp +++ /dev/null @@ -1,88 +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: test2.c -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** WaitForSingleObject -** -** Purpose: Test to ensure proper operation of the ResetEvent() -** API by calling it on an event handle that's already -** unsignalled. -** - -** -**===========================================================================*/ -#include - - - -PALTEST(threading_ResetEvent_test2_paltest_resetevent_test2, "threading/ResetEvent/test2/paltest_resetevent_test2") - -{ - /* local variables */ - DWORD dwRet = 0; - HANDLE hEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an unsignalled event which we can use with ResetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - NULL ); - - if( hEvent == INVALID_HANDLE_VALUE ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* verify that the event isn't signalled yet */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* try to reset the event */ - if( ! ResetEvent( hEvent ) ) - { - /* ERROR */ - Trace( "FAIL:%lu:ResetEvent() call failed\n", GetLastError() ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* close the event handle */ - if( ! CloseHandle( hEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - - - /* PAL termination */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test3/test3.cpp deleted file mode 100644 index f0c64499bd7418..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test3/test3.cpp +++ /dev/null @@ -1,85 +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: test3.c -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** -** Purpose: -** -** Test to ensure proper operation of the ResetEvent() -** API by calling it on an event handle that's been -** closed. We expect it to return an appropriate error -** result. -** -** - -** -**===========================================================================*/ -#include - - - -PALTEST(threading_ResetEvent_test3_paltest_resetevent_test3, "threading/ResetEvent/test3/paltest_resetevent_test3") - -{ - /* local variables */ - HANDLE hEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with ResetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - NULL ); - - if( hEvent == INVALID_HANDLE_VALUE ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* close the event handle */ - if( ! CloseHandle( hEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - - /* try to reset the event */ - if( ResetEvent( hEvent ) ) - { - /* ERROR */ - Fail( "FAIL:ResetEvent() call succeeded on a closed event handle\n" ); - } - - /* verify the result of GetLastError() */ - if( GetLastError() != ERROR_INVALID_HANDLE ) - { - /* ERROR */ - Fail( "FAIL:ResetEvent() call failed on a closed event handle " - "but returned an unexpected error result %lu\n" ); - } - - - - /* PAL termination */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test4/test4.cpp b/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test4/test4.cpp deleted file mode 100644 index cf89cd551a7f42..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/ResetEvent/test4/test4.cpp +++ /dev/null @@ -1,160 +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: test4.c -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** WaitForSingleObject -** DuplicateHandle -** GetCurrentProcess -** -** Purpose: -** -** Test to ensure proper operation of the ResetEvent() -** API by calling it on an event handle that's the -** result of a DuplicateHandle() call on another event -** handle. -** - -** -**===========================================================================*/ -#include - - - -PALTEST(threading_ResetEvent_test4_paltest_resetevent_test4, "threading/ResetEvent/test4/paltest_resetevent_test4") - -{ - /* local variables */ - DWORD dwRet = 0; - HANDLE hEvent = NULL; - HANDLE hDupEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = TRUE; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with ResetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - NULL ); - - if( hEvent == INVALID_HANDLE_VALUE ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* verify that the event is signalled already */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - - /* duplicate the event handle */ - if( ! (DuplicateHandle( - GetCurrentProcess(), - hEvent, - GetCurrentProcess(), - &hDupEvent, - GENERIC_READ|GENERIC_WRITE, /* ignored in PAL */ - FALSE, - DUPLICATE_SAME_ACCESS ) ) ) - { - Trace("ERROR:%u:DuplicateHandle() call failed\n", - GetLastError() ); - CloseHandle( hEvent ); - Fail("Test failed\n"); - } - - /* verify that the event is signalled with the duplicate handle */ - dwRet = WaitForSingleObject( hDupEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - CloseHandle( hEvent ); - CloseHandle( hDupEvent ); - Fail( "Test failed\n" ); - } - - - /* reset the event using the duplicate handle */ - if( ! ResetEvent( hDupEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:ResetEvent() call failed\n", GetLastError() ); - CloseHandle( hEvent ); - CloseHandle( hDupEvent ); - Fail( "Test failed\n" ); - } - - /* verify that the event isn't signalled using the duplicate handle*/ - dwRet = WaitForSingleObject( hDupEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* check that the event isn't signalled using the original event handle */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - - /* close the duplicate event handle */ - if( ! CloseHandle( hDupEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed for duplicate handle\n", - GetLastError() ); - } - - - /* close the event handle */ - if( ! CloseHandle( hEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed for original handle\n", - GetLastError() ); - } - - - /* PAL termination */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/ResumeThread/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/ResumeThread/test1/test1.cpp index 259fcbb9612d66..e83a2926e8dd64 100644 --- a/src/coreclr/pal/tests/palsuite/threading/ResumeThread/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/ResumeThread/test1/test1.cpp @@ -15,6 +15,7 @@ #include DWORD dwResumeThreadTestParameter = 0; +LONG completedThreadCount_ResumeThread_test1 = 0; DWORD PALAPI ResumeThreadTestThread( LPVOID lpParameter) { @@ -25,6 +26,7 @@ DWORD PALAPI ResumeThreadTestThread( LPVOID lpParameter) */ dwResumeThreadTestParameter = (DWORD)(SIZE_T)lpParameter; + InterlockedIncrement(&completedThreadCount_ResumeThread_test1); return dwRet; } @@ -53,65 +55,40 @@ BOOL ResumeThreadTest() if (hThread != NULL) { - /* Wait for one second. This should return WAIT_TIMEOUT */ - dwRet = WaitForSingleObject(hThread,1000); + PAL_Sleep(100); - if (dwRet != WAIT_TIMEOUT) + /* Check to ensure the parameter hasn't changed. The function + shouldn't have occurred yet. + */ + if (dwResumeThreadTestParameter != 0) { - Trace("ResumeThreadTest:WaitForSingleObject " - "failed (%x)\n",GetLastError()); + Trace("ResumeThreadTest:parameter error\n"); } else { - /* Check to ensure the parameter hasn't changed. The - function shouldn't have occurred yet. - */ - if (dwResumeThreadTestParameter != 0) + /* Call ResumeThread and ensure the return value is correct. */ + dwRet = ResumeThread(hThread); + + if (dwRet != 1) { - Trace("ResumeThreadTest:parameter error\n"); + Trace("ResumeThreadTest:ResumeThread " + "failed (%x)\n",GetLastError()); } else { - /* Call ResumeThread and ensure the return value is - correct. - */ - - dwRet = ResumeThread(hThread); + WaitForThreadCompletion(&completedThreadCount_ResumeThread_test1, 1); - if (dwRet != 1) + if (dwResumeThreadTestParameter != (DWORD)(SIZE_T)lpParameter) { - Trace("ResumeThreadTest:ResumeThread " - "failed (%x)\n",GetLastError()); + Trace("ResumeThreadTest:parameter error\n"); } else { - /* Wait again, now that the thread has been - resumed, and the return should be WAIT_OBJECT_0 - */ - dwRet = WaitForSingleObject(hThread,INFINITE); - - if (dwRet != WAIT_OBJECT_0) - { - Trace("ResumeThreadTest:WaitForSingleObject " - "failed (%x)\n",GetLastError()); - } - else - { - /* Check the param now and it should have been - set. - */ - if (dwResumeThreadTestParameter != (DWORD)(SIZE_T)lpParameter) - { - Trace("ResumeThreadTest:parameter error\n"); - } - else - { - bRet = TRUE; - } - } + bRet = TRUE; } } } + CloseHandle(hThread); } else { diff --git a/src/coreclr/pal/tests/palsuite/threading/RuntimeEvent/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/RuntimeEvent/test1/test1.cpp new file mode 100644 index 00000000000000..09f902393db1b1 --- /dev/null +++ b/src/coreclr/pal/tests/palsuite/threading/RuntimeEvent/test1/test1.cpp @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include + +#include "RuntimeEvent.h" + +static DWORD PALAPI SignalRuntimeEvent(LPVOID context) +{ + PAL_Sleep(10); + return PAL_SetEvent(context) ? 0 : 1; +} + +static void VerifyWait(void* event, uint32_t timeout, uint32_t expected) +{ + void* events[] = { event }; + uint32_t result = PAL_WaitForMultipleObjectsEx(1, events, false, timeout, false); + if (result != expected) + { + Fail("PAL_WaitForMultipleObjectsEx returned %u instead of %u\n", result, expected); + } +} + +PALTEST(threading_RuntimeEvent_test1_paltest_runtimeevent_test1, "threading/RuntimeEvent/test1/paltest_runtimeevent_test1") +{ + if (PAL_Initialize(argc, argv) != 0) + { + return FAIL; + } + + void* autoResetEvent = PAL_CreateEvent(nullptr, false, false); + if (autoResetEvent == nullptr) + { + Fail("PAL_CreateEvent failed to create an auto-reset event\n"); + } + + VerifyWait(autoResetEvent, 0, WAIT_TIMEOUT); + + DWORD threadId; + HANDLE thread = CreateThread(nullptr, 0, SignalRuntimeEvent, autoResetEvent, 0, &threadId); + if (thread == nullptr) + { + Fail("CreateThread failed with error %u\n", GetLastError()); + } + + VerifyWait(autoResetEvent, 10000, WAIT_OBJECT_0); + + CloseHandle(thread); + + VerifyWait(autoResetEvent, 0, WAIT_TIMEOUT); + + if (!PAL_SetEvent(autoResetEvent)) + { + Fail("PAL_SetEvent failed for an auto-reset event\n"); + } + + VerifyWait(autoResetEvent, 0, WAIT_OBJECT_0); + VerifyWait(autoResetEvent, 0, WAIT_TIMEOUT); + + if (!PAL_CloseEvent(autoResetEvent)) + { + Fail("PAL_CloseEvent failed for an auto-reset event\n"); + } + + void* manualResetEvent = PAL_CreateEvent(nullptr, true, false); + if (manualResetEvent == nullptr) + { + Fail("PAL_CreateEvent failed to create a manual-reset event\n"); + } + + VerifyWait(manualResetEvent, 0, WAIT_TIMEOUT); + + if (!PAL_SetEvent(manualResetEvent)) + { + Fail("PAL_SetEvent failed for a manual-reset event\n"); + } + + VerifyWait(manualResetEvent, 0, WAIT_OBJECT_0); + VerifyWait(manualResetEvent, 0, WAIT_OBJECT_0); + + if (!PAL_ResetEvent(manualResetEvent)) + { + Fail("PAL_ResetEvent failed for a manual-reset event\n"); + } + + VerifyWait(manualResetEvent, 0, WAIT_TIMEOUT); + + if (!PAL_CloseEvent(manualResetEvent)) + { + Fail("PAL_CloseEvent failed for a manual-reset event\n"); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/SetEvent/test1/test1.cpp deleted file mode 100644 index b374e713644171..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test1/test1.cpp +++ /dev/null @@ -1,93 +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: test1.c -** -** Purpose: Test for SetEvent. Create an Event and then set -** this event, checking the return value. Ensure that it returns -** positive. -** -** -**=========================================================*/ - -#include - -BOOL SetEventTest() -{ - int bRet = 0; - DWORD dwRet = 0; - - LPSECURITY_ATTRIBUTES lpEventAttributes = 0; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - - /* Create an event which we can use with SetEvent */ - HANDLE hEvent = CreateEvent( lpEventAttributes, - bManualReset, bInitialState, NULL); - - if (hEvent != INVALID_HANDLE_VALUE) - { - dwRet = WaitForSingleObject(hEvent,0); - - if (dwRet != WAIT_TIMEOUT) - { - Trace("SetEventTest:WaitForSingleObject failed (%x)\n", GetLastError()); - } - else - { - /* Set the event to the previously created event and check - the return value. - */ - bRet = SetEvent(hEvent); - - if (!bRet) - { - Trace("SetEventTest:SetEvent failed (%x)\n", GetLastError()); - } - else - { - dwRet = WaitForSingleObject(hEvent,0); - - if (dwRet != WAIT_OBJECT_0) - { - Trace("SetEventTest:WaitForSingleObject failed (%x)\n", GetLastError()); - } - else - { - dwRet = CloseHandle(hEvent); - - if (!dwRet) - { - Trace("SetEventTest:CloseHandle failed (%x)\n", GetLastError()); - } - } - } - } - } - else - { - Trace("SetEventTest:CreateEvent failed (%x)\n", GetLastError()); - } - - return bRet; -} - - -PALTEST(threading_SetEvent_test1_paltest_setevent_test1, "threading/SetEvent/test1/paltest_setevent_test1") -{ - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - if(SetEventTest() == 0) - { - Fail ("Test failed\n"); - } - - PAL_Terminate(); - return ( PASS ); - -} diff --git a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test2/test2.cpp b/src/coreclr/pal/tests/palsuite/threading/SetEvent/test2/test2.cpp deleted file mode 100644 index 373d0f7a53f67d..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test2/test2.cpp +++ /dev/null @@ -1,124 +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: test2.c -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** WaitForSingleObject -** -** Purpose: -** -** Test to ensure proper operation of the SetEvent() -** API by calling it on an event handle that's already set. -** - -** -**===========================================================================*/ -#include - - - -PALTEST(threading_SetEvent_test2_paltest_setevent_test2, "threading/SetEvent/test2/paltest_setevent_test2") - -{ - /* local variables */ - DWORD dwRet = 0; - HANDLE hEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with SetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - NULL ); - - if( hEvent == INVALID_HANDLE_VALUE ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* verify that the event isn't signalled yet */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* set the event */ - if( ! SetEvent( hEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* verify that the event is signalled */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* try to set the event again */ - if( ! SetEvent( hEvent ) ) - { - /* ERROR */ - Trace( "FAIL:%lu:SetEvent() call failed on signalled event\n", - GetLastError() ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* verify that the event is still signalled */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - - /* close the event handle */ - if( ! CloseHandle( hEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - - - /* PAL termination */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test3/test3.cpp b/src/coreclr/pal/tests/palsuite/threading/SetEvent/test3/test3.cpp deleted file mode 100644 index 057661d458072c..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test3/test3.cpp +++ /dev/null @@ -1,84 +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: test3.c -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** -** Purpose: -** -** Test to ensure proper operation of the SetEvent() -** API by calling it on an event handle that's been -** closed. We expect it to return an appropriate error -** result. -** - -** -**===========================================================================*/ -#include - - - -PALTEST(threading_SetEvent_test3_paltest_setevent_test3, "threading/SetEvent/test3/paltest_setevent_test3") - -{ - /* local variables */ - HANDLE hEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with SetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - NULL ); - - if( hEvent == INVALID_HANDLE_VALUE ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* close the event handle */ - if( ! CloseHandle( hEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() ); - } - - /* try to set the event */ - if( SetEvent( hEvent ) ) - { - /* ERROR */ - Fail( "FAIL:SetEvent() call succeeded on a closed event handle\n" ); - } - - /* verify the result of GetLastError() */ - if( GetLastError() != ERROR_INVALID_HANDLE ) - { - /* ERROR */ - Fail( "FAIL:SetEvent() call failed on a closed event handle" - "but returned an unexpected error result %lu\n" ); - } - - - - /* PAL termination */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test4/test4.cpp b/src/coreclr/pal/tests/palsuite/threading/SetEvent/test4/test4.cpp deleted file mode 100644 index 8a86ecf9badaea..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/SetEvent/test4/test4.cpp +++ /dev/null @@ -1,160 +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: test4.c -** -** Dependencies: PAL_Initialize -** PAL_Terminate -** CreateEvent -** CloseHandle -** WaitForSingleObject -** DuplicateHandle -** GetCurrentProcess -** -** Purpose: -** -** Test to ensure proper operation of the SetEvent() -** API by calling it on an event handle that's the -** result of a DuplicateHandle() call on another event -** handle. -** - -** -**===========================================================================*/ -#include - - - -PALTEST(threading_SetEvent_test4_paltest_setevent_test4, "threading/SetEvent/test4/paltest_setevent_test4") - -{ - /* local variables */ - DWORD dwRet = 0; - HANDLE hEvent = NULL; - HANDLE hDupEvent = NULL; - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = FALSE; - - - /* PAL initialization */ - if( (PAL_Initialize(argc, argv)) != 0 ) - { - return( FAIL ); - } - - - /* create an event which we can use with SetEvent */ - hEvent = CreateEvent( lpEventAttributes, - bManualReset, - bInitialState, - NULL ); - - if( hEvent == INVALID_HANDLE_VALUE ) - { - /* ERROR */ - Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() ); - } - - /* verify that the event isn't signalled yet */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - - /* duplicate the event handle */ - if( ! (DuplicateHandle( - GetCurrentProcess(), - hEvent, - GetCurrentProcess(), - &hDupEvent, - GENERIC_READ|GENERIC_WRITE, /* ignored in PAL */ - FALSE, - DUPLICATE_SAME_ACCESS ) ) ) - { - Trace("ERROR:%u:DuplicateHandle() call failed\n", - GetLastError() ); - CloseHandle( hEvent ); - Fail("Test failed\n"); - } - - /* verify that the event isn't signalled yet with the duplicate handle */ - dwRet = WaitForSingleObject( hDupEvent, 0 ); - if( dwRet != WAIT_TIMEOUT ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_TIMEOUT\n", - dwRet ); - CloseHandle( hEvent ); - CloseHandle( hDupEvent ); - Fail( "Test failed\n" ); - } - - - /* set the event using the duplicate handle */ - if( ! SetEvent( hDupEvent ) ) - { - /* ERROR */ - Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() ); - CloseHandle( hEvent ); - CloseHandle( hDupEvent ); - Fail( "Test failed\n" ); - } - - /* verify that the event is signalled using the duplicate handle*/ - dwRet = WaitForSingleObject( hDupEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - /* verify that the event is signalled using the original event handle */ - dwRet = WaitForSingleObject( hEvent, 0 ); - if( dwRet != WAIT_OBJECT_0 ) - { - /* ERROR */ - Trace( "ERROR:WaitForSingleObject() call returned %lu, " - "expected WAIT_OBJECT_0\n", - dwRet ); - CloseHandle( hEvent ); - Fail( "Test failed\n" ); - } - - - /* close the duplicate event handle */ - if( ! CloseHandle( hDupEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed for duplicate handle\n", - GetLastError() ); - } - - - /* close the event handle */ - if( ! CloseHandle( hEvent ) ) - { - Fail( "ERROR:%lu:CloseHandle() call failed for original handle\n", - GetLastError() ); - } - - - /* PAL termination */ - PAL_Terminate(); - - /* return success */ - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/Sleep/test1/Sleep.cpp b/src/coreclr/pal/tests/palsuite/threading/Sleep/test1/Sleep.cpp index d7fb16d8b963b8..5fd4d14b24c693 100644 --- a/src/coreclr/pal/tests/palsuite/threading/Sleep/test1/Sleep.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/Sleep/test1/Sleep.cpp @@ -45,7 +45,7 @@ PALTEST(threading_Sleep_test1_paltest_sleep_test1, "threading/Sleep/test1/paltes for( i = 0; i < sizeof(SleepTimes) / sizeof(DWORD); i++) { OldTimeStamp = minipal_hires_ticks(); - Sleep(SleepTimes[i]); + PAL_Sleep(SleepTimes[i]); NewTimeStamp = minipal_hires_ticks(); TimeDelta = (NewTimeStamp - OldTimeStamp) / (minipal_hires_tick_frequency() / 1000); diff --git a/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp b/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp index f6a06e1b527317..5a36f8fa58c6c7 100644 --- a/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/Sleep/test2/sleep.cpp @@ -45,7 +45,7 @@ PALTEST(threading_Sleep_test2_paltest_sleep_test2, "threading/Sleep/test2/paltes for( i = 0; i < sizeof(SleepTimes) / sizeof(DWORD); i++) { OldTimeStamp = minipal_hires_ticks(); - Sleep(SleepTimes[i]); + PAL_Sleep(SleepTimes[i]); NewTimeStamp = minipal_hires_ticks(); TimeDelta = (NewTimeStamp - OldTimeStamp) / (minipal_hires_tick_frequency() / 1000); diff --git a/src/coreclr/pal/tests/palsuite/threading/SleepEx/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/SleepEx/test1/test1.cpp deleted file mode 100644 index eeeceecbddf39f..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/SleepEx/test1/test1.cpp +++ /dev/null @@ -1,82 +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: test1.c -** -** Purpose: Tests that SleepEx correctly sleeps for a given amount of time, -** regardless of the alertable flag. -** -** -**===================================================================*/ - -#include - -typedef struct -{ - DWORD SleepTime; - BOOL Alertable; -} testCase; - -PALTEST(threading_SleepEx_test1_paltest_sleepex_test1, "threading/SleepEx/test1/paltest_sleepex_test1") -{ - /* Milliseconds of error which are acceptable Function execution time, etc. */ - DWORD AcceptableTimeError = 150; - - testCase testCases[] = - { - {0, FALSE}, - {50, FALSE}, - {100, FALSE}, - {500, FALSE}, - {2000, FALSE}, - - {0, TRUE}, - {50, TRUE}, - {100, TRUE}, - {500, TRUE}, - {2000, TRUE}, - }; - - int64_t OldTimeStamp; - int64_t NewTimeStamp; - DWORD MaxDelta; - DWORD TimeDelta; - DWORD i; - - if (0 != (PAL_Initialize(argc, argv))) - { - return FAIL; - } - - for (i = 0; i AcceptableTimeError) - { - MaxDelta = testCases[i].SleepTime + (DWORD)(testCases[i].SleepTime * 0.1); - } - else - { - MaxDelta = testCases[i].SleepTime + AcceptableTimeError; - } - - if (TimeDelta < testCases[i].SleepTime || TimeDelta > MaxDelta) - { - Fail("The sleep function slept for %d ms when it should have " - "slept for %d ms\n", TimeDelta, testCases[i].SleepTime); - } - } - - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/SwitchToThread/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/SwitchToThread/test1/test1.cpp index 4bfb886ebf48ca..2301ad154ace6f 100644 --- a/src/coreclr/pal/tests/palsuite/threading/SwitchToThread/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/SwitchToThread/test1/test1.cpp @@ -11,7 +11,7 @@ ** Dependencies: PAL_Initialize ** Fail ** SwitchToThread -** WaitForMultipleObject +** WaitForSingleObject ** CreateThread ** GetLastError ** @@ -23,7 +23,7 @@ #include #define THREAD_COUNT 10 #define REPEAT_COUNT 1000 -#define TIMEOUT 60000 +LONG completedThreadCount_SwitchToThread_test1 = 0; void PALAPI Run_Thread_switchtothread_test1(LPVOID lpParam); /** @@ -37,8 +37,7 @@ PALTEST(threading_SwitchToThread_test1_paltest_switchtothread_test1, "threading/ HANDLE hThread[THREAD_COUNT]; DWORD threadId[THREAD_COUNT]; - int i = 0; - int returnCode = 0; + int i = 0; /*PAL initialization */ if( (PAL_Initialize(argc, argv)) != 0 ) @@ -68,10 +67,10 @@ PALTEST(threading_SwitchToThread_test1_paltest_switchtothread_test1, "threading/ } - returnCode = WaitForMultipleObjectsEx(THREAD_COUNT, hThread, TRUE, TIMEOUT, FALSE); - if( WAIT_OBJECT_0 != returnCode ) + WaitForThreadCompletion(&completedThreadCount_SwitchToThread_test1, THREAD_COUNT); + for (i = 0; i < THREAD_COUNT; i++) { - Trace("Wait for Object(s) returned %d, expected value is %d, and GetLastError value is %d\n", returnCode, WAIT_OBJECT_0, GetLastError()); + CloseHandle(hThread[i]); } PAL_Terminate(); @@ -93,4 +92,5 @@ void PALAPI Run_Thread_switchtothread_test1 (LPVOID lpParam) "for thread id[%d], iteration [%d]\n", Id, i ); } } + InterlockedIncrement(&completedThreadCount_SwitchToThread_test1); } diff --git a/src/coreclr/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.cpp deleted file mode 100644 index b962dc306bba40..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.cpp +++ /dev/null @@ -1,225 +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: test1.c -** -** Purpose: Test for WaitForMultipleObjectsEx. Call the function -** on an array of 4 events, and ensure that it returns correct -** results when we do so. -** -** -**=========================================================*/ - -#include - -/* Originally written as WaitForMultipleObjects/test1 */ - - -/* Number of events in array */ -#define MAX_EVENTS 4 - -BOOL WaitForMultipleObjectsExTest() -{ - BOOL bRet = TRUE; - DWORD dwRet = 0; - DWORD i = 0, j = 0; - - LPSECURITY_ATTRIBUTES lpEventAttributes = NULL; - BOOL bManualReset = TRUE; - BOOL bInitialState = TRUE; - - HANDLE hEvent[MAX_EVENTS]; - - /* Run through this for loop and create 4 events */ - for (i = 0; i < MAX_EVENTS; i++) - { - hEvent[i] = CreateEvent( lpEventAttributes, - bManualReset, bInitialState, NULL); - - if (hEvent[i] == INVALID_HANDLE_VALUE) - { - Trace("WaitForMultipleObjectsExTest:CreateEvent %u failed (%x)\n", i, GetLastError()); - bRet = FALSE; - break; - } - - /* Set the current event */ - bRet = SetEvent(hEvent[i]); - - if (!bRet) - { - Trace("WaitForMultipleObjectsExTest:SetEvent %u failed (%x)\n", i, GetLastError()); - bRet = FALSE; - break; - } - - /* Ensure that this returns the correct value */ - dwRet = WaitForSingleObject(hEvent[i],0); - - if (dwRet != WAIT_OBJECT_0) - { - Trace("WaitForMultipleObjectsExTest:WaitForSingleObject %u failed (%x)\n", i, GetLastError()); - bRet = FALSE; - break; - } - - /* Reset the event, and again ensure that the return value of - WaitForSingle is correct. - */ - bRet = ResetEvent(hEvent[i]); - - if (!bRet) - { - Trace("WaitForMultipleObjectsExTest:ResetEvent %u failed (%x)\n", i, GetLastError()); - bRet = FALSE; - break; - } - - dwRet = WaitForSingleObject(hEvent[i],0); - - if (dwRet != WAIT_TIMEOUT) - { - Trace("WaitForMultipleObjectsExTest:WaitForSingleObject %u failed (%x)\n", i, GetLastError()); - bRet = FALSE; - break; - } - } - - /* - * If the first section of the test passed, move on to the - * second. - */ - - if (bRet) - { - BOOL bWaitAll = TRUE; - DWORD nCount = MAX_EVENTS; - CONST HANDLE *lpHandles = &hEvent[0]; - - /* Call WaitForMultipleObjectsEx on all the events, the return - should be WAIT_TIMEOUT - */ - dwRet = WaitForMultipleObjectsEx(nCount, - lpHandles, - bWaitAll, - 0, - FALSE); - - if (dwRet != WAIT_TIMEOUT) - { - Trace("WaitForMultipleObjectsExTest: WaitForMultipleObjectsEx failed (%x)\n", GetLastError()); - } - else - { - /* Step through each event and one at a time, set the - current test, while resetting all the other tests - */ - - for (i = 0; i < MAX_EVENTS; i++) - { - for (j = 0; j < MAX_EVENTS; j++) - { - if (j == i) - { - - bRet = SetEvent(hEvent[j]); - - if (!bRet) - { - Trace("WaitForMultipleObjectsExTest:SetEvent %j failed (%x)\n", j, GetLastError()); - break; - } - } - else - { - bRet = ResetEvent(hEvent[j]); - - if (!bRet) - { - Trace("WaitForMultipleObjectsExTest:ResetEvent %u failed (%x)\n", j, GetLastError()); - } - } - } - - bWaitAll = FALSE; - - /* Check that WaitFor returns WAIT_OBJECT + i */ - dwRet = WaitForMultipleObjectsEx( nCount, - lpHandles, bWaitAll, 0, FALSE); - - if (dwRet != WAIT_OBJECT_0+i) - { - Trace("WaitForMultipleObjectsExTest: WaitForMultipleObjectsEx failed (%x)\n", GetLastError()); - bRet = FALSE; - break; - } - } - } - - for (i = 0; i < MAX_EVENTS; i++) - { - bRet = CloseHandle(hEvent[i]); - - if (!bRet) - { - Trace("WaitForMultipleObjectsExTest:CloseHandle %u failed (%x)\n", i, GetLastError()); - } - } - } - - return bRet; -} - -BOOL WaitMultipleDuplicateHandleTest_WFMOEx_test1() -{ - BOOL testResult = TRUE; - const HANDLE eventHandle = CreateEvent(NULL, TRUE, TRUE, NULL); - HANDLE eventHandles[] = {eventHandle, eventHandle}; - - // WaitAny - Wait for any of the events (no error expected) - DWORD result = WaitForMultipleObjectsEx(sizeof(eventHandles) / sizeof(eventHandles[0]), eventHandles, FALSE, 0, FALSE); - if (result != WAIT_OBJECT_0) - { - Trace("WaitMultipleDuplicateHandleTest:WaitAny failed (%x)\n", GetLastError()); - testResult = FALSE; - } - - // WaitAll - Wait for all of the events (error expected) - result = WaitForMultipleObjectsEx(sizeof(eventHandles) / sizeof(eventHandles[0]), eventHandles, TRUE, 0, FALSE); - if (result != WAIT_FAILED) - { - Trace("WaitMultipleDuplicateHandleTest:WaitAll failed: call unexpectedly succeeded\n"); - testResult = FALSE; - } - else if (GetLastError() != ERROR_INVALID_PARAMETER) - { - Trace("WaitMultipleDuplicateHandleTest:WaitAll failed: unexpected last error (%x)\n"); - testResult = FALSE; - } - - return testResult; -} - -PALTEST(threading_WaitForMultipleObjectsEx_test1_paltest_waitformultipleobjectsex_test1, "threading/WaitForMultipleObjectsEx/test1/paltest_waitformultipleobjectsex_test1") -{ - - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - if(!WaitForMultipleObjectsExTest()) - { - Fail ("Test failed\n"); - } - - if (!WaitMultipleDuplicateHandleTest_WFMOEx_test1()) - { - Fail("Test failed\n"); - } - - PAL_Terminate(); - return PASS; -} diff --git a/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.cpp b/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.cpp deleted file mode 100644 index 6cdd34cb790735..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.cpp +++ /dev/null @@ -1,161 +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: WFSOThreadTest.c -** -** Purpose: Test for WaitForSingleObjectTest. -** Create One Thread and do some work -** Use WFSO For the Thread to finish -** -** Test Passes if the above operations are successful -** -** -** -**=========================================================*/ - - - -#include - - -//Declaring Variables -HANDLE hThread_WFSOThreadTest = NULL; -HANDLE hEvent_WFSOThreadTest = NULL; - -unsigned int globalcounter_WFSOThreadTest =0; - -//Declaring Function Prototypes -DWORD PALAPI incrementCounter(LPVOID params); - -PALTEST(threading_WaitForSingleObject_WFSOThreadTest_paltest_waitforsingleobject_wfsothreadtest, "threading/WaitForSingleObject/WFSOThreadTest/paltest_waitforsingleobject_wfsothreadtest") -{ - - //Declare local variables - DWORD dwThreadId=0; - DWORD dwWaitResult=0; - - //Initialize PAL - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - - //Create Event - hEvent_WFSOThreadTest = CreateEvent(NULL,TRUE,FALSE, NULL); - if(hEvent_WFSOThreadTest == NULL) - { - Fail("Create Event Failed\n" - "GetLastError returned %d\n", GetLastError()); - } - - - //Create Thread - hThread_WFSOThreadTest = CreateThread( - NULL, - 0, - incrementCounter, - NULL, - 0, - &dwThreadId); - - if ( NULL == hThread_WFSOThreadTest ) - { - Fail ( "CreateThread() returned NULL. Failing test.\n" - "GetLastError returned %d\n", GetLastError()); - } - - - //Wait For Thread to signal start - dwWaitResult = WaitForSingleObject(hEvent_WFSOThreadTest,INFINITE); - - switch (dwWaitResult) - { - // The thread wait was successful - case WAIT_OBJECT_0: - { - - Trace ("Wait for Single Object (hEvent) was successful.\n"); - break; - } - - // Time-out. - case WAIT_TIMEOUT: - { - Fail ( "Time -out. Failing test.\n" - "GetLastError returned %d\n", GetLastError()); - return FALSE; - } - } - - - //Wait for Thread to finish - dwWaitResult = WaitForSingleObject( - hThread_WFSOThreadTest, //handle to thread - 5000L); //Wait Indefinitely - - - switch (dwWaitResult) - { - // The thread wait was successful - case WAIT_OBJECT_0: - { - - Trace("Wait for thread was successful\n"); - - break; - } - - // Time-out. - case WAIT_TIMEOUT: - { - Fail ( "Time -out. Failing test.\n" - "GetLastError returned %d\n", GetLastError()); - return FALSE; - } - - } - - -//Close Handles -if (0==CloseHandle(hEvent_WFSOThreadTest)) - { - Trace("Could not Close event handle\n"); - Fail ( "GetLastError returned %d\n", GetLastError()); - } -if (0==CloseHandle(hThread_WFSOThreadTest)) - { - Trace("Could not Close thread handle\n"); - Fail ( "GetLastError returned %d\n", GetLastError()); - } - -PAL_Terminate(); -return ( PASS ); - -} - -DWORD PALAPI incrementCounter(LPVOID params) -{ - - //Signal Event so that main thread can start to wait for thread object - if (0==SetEvent(hEvent_WFSOThreadTest)) - { - Fail ( "SetEvent returned Zero. Failing test.\n" - "GetLastError returned %d\n", GetLastError()); - } - - for (globalcounter_WFSOThreadTest=0;globalcounter_WFSOThreadTest<100000;globalcounter_WFSOThreadTest++); - - //Sleep(5000); - - Trace("Global Counter Value: %d \n", globalcounter_WFSOThreadTest); - return 0; -} - - - - - - diff --git a/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.cpp deleted file mode 100644 index 421a3652294edf..00000000000000 --- a/src/coreclr/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.cpp +++ /dev/null @@ -1,120 +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: test1.c -** -** Purpose: Test for WaitForSingleObjectTest. Create two events, one -** with a TRUE and one with FALSE initial state. Ensure that WaitForSingle -** returns correct values for each of these. -** -** -**=========================================================*/ - -#include - -BOOL WaitForSingleObjectTest() -{ - - BOOL bRet = FALSE; - DWORD dwRet = 0; - - LPSECURITY_ATTRIBUTES lpEventAttributes = 0; - BOOL bManualReset = TRUE; - BOOL bInitialState = TRUE; - - HANDLE hEvent; - - /* Create an event, and ensure the HANDLE is valid */ - hEvent = CreateEvent(lpEventAttributes, bManualReset, - bInitialState, NULL); - - if (hEvent != INVALID_HANDLE_VALUE) - { - - /* Call WaitForSingleObject with 0 time on the event. It - should return WAIT_OBJECT_0 - */ - - dwRet = WaitForSingleObject(hEvent,0); - - if (dwRet != WAIT_OBJECT_0) - { - Trace("WaitForSingleObjectTest:WaitForSingleObject failed (%x)\n", GetLastError()); - } - else - { - bRet = CloseHandle(hEvent); - - if (!bRet) - { - Trace("WaitForSingleObjectTest:CloseHandle failed (%x)\n", GetLastError()); - } - } - } - else - { - Trace("WaitForSingleObjectTest:CreateEvent failed (%x)\n", GetLastError()); - } - - /* If the first section passed, Create another event, with the - initial state being FALSE this time. - */ - - if (bRet) - { - bRet = FALSE; - - bInitialState = FALSE; - - hEvent = CreateEvent( lpEventAttributes, - bManualReset, bInitialState, NULL); - - if (hEvent != INVALID_HANDLE_VALUE) - { - - /* Test WaitForSingleObject and ensure that it returns - WAIT_TIMEOUT in this case. - */ - - dwRet = WaitForSingleObject(hEvent,0); - - if (dwRet != WAIT_TIMEOUT) - { - Trace("WaitForSingleObjectTest:WaitForSingleObject failed (%x)\n", GetLastError()); - } - else - { - bRet = CloseHandle(hEvent); - - if (!bRet) - { - Trace("WaitForSingleObjectTest:CloseHandle failed (%x)\n", GetLastError()); - } - } - } - else - { - Trace("WaitForSingleObjectTest::CreateEvent failed (%x)\n", GetLastError()); - } - } - return bRet; -} - -PALTEST(threading_WaitForSingleObject_test1_paltest_waitforsingleobject_test1, "threading/WaitForSingleObject/test1/paltest_waitforsingleobject_test1") -{ - if(0 != (PAL_Initialize(argc, argv))) - { - return ( FAIL ); - } - - if(!WaitForSingleObjectTest()) - { - Fail ("Test failed\n"); - } - - PAL_Terminate(); - return ( PASS ); - -} diff --git a/src/coreclr/pal/tests/palsuite/threading/YieldProcessor/test1/test1.cpp b/src/coreclr/pal/tests/palsuite/threading/YieldProcessor/test1/test1.cpp index dd80015e05f733..3efcd208be977f 100644 --- a/src/coreclr/pal/tests/palsuite/threading/YieldProcessor/test1/test1.cpp +++ b/src/coreclr/pal/tests/palsuite/threading/YieldProcessor/test1/test1.cpp @@ -11,7 +11,7 @@ ** Dependencies: PAL_Initialize ** Fail ** YieldProcessor -** WaitForMultipleObject +** WaitForSingleObject ** CreateThread ** GetLastError ** @@ -23,7 +23,7 @@ #include #define THREAD_COUNT 10 #define REPEAT_COUNT 1000 -#define TIMEOUT 60000 +LONG completedThreadCount_YieldProcessor_test1 = 0; void PALAPI Run_Thread_yieldprocessor_test1(LPVOID lpParam); /** @@ -37,8 +37,7 @@ PALTEST(threading_YieldProcessor_test1_paltest_yieldprocessor_test1, "threading/ HANDLE hThread[THREAD_COUNT]; DWORD threadId[THREAD_COUNT]; - int i = 0; - int returnCode = 0; + int i = 0; /*PAL initialization */ if( (PAL_Initialize(argc, argv)) != 0 ) @@ -68,10 +67,10 @@ PALTEST(threading_YieldProcessor_test1_paltest_yieldprocessor_test1, "threading/ } - returnCode = WaitForMultipleObjectsEx(THREAD_COUNT, hThread, TRUE, TIMEOUT, FALSE); - if( WAIT_OBJECT_0 != returnCode ) + WaitForThreadCompletion(&completedThreadCount_YieldProcessor_test1, THREAD_COUNT); + for (i = 0; i < THREAD_COUNT; i++) { - Trace("Wait for Object(s) returned %d, expected value is %d, and GetLastError value is %d\n", returnCode, WAIT_OBJECT_0, GetLastError()); + CloseHandle(hThread[i]); } PAL_Terminate(); @@ -88,4 +87,5 @@ void PALAPI Run_Thread_yieldprocessor_test1 (LPVOID lpParam) // No error code set nor does it have any return code YieldProcessor(); } + InterlockedIncrement(&completedThreadCount_YieldProcessor_test1); } diff --git a/src/coreclr/runtime/RuntimeEvent.h b/src/coreclr/runtime/RuntimeEvent.h new file mode 100644 index 00000000000000..3f9ee7d125a83f --- /dev/null +++ b/src/coreclr/runtime/RuntimeEvent.h @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __RUNTIME_EVENT_H__ +#define __RUNTIME_EVENT_H__ + +#include + +void* PAL_CreateEvent(void* eventAttributes, bool manualReset, bool initialState); +bool PAL_CloseEvent(void* event); +bool PAL_SetEvent(void* event); +bool PAL_ResetEvent(void* event); +void PAL_Sleep(uint32_t milliseconds); + +// Unix supports a single event and waitAll must be false. Windows forwards to the OS implementation. +uint32_t PAL_WaitForMultipleObjectsEx( + uint32_t count, + void* const* events, + bool waitAll, + uint32_t milliseconds, + bool alertable); + +#endif // __RUNTIME_EVENT_H__ diff --git a/src/coreclr/runtime/unix/RuntimeEvent.cpp b/src/coreclr/runtime/unix/RuntimeEvent.cpp new file mode 100644 index 00000000000000..e9c59549fc78ca --- /dev/null +++ b/src/coreclr/runtime/unix/RuntimeEvent.cpp @@ -0,0 +1,338 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "../RuntimeEvent.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "minipalconfig.h" + +static constexpr uint32_t Infinite = UINT32_MAX; +static constexpr uint32_t MillisecondsToNanoseconds = 1000000; +static constexpr uint32_t NanosecondsPerSecond = 1000000000; +static constexpr uint32_t WaitFailed = UINT32_MAX; +static constexpr uint32_t WaitObject0 = 0; +static constexpr uint32_t WaitTimeout = 258; + +static void AddMilliseconds(timespec* time, uint32_t milliseconds) +{ + uint64_t nanoseconds = time->tv_nsec + static_cast(milliseconds) * MillisecondsToNanoseconds; + if (nanoseconds >= NanosecondsPerSecond) + { + time->tv_sec += nanoseconds / NanosecondsPerSecond; + nanoseconds %= NanosecondsPerSecond; + } + + time->tv_nsec = nanoseconds; +} + +static void NanosecondsToTimeSpec(uint64_t nanoseconds, timespec* time) +{ + time->tv_sec = nanoseconds / NanosecondsPerSecond; + time->tv_nsec = nanoseconds % NanosecondsPerSecond; +} + +class RuntimeEvent +{ + pthread_cond_t m_condition; + pthread_mutex_t m_mutex; + bool m_manualReset; + bool m_state; + bool m_isValid; + +public: + RuntimeEvent(bool manualReset, bool initialState) + : m_manualReset(manualReset), + m_state(initialState), + m_isValid(false) + { + } + + bool Initialize() + { + pthread_condattr_t attributes; + int status = pthread_condattr_init(&attributes); + if (status != 0) + { + return false; + } + + bool success = false; + +#if HAVE_PTHREAD_CONDATTR_SETCLOCK && !HAVE_CLOCK_GETTIME_NSEC_NP + status = pthread_condattr_setclock(&attributes, CLOCK_MONOTONIC); + if (status != 0) + { + goto Exit; + } +#endif // HAVE_PTHREAD_CONDATTR_SETCLOCK && !HAVE_CLOCK_GETTIME_NSEC_NP + + status = pthread_mutex_init(&m_mutex, nullptr); + if (status != 0) + { + goto Exit; + } + + status = pthread_cond_init(&m_condition, &attributes); + if (status != 0) + { + status = pthread_mutex_destroy(&m_mutex); + assert(status == 0); + goto Exit; + } + + m_isValid = true; + success = true; + + Exit: + status = pthread_condattr_destroy(&attributes); + assert(status == 0); + return success; + } + + bool Destroy() + { + if (!m_isValid) + { + return true; + } + + int conditionStatus = pthread_cond_destroy(&m_condition); + assert(conditionStatus == 0); + + int mutexStatus = pthread_mutex_destroy(&m_mutex); + assert(mutexStatus == 0); + + m_isValid = false; + return conditionStatus == 0 && mutexStatus == 0; + } + + uint32_t Wait(uint32_t milliseconds) + { + timespec endTime; +#if HAVE_CLOCK_GETTIME_NSEC_NP + uint64_t endNanoseconds = 0; + if (milliseconds != Infinite) + { + uint64_t nanoseconds = static_cast(milliseconds) * MillisecondsToNanoseconds; + NanosecondsToTimeSpec(nanoseconds, &endTime); + endNanoseconds = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) + nanoseconds; + } +#elif HAVE_PTHREAD_CONDATTR_SETCLOCK + if (milliseconds != Infinite) + { + clock_gettime(CLOCK_MONOTONIC, &endTime); + AddMilliseconds(&endTime, milliseconds); + } +#else +#error "Don't know how to perform timed wait on this platform" +#endif + + int status = pthread_mutex_lock(&m_mutex); + if (status != 0) + { + return WaitFailed; + } + + while (!m_state) + { + if (milliseconds == Infinite) + { + status = pthread_cond_wait(&m_condition, &m_mutex); + } + else + { +#if HAVE_CLOCK_GETTIME_NSEC_NP + status = pthread_cond_timedwait_relative_np(&m_condition, &m_mutex, &endTime); + if (status == 0 && !m_state) + { + uint64_t currentNanoseconds = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); + if (currentNanoseconds < endNanoseconds) + { + NanosecondsToTimeSpec(endNanoseconds - currentNanoseconds, &endTime); + } + else + { + status = ETIMEDOUT; + } + } +#else // HAVE_CLOCK_GETTIME_NSEC_NP + status = pthread_cond_timedwait(&m_condition, &m_mutex, &endTime); +#endif // HAVE_CLOCK_GETTIME_NSEC_NP + } + + if (status != 0) + { + break; + } + } + + if (status == 0 && !m_manualReset) + { + m_state = false; + } + + int unlockStatus = pthread_mutex_unlock(&m_mutex); + if (unlockStatus != 0) + { + return WaitFailed; + } + + if (status == 0) + { + return WaitObject0; + } + + return status == ETIMEDOUT ? WaitTimeout : WaitFailed; + } + + bool Set() + { + int status = pthread_mutex_lock(&m_mutex); + if (status != 0) + { + return false; + } + + m_state = true; + status = pthread_cond_broadcast(&m_condition); + int unlockStatus = pthread_mutex_unlock(&m_mutex); + return status == 0 && unlockStatus == 0; + } + + bool Reset() + { + int status = pthread_mutex_lock(&m_mutex); + if (status != 0) + { + return false; + } + + m_state = false; + return pthread_mutex_unlock(&m_mutex) == 0; + } +}; + +void* PAL_CreateEvent(void* eventAttributes, bool manualReset, bool initialState) +{ + (void)eventAttributes; + + RuntimeEvent* event = new (std::nothrow) RuntimeEvent(manualReset, initialState); + if (event == nullptr) + { + return nullptr; + } + + if (!event->Initialize()) + { + delete event; + return nullptr; + } + + return event; +} + +bool PAL_CloseEvent(void* event) +{ + if (event == nullptr) + { + return false; + } + + RuntimeEvent* runtimeEvent = static_cast(event); + bool success = runtimeEvent->Destroy(); + delete runtimeEvent; + return success; +} + +bool PAL_SetEvent(void* event) +{ + if (event == nullptr) + { + return false; + } + + return static_cast(event)->Set(); +} + +bool PAL_ResetEvent(void* event) +{ + if (event == nullptr) + { + return false; + } + + return static_cast(event)->Reset(); +} + +static void SleepMicroseconds(uint64_t microseconds) +{ + timespec requested; + requested.tv_sec = microseconds / 1000000; + requested.tv_nsec = (microseconds % 1000000) * 1000; + + timespec remaining; + while (nanosleep(&requested, &remaining) != 0 && errno == EINTR) + { + requested = remaining; + } +} + +void PAL_Sleep(uint32_t milliseconds) +{ +#if defined(TARGET_WASM) && !defined(FEATURE_MULTITHREADING) + (void)milliseconds; + return; +#endif + + if (milliseconds == 0) + { + sched_yield(); + return; + } + + if (milliseconds == Infinite) + { + while (true) + { + usleep(999000); + } + } + + SleepMicroseconds(static_cast(milliseconds) * 1000); +} + +uint32_t PAL_WaitForMultipleObjectsEx( + uint32_t count, + void* const* events, + bool waitAll, + uint32_t milliseconds, + bool alertable) +{ + (void)alertable; + + assert(count == 1); + assert(!waitAll); + + if (count != 1 || events == nullptr || events[0] == nullptr || waitAll) + { + return WaitFailed; + } + +#if defined(TARGET_WASM) && !defined(FEATURE_MULTITHREADING) + if (milliseconds != 0) + { + assert(!"Cannot block on an event wait in single-threaded mode"); + return WaitFailed; + } +#endif + + return static_cast(events[0])->Wait(milliseconds); +} diff --git a/src/coreclr/runtime/windows/RuntimeEvent.cpp b/src/coreclr/runtime/windows/RuntimeEvent.cpp new file mode 100644 index 00000000000000..0684534e4095df --- /dev/null +++ b/src/coreclr/runtime/windows/RuntimeEvent.cpp @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "../RuntimeEvent.h" + +#include + +void* PAL_CreateEvent(void* eventAttributes, bool manualReset, bool initialState) +{ + return CreateEventW( + static_cast(eventAttributes), + manualReset, + initialState, + nullptr); +} + +bool PAL_CloseEvent(void* event) +{ + return CloseHandle(event) != FALSE; +} + +bool PAL_SetEvent(void* event) +{ + return SetEvent(event) != FALSE; +} + +bool PAL_ResetEvent(void* event) +{ + return ResetEvent(event) != FALSE; +} + +void PAL_Sleep(uint32_t milliseconds) +{ + Sleep(milliseconds); +} + +uint32_t PAL_WaitForMultipleObjectsEx( + uint32_t count, + void* const* events, + bool waitAll, + uint32_t milliseconds, + bool alertable) +{ + return WaitForMultipleObjectsEx(count, events, waitAll, milliseconds, alertable); +} diff --git a/src/coreclr/utilcode/hostimpl.cpp b/src/coreclr/utilcode/hostimpl.cpp index e463af9f705a08..035f8959bae213 100644 --- a/src/coreclr/utilcode/hostimpl.cpp +++ b/src/coreclr/utilcode/hostimpl.cpp @@ -38,11 +38,6 @@ void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie) minipal_mutex_leave((minipal_mutex*)cookie); } -DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) -{ - return SleepEx(dwMilliseconds, bAlertable); -} - LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp index 7b987cdd1aea32..1165e1fbbcb1e4 100644 --- a/src/coreclr/utilcode/stresslog.cpp +++ b/src/coreclr/utilcode/stresslog.cpp @@ -16,6 +16,7 @@ #define DONOT_DEFINE_ETW_CALLBACK #include "eventtracebase.h" #include "minipal/time.h" +#include "../runtime/RuntimeEvent.h" #if !defined(STRESS_LOG_READONLY) #ifdef HOST_WINDOWS @@ -389,7 +390,7 @@ void StressLog::Terminate(BOOL fProcessDetach) { // threads are out of logMsg. In practice, since they can no longer enter logMsg // and there are no blocking operations in logMsg, simply sleeping will ensure // that everyone gets out. - ClrSleepEx(2, FALSE); + PAL_Sleep(2); lockh.Acquire(); } @@ -999,4 +1000,3 @@ void __cdecl ThreadStressLog::operator delete(void* p) #endif //MEMORY_MAPPED_STRESSLOG #endif // STRESS_LOG - diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index a9e1dcc0fb00b9..f002b0e5b6e76c 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -12,6 +12,7 @@ ===========================================================*/ #include "common.h" +#include "RuntimeEvent.h" #include @@ -1282,7 +1283,7 @@ static void RunMainPost() // if (dwSecondsToSleep != 0) { - ClrSleepEx(dwSecondsToSleep * 1000, FALSE); + PAL_Sleep(dwSecondsToSleep * 1000); } } diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index e1c06d2c629797..f75fb637e01db1 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -116,6 +116,7 @@ // boxing this describes this feature. #include "common.h" +#include "RuntimeEvent.h" #include "vars.hpp" #include "log.h" @@ -790,7 +791,7 @@ void EEStartupHelper() _ASSERTE(NULL != g_pConfig); if (g_pConfig->StartupDelayMS()) { - ClrSleepEx(g_pConfig->StartupDelayMS(), FALSE); + PAL_Sleep(g_pConfig->StartupDelayMS()); } #endif @@ -1674,6 +1675,9 @@ static void RuntimeThreadShutdown(void* thread) GCX_COOP_NO_DTOR_END(); } +#ifdef TARGET_UNIX + pThread->SetThreadExited(); +#endif // TARGET_UNIX pThread->DetachThread(TRUE); } else diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index 6a0effc18054ec..f9885ecbb749df 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -348,4 +348,3 @@ void LogErrorToHost(const char* format, ...) MINIPAL_ATTR_FORMAT_PRINTF(1, 2); #endif // !_common_h_ - diff --git a/src/coreclr/vm/eepolicy.cpp b/src/coreclr/vm/eepolicy.cpp index bdf31244611f23..28ac249cb805e2 100644 --- a/src/coreclr/vm/eepolicy.cpp +++ b/src/coreclr/vm/eepolicy.cpp @@ -6,6 +6,7 @@ // --------------------------------------------------------------------------- #include "common.h" +#include "RuntimeEvent.h" #include "eepolicy.h" #include "corhost.h" #include "dbginterface.h" @@ -448,7 +449,7 @@ void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, PEXCEPTION_POINTERS // for GC during the stacktrace reporting. GCX_PREEMP(); - ClrSleepEx(INFINITE, /*bAlertable*/ FALSE); + PAL_Sleep(INFINITE); } return; } @@ -685,11 +686,14 @@ void DisplayStackOverflowException() PrintToStdErrA("Stack overflow.\n"); } +static volatile LONG g_stackOverflowCallStackLogged = 0; + DWORD LogStackOverflowStackTraceThread(void* arg) { - LogCallstackForLogWorker((Thread*)arg, NULL, /*captureStackOverflowTrace*/ true); + LogCallstackForLogWorker((Thread*)arg, NULL, /*captureStackOverflowTrace*/ true); + InterlockedExchange(&g_stackOverflowCallStackLogged, 2); - return 0; + return 0; } void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pExceptionInfo, BOOL fSkipDebugger) @@ -747,8 +751,6 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE fef.InitAndLink(pExceptionContext); } - static volatile LONG g_stackOverflowCallStackLogged = 0; - // Dump stack trace only for the first thread failing with stack overflow to prevent mixing // multiple stack traces together. if (InterlockedCompareExchange(&g_stackOverflowCallStackLogged, 1, 0) == 0) @@ -763,15 +765,19 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE if (stackDumpThreadHandle != NULL) { // Wait for the stack trace logging completion - DWORD res = WaitForSingleObject(stackDumpThreadHandle, INFINITE); - _ASSERTE(res == WAIT_OBJECT_0); + while (g_stackOverflowCallStackLogged != 2) + { + PAL_Sleep(1); + } #ifdef _DEBUG if (g_LogStackOverflowExit) PrintToStdErrA("@Stack trace printing helper thread exited.\n"); #endif } - - g_stackOverflowCallStackLogged = 2; + else + { + InterlockedExchange(&g_stackOverflowCallStackLogged, 2); + } } else { @@ -782,7 +788,7 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE // Wait for the thread that is logging the stack trace to complete while (g_stackOverflowCallStackLogged != 2) { - Sleep(50); + PAL_Sleep(50); } } diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index 392041db03ebeb..9173e021087bec 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -16,6 +16,7 @@ #include "typestring.h" #include "clrversion.h" #include "hostinformation.h" +#include "RuntimeEvent.h" #ifdef HOST_WINDOWS #include @@ -1123,7 +1124,7 @@ ep_rt_thread_sleep (uint64_t ns) PAL_nanosleep (ns); #else //TARGET_UNIX const uint32_t NUM_NANOSECONDS_IN_1_MS = 1000000; - ClrSleepEx (static_cast(ns / NUM_NANOSECONDS_IN_1_MS), FALSE); + PAL_Sleep(static_cast(ns / NUM_NANOSECONDS_IN_1_MS)); #endif //TARGET_UNIX #endif // PERFTRACING_DISABLE_THREADS } diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp index 56db5891234347..d213af255a3b59 100644 --- a/src/coreclr/vm/finalizerthread.cpp +++ b/src/coreclr/vm/finalizerthread.cpp @@ -3,6 +3,7 @@ // =========================================================================== #include "common.h" +#include "RuntimeEvent.h" #include "finalizerthread.h" #include "threadsuspend.h" @@ -321,7 +322,7 @@ OBJECTREF FinalizerThread::GetNextFinalizableObject() // regular not re-arming finalizables. GetFinalizerThread()->m_GCOnTransitionsOK = FALSE; GetFinalizerThread()->EnablePreemptiveGC(); - ClrSleepEx(1, false); + PAL_Sleep(1); GetFinalizerThread()->DisablePreemptiveGC(); GetFinalizerThread()->m_GCOnTransitionsOK = TRUE; } @@ -458,7 +459,7 @@ void FinalizerThread::WaitForFinalizerEvent (CLREvent *event) cEventsForWait--; } - switch (WaitForMultipleObjectsEx( + switch (PAL_WaitForMultipleObjectsEx( cEventsForWait, // # objects to wait on &(MHandles[uiEventIndexOffsetForWait]), // array of objects to wait on FALSE, // bWaitAll == FALSE, so wait for first signal diff --git a/src/coreclr/vm/hosting.cpp b/src/coreclr/vm/hosting.cpp index 640f31baf71fcb..47f1ab085e5301 100644 --- a/src/coreclr/vm/hosting.cpp +++ b/src/coreclr/vm/hosting.cpp @@ -3,6 +3,7 @@ // #include "common.h" +#include "RuntimeEvent.h" #include "mscoree.h" #include "corhost.h" @@ -210,12 +211,6 @@ BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWO return ::VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); } -DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) -{ - WRAPPER_NO_CONTRACT; - return ::SleepEx(dwMilliseconds, bAlertable); -} - // non-zero return value if this function causes the OS to switch to another thread // See file:spinlock.h#SwitchToThreadSpinning for an explanation of dwSwitchCount BOOL __SwitchToThread (DWORD dwSleepMSec, DWORD dwSwitchCount) @@ -232,7 +227,7 @@ BOOL __SwitchToThread (DWORD dwSleepMSec, DWORD dwSwitchCount) if (dwSleepMSec > 0) { - ClrSleepEx(dwSleepMSec,FALSE); + PAL_Sleep(dwSleepMSec); return TRUE; } @@ -259,7 +254,7 @@ BOOL __SwitchToThread (DWORD dwSleepMSec, DWORD dwSwitchCount) _ASSERTE(CALLER_LIMITS_SPINNING < SLEEP_START_THRESHOLD); if (dwSwitchCount >= SLEEP_START_THRESHOLD) { - ClrSleepEx(1, FALSE); + PAL_Sleep(1); } return SwitchToThread(); diff --git a/src/coreclr/vm/multicorejit.cpp b/src/coreclr/vm/multicorejit.cpp index 5b1f0fcb957c96..e083eee89733bd 100644 --- a/src/coreclr/vm/multicorejit.cpp +++ b/src/coreclr/vm/multicorejit.cpp @@ -10,6 +10,7 @@ // #include "common.h" +#include "RuntimeEvent.h" #include "vars.hpp" #include "eeconfig.h" #include "dllimport.h" @@ -1058,7 +1059,7 @@ HRESULT MulticoreJitRecorder::StartProfile(const WCHAR * pRoot, const WCHAR * pF { MulticoreJitTrace(("Delay main thread %d ms", g_MulticoreJitDelay)); - ClrSleepEx(g_MulticoreJitDelay, FALSE); + PAL_Sleep(g_MulticoreJitDelay); } player.SuppressRelease(); diff --git a/src/coreclr/vm/profdetach.cpp b/src/coreclr/vm/profdetach.cpp index 258d59bb6b2e71..27224da3af3e5d 100644 --- a/src/coreclr/vm/profdetach.cpp +++ b/src/coreclr/vm/profdetach.cpp @@ -10,6 +10,7 @@ // ====================================================================================== #include "common.h" +#include "RuntimeEvent.h" #ifdef FEATURE_PROFAPI_ATTACH_DETACH @@ -449,7 +450,7 @@ void ProfilingAPIDetach::SleepWhileProfilerEvacuates(ProfilerDetachInfo *pDetach // At this point it's safe to cast ui64SleepMilliseconds down to a DWORD since we // know it's between s_dwMinSleepMs & s_dwMaxSleepMs _ASSERTE(ui64SleepMilliseconds <= 0xFFFFffff); - ClrSleepEx((DWORD) ui64SleepMilliseconds, FALSE /* alertable */); + PAL_Sleep((DWORD)ui64SleepMilliseconds); } diff --git a/src/coreclr/vm/rejit.cpp b/src/coreclr/vm/rejit.cpp index 0f92361aa36f93..383b5ce309d076 100644 --- a/src/coreclr/vm/rejit.cpp +++ b/src/coreclr/vm/rejit.cpp @@ -132,6 +132,7 @@ // ====================================================================================== #include "common.h" +#include "RuntimeEvent.h" #include "rejit.h" #include "method.hpp" #include "eeconfig.h" @@ -1092,7 +1093,7 @@ HRESULT ReJitManager::ConfigureILCodeVersion(ILCodeVersion ilCodeVersion) break; // the other thread got the parameters successfully, go race to rejit } } - ClrSleepEx(1, FALSE); + PAL_Sleep(1); } } diff --git a/src/coreclr/vm/synch.cpp b/src/coreclr/vm/synch.cpp index 54998f896738fc..eed3c50f1abef8 100644 --- a/src/coreclr/vm/synch.cpp +++ b/src/coreclr/vm/synch.cpp @@ -7,6 +7,7 @@ #include "common.h" #include "corhost.h" +#include "RuntimeEvent.h" #include "synch.h" void CLREventBase::CreateAutoEvent (BOOL bInitialState // If TRUE, initial state is signalled @@ -23,7 +24,7 @@ void CLREventBase::CreateAutoEvent (BOOL bInitialState // If TRUE, initial stat CONTRACTL_END; { - HANDLE h = CreateEvent(NULL,FALSE,bInitialState,NULL); + HANDLE h = PAL_CreateEvent(NULL, false, bInitialState); if (h == NULL) { ThrowOutOfMemory(); } @@ -71,7 +72,7 @@ void CLREventBase::CreateManualEvent (BOOL bInitialState // If TRUE, initial st CONTRACTL_END; { - HANDLE h = CreateEvent(NULL,TRUE,bInitialState,NULL); + HANDLE h = PAL_CreateEvent(NULL, true, bInitialState); if (h == NULL) { ThrowOutOfMemory(); } @@ -117,7 +118,7 @@ void CLREventBase::CloseEvent() if (m_handle != INVALID_HANDLE_VALUE) { { - CloseHandle(m_handle); + PAL_CloseEvent(m_handle); } m_handle = INVALID_HANDLE_VALUE; @@ -138,7 +139,7 @@ BOOL CLREventBase::Set() _ASSERTE(Thread::Debug_AllowCallout()); { - return SetEvent(m_handle); + return PAL_SetEvent(m_handle); } } @@ -157,7 +158,7 @@ BOOL CLREventBase::Reset() _ASSERTE(Thread::Debug_AllowCallout()); { - return ResetEvent(m_handle); + return PAL_ResetEvent(m_handle); } } @@ -166,7 +167,7 @@ static DWORD CLREventWaitHelper2(HANDLE handle, DWORD dwMilliseconds, BOOL alert { STATIC_CONTRACT_THROWS; - return WaitForSingleObjectEx(handle,dwMilliseconds,alertable); + return PAL_WaitForMultipleObjectsEx(1, &handle, false, dwMilliseconds, alertable); } static DWORD CLREventWaitHelper(HANDLE handle, DWORD dwMilliseconds, BOOL alertable) @@ -248,7 +249,11 @@ DWORD CLREventBase::WaitEx(DWORD dwMilliseconds, WaitMode mode) { if (pThread && alertable) { GCX_PREEMP(); +#ifdef TARGET_UNIX + return PAL_WaitForMultipleObjectsEx(1, &m_handle, false, dwMilliseconds, alertable); +#else return pThread->DoReentrantWaitWithRetry(m_handle, dwMilliseconds, mode); +#endif // TARGET_UNIX } else { return CLREventWaitHelper(m_handle,dwMilliseconds,alertable); diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index d84fd89705df9d..de762d2287fd35 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -6,6 +6,7 @@ // #include "common.h" +#include "RuntimeEvent.h" #include "frames.h" #include "threads.h" @@ -897,7 +898,7 @@ HRESULT Thread::DetachThread(BOOL inTerminationCallback) { // Another thread is using the handle now. // We can not call __SwitchToThread since we can not go back to host. - ClrSleepEx(10, FALSE); + PAL_Sleep(10); } if (m_ThreadHandleForClose == INVALID_HANDLE_VALUE) { @@ -1659,18 +1660,29 @@ BOOL Thread::AllocHandles() WRAPPER_NO_CONTRACT; _ASSERTE(!m_DebugSuspendEvent.IsValid()); +#ifdef TARGET_UNIX + _ASSERTE(!m_ThreadExitedEvent.IsValid()); +#endif // TARGET_UNIX BOOL fOK = TRUE; EX_TRY { // create a manual reset event for getting the thread to a safe point m_DebugSuspendEvent.CreateManualEvent(FALSE); +#ifdef TARGET_UNIX + m_ThreadExitedEvent.CreateManualEvent(FALSE); +#endif // TARGET_UNIX } EX_CATCH { fOK = FALSE; - if (!m_DebugSuspendEvent.IsValid()) { + if (m_DebugSuspendEvent.IsValid()) { m_DebugSuspendEvent.CloseEvent(); } +#ifdef TARGET_UNIX + if (m_ThreadExitedEvent.IsValid()) { + m_ThreadExitedEvent.CloseEvent(); + } +#endif // TARGET_UNIX RethrowTerminalExceptions(); } @@ -2371,6 +2383,13 @@ Thread::~Thread() m_DebugSuspendEvent.CloseEvent(); } +#ifdef TARGET_UNIX + if (m_ThreadExitedEvent.IsValid()) + { + m_ThreadExitedEvent.CloseEvent(); + } +#endif // TARGET_UNIX + if (m_OSContext) delete m_OSContext; @@ -3015,8 +3034,10 @@ DWORD Thread::DoReentrantWaitWithRetry(HANDLE handle, DWORD timeout, WaitMode mo CONTRACTL_END; #ifdef TARGET_UNIX - return WaitForSingleObjectEx(handle, timeout, mode == WaitMode_Alertable); -#else + _ASSERTE(handle == GetThreadHandle()); + handle = GetThreadExitedEvent(); +#endif // TARGET_UNIX + ULONGLONG dwStart = 0, dwEnd; if (timeout != INFINITE) { @@ -3046,7 +3067,6 @@ DWORD Thread::DoReentrantWaitWithRetry(HANDLE handle, DWORD timeout, WaitMode mo dwStart = dwEnd; } } -#endif } @@ -3070,7 +3090,7 @@ DWORD Thread::DoAppropriateAptStateWait(int numWaiters, HANDLE* pHandles, BOOL b } #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT - return WaitForMultipleObjectsEx(numWaiters, pHandles, bWaitAll, timeout, alertable); + return PAL_WaitForMultipleObjectsEx(numWaiters, pHandles, bWaitAll, timeout, alertable); } #ifdef TARGET_WINDOWS diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index ae8f7d32cdfadd..c19270b21c89b9 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -2580,9 +2580,26 @@ class Thread return m_ThreadHandle; } +#if defined(TARGET_UNIX) && !defined(DACCESS_COMPILE) + HANDLE GetThreadExitedEvent() + { + LIMITED_METHOD_CONTRACT; + return m_ThreadExitedEvent.GetOSEvent(); + } + + void SetThreadExited() + { + WRAPPER_NO_CONTRACT; + m_ThreadExitedEvent.Set(); + } +#endif // TARGET_UNIX && !DACCESS_COMPILE + private: // For suspends: CLREvent m_DebugSuspendEvent; +#ifdef TARGET_UNIX + CLREvent m_ThreadExitedEvent; +#endif // TARGET_UNIX void SetThreadHandle(HANDLE h) { diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 0a02c64b97be43..0bf695cea72a59 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -10,6 +10,7 @@ // #include "common.h" +#include "RuntimeEvent.h" #include "threadsuspend.h" @@ -1582,7 +1583,7 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout) } else { - ClrSleepEx(ABORT_POLL_TIMEOUT, FALSE); + PAL_Sleep(ABORT_POLL_TIMEOUT); } @@ -1618,7 +1619,7 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout) } else { - ClrSleepEx(100, FALSE); + PAL_Sleep(100); } } diff --git a/src/coreclr/vm/tieredcompilation.cpp b/src/coreclr/vm/tieredcompilation.cpp index ae74980df00898..281b0f2a4b3299 100644 --- a/src/coreclr/vm/tieredcompilation.cpp +++ b/src/coreclr/vm/tieredcompilation.cpp @@ -8,6 +8,7 @@ #include "common.h" +#include "RuntimeEvent.h" #include "excep.h" #include "log.h" #include "threadsuspend.h" @@ -500,14 +501,14 @@ void TieredCompilationManager::BackgroundWorkerStart() { do { - ClrSleepEx(delayMs, false); + PAL_Sleep(delayMs); } while (!TryDeactivateTieringDelay()); } // Don't want to perform background work as soon as it is scheduled if there is possibly more important work that could // be done. Some operating systems may also give a thread woken by a signal higher priority temporarily, which on a // CPU-limited environment may lead to rejitting a method as soon as it's promoted, effectively in the foreground. - ClrSleepEx(0, false); + PAL_Sleep(0); if (IsTieringDelayActive()) { @@ -827,7 +828,7 @@ bool TieredCompilationManager::DoBackgroundWork( } int64_t beforeSleepTicks = currentTicks; - ClrSleepEx(0, false); + PAL_Sleep(0); currentTicks = minipal_hires_ticks(); diff --git a/src/native/minipal/time.c b/src/native/minipal/time.c index 3f1d7c1259f4a6..12ce769a741237 100644 --- a/src/native/minipal/time.c +++ b/src/native/minipal/time.c @@ -156,7 +156,7 @@ void minipal_microdelay(uint32_t usecs, uint32_t* usecsSinceYield) #if HOST_WINDOWS if (usecs > 1000) { - SleepEx(usecs / 1000, FALSE); + Sleep(usecs / 1000); if (usecsSinceYield) { *usecsSinceYield = 0;