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