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.
4
5// ==++==
6//
7
8//
9//
10
11//
12// ==--==
13
14#include "stdafx.h"
15
16#include "mscoree.h"
17#include "clrinternal.h"
18#include "hostimpl.h"
19#include "predeftlsslot.h"
20#include "unsafe.h"
21
22// to avoid to include clrhost.h in this file
23#ifdef FAILPOINTS_ENABLED
24extern int RFS_HashStack();
25#endif
26
27static DWORD TlsIndex = TLS_OUT_OF_INDEXES;
28static PTLS_CALLBACK_FUNCTION Callbacks[MAX_PREDEFINED_TLS_SLOT];
29
30#ifdef SELF_NO_HOST
31HANDLE (*g_fnGetExecutableHeapHandle)();
32#endif
33
34extern LPVOID* (*__ClrFlsGetBlock)();
35
36//
37// FLS getter to avoid unnecessary indirection via execution engine.
38//
39LPVOID* ClrFlsGetBlockDirect()
40{
41 return (LPVOID*)UnsafeTlsGetValue(TlsIndex);
42}
43
44//
45// utility functions for tls functionality
46//
47static void **CheckThreadState(DWORD slot, BOOL force = TRUE)
48{
49 // Treat as a runtime assertion, since the invariant spans many DLLs.
50 _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
51
52 // Ensure we have a TLS Index
53 if (TlsIndex == TLS_OUT_OF_INDEXES)
54 {
55 DWORD tmp = UnsafeTlsAlloc();
56
57 if (InterlockedCompareExchange((LONG*)&TlsIndex, tmp, TLS_OUT_OF_INDEXES) != (LONG) TLS_OUT_OF_INDEXES)
58 {
59 // We lost the race with another thread.
60 UnsafeTlsFree(tmp);
61 }
62
63 // Switch to faster TLS getter now that the TLS slot is initialized
64 __ClrFlsGetBlock = ClrFlsGetBlockDirect;
65 }
66
67 _ASSERTE(TlsIndex != TLS_OUT_OF_INDEXES);
68
69 void **pTlsData = (void **)TlsGetValue(TlsIndex);
70
71 if (pTlsData == 0 && force) {
72
73 // !!! Contract uses our TLS support. Contract may be used before our host support is set up.
74 // !!! To better support contract, we call into OS for memory allocation.
75 pTlsData = (void**) ::HeapAlloc(GetProcessHeap(),0,MAX_PREDEFINED_TLS_SLOT*sizeof(void*));
76
77
78 if (pTlsData == NULL)
79 {
80 // workaround! We don't want exceptions being thrown during ClrInitDebugState. Just return NULL out of TlsSetValue.
81 // ClrInitDebugState will do a confirming FlsGet to see if the value stuck.
82
83 // If this is for the stack probe, and we failed to allocate memory for it, we won't
84 // put in a guard page.
85 if (slot == TlsIdx_ClrDebugState || slot == TlsIdx_StackProbe)
86 {
87 return NULL;
88 }
89 RaiseException(STATUS_NO_MEMORY, 0, 0, NULL);
90 }
91 for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
92 pTlsData[i] = 0;
93 UnsafeTlsSetValue(TlsIndex, pTlsData);
94 }
95
96 return pTlsData;
97} // CheckThreadState
98
99// This function should only be called during process detatch for
100// mscoree.dll.
101VOID STDMETHODCALLTYPE TLS_FreeMasterSlotIndex()
102{
103 if (TlsIndex != TLS_OUT_OF_INDEXES)
104 if (UnsafeTlsFree(TlsIndex))
105 TlsIndex = TLS_OUT_OF_INDEXES;
106} // TLS_FreeMasterSlotIndex
107
108
109
110HRESULT STDMETHODCALLTYPE UtilExecutionEngine::QueryInterface(REFIID id, void **pInterface)
111{
112 if (!pInterface)
113 return E_POINTER;
114
115 *pInterface = NULL;
116
117 if (id == IID_IExecutionEngine)
118 *pInterface = (IExecutionEngine *)this;
119 else if (id == IID_IEEMemoryManager)
120 *pInterface = (IEEMemoryManager *)this;
121 else if (id == IID_IUnknown)
122 *pInterface = (IUnknown *)(IExecutionEngine *)this;
123 else
124 return E_NOINTERFACE;
125
126 AddRef();
127 return S_OK;
128} // UtilExecutionEngine::QueryInterface
129
130//
131// lifetime of this object is that of the app it lives in so no point in AddRef/Release
132//
133ULONG STDMETHODCALLTYPE UtilExecutionEngine::AddRef()
134{
135 return 1;
136}
137
138ULONG STDMETHODCALLTYPE UtilExecutionEngine::Release()
139{
140 return 1;
141}
142
143VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
144{
145 CheckThreadState(slot);
146
147 // They can toggle between a callback and no callback. But anything else looks like
148 // confusion on their part.
149 //
150 // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But
151 // all the callbacks are equally good.)
152 _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0);
153 Callbacks[slot] = callback;
154}
155
156LPVOID* STDMETHODCALLTYPE UtilExecutionEngine::TLS_GetDataBlock()
157{
158 if (TlsIndex == TLS_OUT_OF_INDEXES)
159 return NULL;
160
161 return (LPVOID *)UnsafeTlsGetValue(TlsIndex);
162}
163
164LPVOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_GetValue(DWORD slot)
165{
166 void **pTlsData = CheckThreadState(slot, FALSE);
167 if (pTlsData)
168 return pTlsData[slot];
169 else
170 return NULL;
171}
172
173BOOL STDMETHODCALLTYPE UtilExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue)
174{
175 void **pTlsData = CheckThreadState(slot, FALSE);
176 if (pTlsData)
177 {
178 *pValue = pTlsData[slot];
179 return TRUE;
180 }
181 return FALSE;
182}
183
184VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData)
185{
186 void **pTlsData = CheckThreadState(slot);
187 if (pTlsData) // Yes, CheckThreadState(slot, TRUE) can return NULL now.
188 {
189 pTlsData[slot] = pData;
190 }
191}
192
193VOID STDMETHODCALLTYPE UtilExecutionEngine::TLS_ThreadDetaching()
194{
195 void **pTlsData = CheckThreadState(0, FALSE);
196 if (pTlsData)
197 {
198 for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
199 {
200 // If we have some data and a callback, issue it.
201 if (Callbacks[i] != 0 && pTlsData[i] != 0)
202 (*Callbacks[i])(pTlsData[i]);
203 }
204 ::HeapFree (GetProcessHeap(),0,pTlsData);
205
206 }
207}
208
209CRITSEC_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags)
210{
211 CRITICAL_SECTION *cs = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
212 UnsafeInitializeCriticalSection(cs);
213 return (CRITSEC_COOKIE)cs;
214}
215
216void STDMETHODCALLTYPE UtilExecutionEngine::DestroyLock(CRITSEC_COOKIE lock)
217{
218 _ASSERTE(lock);
219 UnsafeDeleteCriticalSection((CRITICAL_SECTION*)lock);
220 free(lock);
221}
222
223void STDMETHODCALLTYPE UtilExecutionEngine::AcquireLock(CRITSEC_COOKIE lock)
224{
225 _ASSERTE(lock);
226 UnsafeEnterCriticalSection((CRITICAL_SECTION*)lock);
227}
228
229void STDMETHODCALLTYPE UtilExecutionEngine::ReleaseLock(CRITSEC_COOKIE lock)
230{
231 _ASSERTE(lock);
232 UnsafeLeaveCriticalSection((CRITICAL_SECTION*)lock);
233}
234
235EVENT_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateAutoEvent(BOOL bInitialState)
236{
237 HANDLE handle = UnsafeCreateEvent(NULL, FALSE, bInitialState, NULL);
238 _ASSERTE(handle);
239 return (EVENT_COOKIE)handle;
240}
241
242EVENT_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::CreateManualEvent(BOOL bInitialState)
243{
244 HANDLE handle = UnsafeCreateEvent(NULL, TRUE, bInitialState, NULL);
245 _ASSERTE(handle);
246 return (EVENT_COOKIE)handle;
247}
248
249void STDMETHODCALLTYPE UtilExecutionEngine::CloseEvent(EVENT_COOKIE event)
250{
251 _ASSERTE(event);
252 CloseHandle((HANDLE)event);
253}
254
255BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrSetEvent(EVENT_COOKIE event)
256{
257 _ASSERTE(event);
258 return UnsafeSetEvent((HANDLE)event);
259}
260
261BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrResetEvent(EVENT_COOKIE event)
262{
263 _ASSERTE(event);
264 return UnsafeResetEvent((HANDLE)event);
265}
266
267DWORD STDMETHODCALLTYPE UtilExecutionEngine::WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable)
268{
269 _ASSERTE(event);
270 return WaitForSingleObjectEx((HANDLE)event, dwMilliseconds, bAlertable);
271}
272
273DWORD STDMETHODCALLTYPE UtilExecutionEngine::WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds)
274{
275 _ASSERTE(handle);
276 return WaitForSingleObjectEx(handle, dwMilliseconds, FALSE);
277}
278
279SEMAPHORE_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax)
280{
281 HANDLE handle = UnsafeCreateSemaphore(NULL, (LONG)dwInitial, (LONG)dwMax, NULL);
282 _ASSERTE(handle);
283 return (SEMAPHORE_COOKIE)handle;
284}
285
286void STDMETHODCALLTYPE UtilExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore)
287{
288 _ASSERTE(semaphore);
289 CloseHandle((HANDLE)semaphore);
290}
291
292DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable)
293{
294 _ASSERTE(semaphore);
295 return WaitForSingleObjectEx((HANDLE)semaphore, dwMilliseconds, bAlertable);
296}
297
298BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount)
299{
300 _ASSERTE(semaphore);
301 return UnsafeReleaseSemaphore((HANDLE)semaphore, lReleaseCount, lpPreviousCount);
302}
303
304MUTEX_COOKIE STDMETHODCALLTYPE UtilExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
305 BOOL bInitialOwner,
306 LPCTSTR lpName)
307{
308 return (MUTEX_COOKIE)WszCreateMutex(lpMutexAttributes,bInitialOwner,lpName);
309}
310
311void STDMETHODCALLTYPE UtilExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex)
312{
313 _ASSERTE(mutex);
314 CloseHandle((HANDLE)mutex);
315}
316
317BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex)
318{
319 _ASSERTE(mutex);
320 return ReleaseMutex((HANDLE)mutex);
321}
322
323DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex,
324 DWORD dwMilliseconds,
325 BOOL bAlertable)
326{
327 _ASSERTE(mutex);
328 return WaitForSingleObjectEx ((HANDLE)mutex, dwMilliseconds, bAlertable);
329}
330
331DWORD STDMETHODCALLTYPE UtilExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable)
332{
333 return SleepEx (dwMilliseconds, bAlertable);
334}
335
336BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrAllocationDisallowed()
337{
338 return FALSE;
339}
340
341LPVOID STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
342{
343#ifdef FAILPOINTS_ENABLED
344 if (RFS_HashStack ())
345 return NULL;
346#endif
347 return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
348}
349
350BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
351{
352 return VirtualFree(lpAddress, dwSize, dwFreeType);
353}
354
355SIZE_T STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
356{
357 return VirtualQuery(lpAddress, lpBuffer, dwLength);
358}
359
360BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
361{
362 return VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
363}
364
365HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrGetProcessHeap()
366{
367 return GetProcessHeap();
368}
369
370HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrGetProcessExecutableHeap()
371{
372#ifndef CROSSGEN_COMPILE
373 _ASSERTE(g_fnGetExecutableHeapHandle);
374 return (g_fnGetExecutableHeapHandle != NULL) ? g_fnGetExecutableHeapHandle() : NULL;
375#else
376 return GetProcessHeap();
377#endif
378}
379
380HANDLE STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize)
381{
382#ifdef FEATURE_PAL
383 return NULL;
384#else
385 return HeapCreate(flOptions, dwInitialSize, dwMaximumSize);
386#endif
387}
388
389BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapDestroy(HANDLE hHeap)
390{
391#ifdef FEATURE_PAL
392 return FALSE;
393#else
394 return HeapDestroy(hHeap);
395#endif
396}
397
398LPVOID STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes)
399{
400#ifdef FAILPOINTS_ENABLED
401 if (RFS_HashStack ())
402 return NULL;
403#endif
404 return HeapAlloc(hHeap, dwFlags, dwBytes);
405}
406
407BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
408{
409 return HeapFree(hHeap, dwFlags, lpMem);
410}
411
412BOOL STDMETHODCALLTYPE UtilExecutionEngine::ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
413{
414#ifdef FEATURE_PAL
415 return FALSE;
416#else
417 return HeapValidate(hHeap, dwFlags, lpMem);
418#endif
419}
420
421
422//------------------------------------------------------------------------------
423// Helper function to get an exception from outside the exception. In
424// the CLR, it may be from the Thread object. Non-CLR users have no thread object,
425// and it will do nothing.
426
427void UtilExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException)
428{
429 // Declare class so we can declare Exception**
430 class Exception;
431
432 // Cast to our real type.
433 Exception **ppException = reinterpret_cast<Exception**>(ppvException);
434
435 *ppException = NULL;
436} // UtilExecutionEngine::GetLastThrownObjectExceptionFromThread
437
438