// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // // #ifndef __CLRHOST_H__ #define __CLRHOST_H__ #include "windows.h" // worth to include before mscoree.h so we are guaranteed to pick few definitions #ifdef CreateSemaphore #undef CreateSemaphore #endif #include "mscoree.h" #include "clrinternal.h" #include "switches.h" #include "holder.h" #include "new.hpp" #include "staticcontract.h" #include "predeftlsslot.h" #include "safemath.h" #include "debugreturn.h" #include "yieldprocessornormalized.h" #if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE) #define _DEBUG_IMPL 1 #endif #define BEGIN_PRESERVE_LAST_ERROR \ { \ DWORD __dwLastError = ::GetLastError(); \ DEBUG_ASSURE_NO_RETURN_BEGIN(PRESERVE_LAST_ERROR); \ { #define END_PRESERVE_LAST_ERROR \ } \ DEBUG_ASSURE_NO_RETURN_END(PRESERVE_LAST_ERROR); \ ::SetLastError(__dwLastError); \ } // // TRASH_LASTERROR macro sets bogus last error in debug builds to help find places that fail to save it // #ifdef _DEBUG #define LAST_ERROR_TRASH_VALUE 42424 /* = 0xa5b8 */ #define TRASH_LASTERROR \ SetLastError(LAST_ERROR_TRASH_VALUE) #else // _DEBUG #define TRASH_LASTERROR #endif // _DEBUG IExecutionEngine *GetExecutionEngine(); IEEMemoryManager *GetEEMemoryManager(); LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); LPVOID ClrDebugAlloc (size_t size, LPCSTR pszFile, int iLineNo); HANDLE ClrGetProcessHeap(); HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); BOOL ClrHeapDestroy(HANDLE hHeap); LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes); BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); BOOL ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); HANDLE ClrGetProcessExecutableHeap(); #ifdef FAILPOINTS_ENABLED extern int RFS_HashStack(); #endif void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback); typedef LPVOID* (*CLRFLSGETBLOCK)(); extern CLRFLSGETBLOCK __ClrFlsGetBlock; // Combining getter/setter into a single call inline void ClrFlsIncrementValue(DWORD slot, int increment) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_MODE_ANY; STATIC_CONTRACT_CANNOT_TAKE_LOCK; _ASSERTE(increment != 0); void **block = (*__ClrFlsGetBlock)(); size_t value; if (block != NULL) { value = (size_t) block[slot]; _ASSERTE((increment > 0) || (value + increment < value)); block[slot] = (void *) (value + increment); } else { BEGIN_PRESERVE_LAST_ERROR; IExecutionEngine * pEngine = GetExecutionEngine(); value = (size_t) pEngine->TLS_GetValue(slot); _ASSERTE((increment > 0) || (value + increment < value)); pEngine->TLS_SetValue(slot, (void *) (value + increment)); END_PRESERVE_LAST_ERROR; } } inline void * ClrFlsGetValue (DWORD slot) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_MODE_ANY; STATIC_CONTRACT_CANNOT_TAKE_LOCK; void **block = (*__ClrFlsGetBlock)(); if (block != NULL) { return block[slot]; } else { void * value = GetExecutionEngine()->TLS_GetValue(slot); return value; } } inline BOOL ClrFlsCheckValue(DWORD slot, void ** pValue) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_MODE_ANY; #ifdef _DEBUG *pValue = ULongToPtr(0xcccccccc); #endif //_DEBUG void **block = (*__ClrFlsGetBlock)(); if (block != NULL) { *pValue = block[slot]; return TRUE; } else { BOOL result = GetExecutionEngine()->TLS_CheckValue(slot, pValue); return result; } } inline void ClrFlsSetValue(DWORD slot, void *pData) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_MODE_ANY; STATIC_CONTRACT_CANNOT_TAKE_LOCK; void **block = (*__ClrFlsGetBlock)(); if (block != NULL) { block[slot] = pData; } else { BEGIN_PRESERVE_LAST_ERROR; GetExecutionEngine()->TLS_SetValue(slot, pData); END_PRESERVE_LAST_ERROR; } } #ifndef SELF_NO_HOST LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes); BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem); #endif inline LPVOID ClrAllocInProcessHeap(DWORD dwFlags, S_SIZE_T dwBytes) { STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY; if (dwBytes.IsOverflow()) { return NULL; } #ifndef SELF_NO_HOST return EEHeapAllocInProcessHeap(dwFlags, dwBytes.Value()); #else #undef HeapAlloc #undef GetProcessHeap static HANDLE ProcessHeap = NULL; if (ProcessHeap == NULL) ProcessHeap = GetProcessHeap(); return ::HeapAlloc(ProcessHeap,dwFlags,dwBytes.Value()); #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes) #define GetProcessHeap() Dont_Use_GetProcessHeap() #endif } inline BOOL ClrFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem) { STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY; #ifndef SELF_NO_HOST return EEHeapFreeInProcessHeap(dwFlags, lpMem); #else #undef HeapFree #undef GetProcessHeap static HANDLE ProcessHeap = NULL; if (ProcessHeap == NULL) ProcessHeap = GetProcessHeap(); return (BOOL)(BYTE)::HeapFree(ProcessHeap, dwFlags, lpMem); #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem) #define GetProcessHeap() Dont_Use_GetProcessHeap() #endif } // Critical section support for CLR DLLs other than the the EE. // Include the header defining each Crst type and its corresponding level (relative rank). This is // auto-generated from a tool that takes a high-level description of each Crst type and its dependencies. #include "crsttypes.h" // critical section api CRITSEC_COOKIE ClrCreateCriticalSection(CrstType type, CrstFlags flags); HRESULT ClrDeleteCriticalSection(CRITSEC_COOKIE cookie); void ClrEnterCriticalSection(CRITSEC_COOKIE cookie); void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie); // event api EVENT_COOKIE ClrCreateAutoEvent(BOOL bInitialState); EVENT_COOKIE ClrCreateManualEvent(BOOL bInitialState); void ClrCloseEvent(EVENT_COOKIE event); BOOL ClrSetEvent(EVENT_COOKIE event); BOOL ClrResetEvent(EVENT_COOKIE event); DWORD ClrWaitEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable); // semaphore api SEMAPHORE_COOKIE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax); void ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore); BOOL ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount); DWORD ClrWaitSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable); // mutex api MUTEX_COOKIE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName); void ClrCloseMutex(MUTEX_COOKIE mutex); BOOL ClrReleaseMutex(MUTEX_COOKIE mutex); DWORD ClrWaitForMutex(MUTEX_COOKIE mutex,DWORD dwMilliseconds,BOOL bAlertable); 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. typedef Holder CRITSEC_Holder; // Use this holder to manage CRITSEC_COOKIE allocation to ensure it will be released if anything goes wrong FORCEINLINE void VoidClrDeleteCriticalSection(CRITSEC_COOKIE cs) { if (cs != NULL) ClrDeleteCriticalSection(cs); } typedef Wrapper, VoidClrDeleteCriticalSection, NULL> CRITSEC_AllocationHolder; class Event { public: Event () : m_event(NULL) {STATIC_CONTRACT_LEAF;} ~Event () { STATIC_CONTRACT_WRAPPER; CloseEvent(); } void CreateAutoEvent(BOOL bInitialState) { STATIC_CONTRACT_WRAPPER; m_event = ClrCreateAutoEvent(bInitialState); } void CreateManualEvent(BOOL bInitialState) { STATIC_CONTRACT_WRAPPER; m_event = ClrCreateManualEvent(bInitialState); } void CloseEvent() { STATIC_CONTRACT_WRAPPER; if (m_event != NULL) ClrCloseEvent(m_event); m_event = NULL; } BOOL Set() { STATIC_CONTRACT_WRAPPER; return ClrSetEvent(m_event); } BOOL Reset() { STATIC_CONTRACT_WRAPPER; return ClrResetEvent(m_event); } DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable) { STATIC_CONTRACT_WRAPPER; return ClrWaitEvent(m_event, dwMilliseconds, bAlertable); } private: EVENT_COOKIE m_event; }; class Semaphore { public: Semaphore () : m_semaphore(NULL) {STATIC_CONTRACT_LEAF;} ~Semaphore () { STATIC_CONTRACT_WRAPPER; Close(); } void Create(DWORD dwInitial, DWORD dwMax) { STATIC_CONTRACT_WRAPPER; m_semaphore = ClrCreateSemaphore(dwInitial, dwMax); } void Close() { STATIC_CONTRACT_WRAPPER; if (m_semaphore != NULL) ClrCloseSemaphore(m_semaphore); m_semaphore = NULL; } BOOL Release(LONG lReleaseCount, LONG* lpPreviousCount) { STATIC_CONTRACT_WRAPPER; return ClrReleaseSemaphore(m_semaphore, lReleaseCount, lpPreviousCount); } DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable) { STATIC_CONTRACT_WRAPPER; return ClrWaitSemaphore(m_semaphore, dwMilliseconds, bAlertable); } private: SEMAPHORE_COOKIE m_semaphore; }; HMODULE GetCLRModule (); extern void IncCantAllocCount(); extern void DecCantAllocCount(); class CantAllocHolder { public: CantAllocHolder () { IncCantAllocCount (); } ~CantAllocHolder() { DecCantAllocCount (); } }; // At places where want to allocate stress log, we need to first check if we are allowed to do so. // If ClrTlsInfo doesn't exist for this thread, we take it as can alloc inline bool IsInCantAllocRegion () { size_t count = 0; if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count)) { _ASSERTE (count >= 0); return count > 0; } return false; } // for stress log the rule is more restrict, we have to check the global counter too extern BOOL IsInCantAllocStressLogRegion(); #endif