1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
17 #include "clrinternal.h"
19 #include "predeftlsslot.h"
21 // to avoid to include clrhost.h in this file
22 #ifdef FAILPOINTS_ENABLED
23 extern int RFS_HashStack();
26 static DWORD TlsIndex = TLS_OUT_OF_INDEXES;
27 static PTLS_CALLBACK_FUNCTION Callbacks[MAX_PREDEFINED_TLS_SLOT];
30 HANDLE (*g_fnGetExecutableHeapHandle)();
33 extern LPVOID* (*__ClrFlsGetBlock)();
36 // FLS getter to avoid unnecessary indirection via execution engine.
38 LPVOID* ClrFlsGetBlockDirect()
40 return (LPVOID*)TlsGetValue(TlsIndex);
44 // utility functions for tls functionality
46 static void **CheckThreadState(DWORD slot, BOOL force = TRUE)
48 // Treat as a runtime assertion, since the invariant spans many DLLs.
49 _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
51 // Ensure we have a TLS Index
52 if (TlsIndex == TLS_OUT_OF_INDEXES)
54 DWORD tmp = TlsAlloc();
56 if (InterlockedCompareExchange((LONG*)&TlsIndex, tmp, TLS_OUT_OF_INDEXES) != (LONG) TLS_OUT_OF_INDEXES)
58 // We lost the race with another thread.
62 // Switch to faster TLS getter now that the TLS slot is initialized
63 __ClrFlsGetBlock = ClrFlsGetBlockDirect;
66 _ASSERTE(TlsIndex != TLS_OUT_OF_INDEXES);
68 void **pTlsData = (void **)TlsGetValue(TlsIndex);
70 if (pTlsData == 0 && force) {
72 // !!! Contract uses our TLS support. Contract may be used before our host support is set up.
73 // !!! To better support contract, we call into OS for memory allocation.
74 pTlsData = (void**) ::HeapAlloc(GetProcessHeap(),0,MAX_PREDEFINED_TLS_SLOT*sizeof(void*));
79 // workaround! We don't want exceptions being thrown during ClrInitDebugState. Just return NULL out of TlsSetValue.
80 // ClrInitDebugState will do a confirming FlsGet to see if the value stuck.
82 // If this is for the stack probe, and we failed to allocate memory for it, we won't
83 // put in a guard page.
84 if (slot == TlsIdx_ClrDebugState)
88 RaiseException(STATUS_NO_MEMORY, 0, 0, NULL);
90 for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
92 TlsSetValue(TlsIndex, pTlsData);
98 // This function should only be called during process detatch for
100 VOID STDMETHODCALLTYPE TLS_FreeMasterSlotIndex()
102 if (TlsIndex != TLS_OUT_OF_INDEXES)
103 if (TlsFree(TlsIndex))
104 TlsIndex = TLS_OUT_OF_INDEXES;
105 } // TLS_FreeMasterSlotIndex
109 HRESULT STDMETHODCALLTYPE UtilExecutionEngine::QueryInterface(REFIID id, void **pInterface)
116 if (id == IID_IExecutionEngine)
117 *pInterface = (IExecutionEngine *)this;
118 else if (id == IID_IEEMemoryManager)
119 *pInterface = (IEEMemoryManager *)this;
120 else if (id == IID_IUnknown)
121 *pInterface = (IUnknown *)(IExecutionEngine *)this;
123 return E_NOINTERFACE;
127 } // UtilExecutionEngine::QueryInterface
130 // lifetime of this object is that of the app it lives in so no point in AddRef/Release
132 ULONG STDMETHODCALLTYPE UtilExecutionEngine::AddRef()
137 ULONG STDMETHODCALLTYPE UtilExecutionEngine::Release()
142 VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
144 CheckThreadState(slot);
146 // They can toggle between a callback and no callback. But anything else looks like
147 // confusion on their part.
149 // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But
150 // all the callbacks are equally good.)
151 _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0);
152 Callbacks[slot] = callback;
155 LPVOID* STDMETHODCALLTYPE UtilExecutionEngine::TLS_GetDataBlock()
157 if (TlsIndex == TLS_OUT_OF_INDEXES)
160 return (LPVOID *)TlsGetValue(TlsIndex);
163 LPVOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_GetValue(DWORD slot)
165 void **pTlsData = CheckThreadState(slot, FALSE);
167 return pTlsData[slot];
172 BOOL STDMETHODCALLTYPE UtilExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue)
174 void **pTlsData = CheckThreadState(slot, FALSE);
177 *pValue = pTlsData[slot];
183 VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData)
185 void **pTlsData = CheckThreadState(slot);
186 if (pTlsData) // Yes, CheckThreadState(slot, TRUE) can return NULL now.
188 pTlsData[slot] = pData;
192 VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_ThreadDetaching()
194 void **pTlsData = CheckThreadState(0, FALSE);
197 for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
199 // If we have some data and a callback, issue it.
200 if (Callbacks[i] != 0 && pTlsData[i] != 0)
201 (*Callbacks[i])(pTlsData[i]);
203 ::HeapFree (GetProcessHeap(),0,pTlsData);
208 CRITSEC_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags)
210 CRITICAL_SECTION *cs = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
211 InitializeCriticalSection(cs);
212 return (CRITSEC_COOKIE)cs;
215 void STDMETHODCALLTYPE UtilExecutionEngine::DestroyLock(CRITSEC_COOKIE lock)
218 DeleteCriticalSection((CRITICAL_SECTION*)lock);
222 void STDMETHODCALLTYPE UtilExecutionEngine::AcquireLock(CRITSEC_COOKIE lock)
225 EnterCriticalSection((CRITICAL_SECTION*)lock);
228 void STDMETHODCALLTYPE UtilExecutionEngine::ReleaseLock(CRITSEC_COOKIE lock)
231 LeaveCriticalSection((CRITICAL_SECTION*)lock);
234 EVENT_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateAutoEvent(BOOL bInitialState)
236 HANDLE handle = WszCreateEvent(NULL, FALSE, bInitialState, NULL);
238 return (EVENT_COOKIE)handle;
241 EVENT_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateManualEvent(BOOL bInitialState)
243 HANDLE handle = WszCreateEvent(NULL, TRUE, bInitialState, NULL);
245 return (EVENT_COOKIE)handle;
248 void STDMETHODCALLTYPE UtilExecutionEngine::CloseEvent(EVENT_COOKIE event)
251 CloseHandle((HANDLE)event);
254 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrSetEvent(EVENT_COOKIE event)
257 return SetEvent((HANDLE)event);
260 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrResetEvent(EVENT_COOKIE event)
263 return ResetEvent((HANDLE)event);
266 DWORD STDMETHODCALLTYPE UtilExecutionEngine::WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable)
269 return WaitForSingleObjectEx((HANDLE)event, dwMilliseconds, bAlertable);
272 DWORD STDMETHODCALLTYPE UtilExecutionEngine::WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds)
275 return WaitForSingleObjectEx(handle, dwMilliseconds, FALSE);
278 SEMAPHORE_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax)
280 HANDLE handle = WszCreateSemaphore(NULL, (LONG)dwInitial, (LONG)dwMax, NULL);
282 return (SEMAPHORE_COOKIE)handle;
285 void STDMETHODCALLTYPE UtilExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore)
288 CloseHandle((HANDLE)semaphore);
291 DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable)
294 return WaitForSingleObjectEx((HANDLE)semaphore, dwMilliseconds, bAlertable);
297 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount)
300 return ReleaseSemaphore((HANDLE)semaphore, lReleaseCount, lpPreviousCount);
303 MUTEX_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
307 return (MUTEX_COOKIE)WszCreateMutex(lpMutexAttributes,bInitialOwner,lpName);
310 void STDMETHODCALLTYPE UtilExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex)
313 CloseHandle((HANDLE)mutex);
316 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex)
319 return ReleaseMutex((HANDLE)mutex);
322 DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex,
323 DWORD dwMilliseconds,
327 return WaitForSingleObjectEx ((HANDLE)mutex, dwMilliseconds, bAlertable);
330 DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable)
332 return SleepEx (dwMilliseconds, bAlertable);
335 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrAllocationDisallowed()
340 LPVOID STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
342 #ifdef FAILPOINTS_ENABLED
343 if (RFS_HashStack ())
346 return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
349 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
351 return VirtualFree(lpAddress, dwSize, dwFreeType);
354 SIZE_T STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
356 return VirtualQuery(lpAddress, lpBuffer, dwLength);
359 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
361 return VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
364 HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrGetProcessHeap()
366 return GetProcessHeap();
369 HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrGetProcessExecutableHeap()
371 #ifndef CROSSGEN_COMPILE
372 _ASSERTE(g_fnGetExecutableHeapHandle);
373 return (g_fnGetExecutableHeapHandle != NULL) ? g_fnGetExecutableHeapHandle() : NULL;
375 return GetProcessHeap();
379 HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize)
384 return HeapCreate(flOptions, dwInitialSize, dwMaximumSize);
388 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapDestroy(HANDLE hHeap)
393 return HeapDestroy(hHeap);
397 LPVOID STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
399 #ifdef FAILPOINTS_ENABLED
400 if (RFS_HashStack ())
403 return HeapAlloc(hHeap, dwFlags, dwBytes);
406 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
408 return HeapFree(hHeap, dwFlags, lpMem);
411 BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
416 return HeapValidate(hHeap, dwFlags, lpMem);
421 //------------------------------------------------------------------------------
422 // Helper function to get an exception from outside the exception. In
423 // the CLR, it may be from the Thread object. Non-CLR users have no thread object,
424 // and it will do nothing.
426 void UtilExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException)
428 // Declare class so we can declare Exception**
431 // Cast to our real type.
432 Exception **ppException = reinterpret_cast<Exception**>(ppvException);
435 } // UtilExecutionEngine::GetLastThrownObjectExceptionFromThread