WAIT_NOTINDEADLOCK = 0x4
}WAIT_OPTION;
-typedef enum ETaskType
-{
- TT_DEBUGGERHELPER = 0x1,
- TT_GC = 0x2,
- TT_FINALIZER = 0x4,
- TT_THREADPOOL_TIMER = 0x8,
- TT_THREADPOOL_GATE = 0x10,
- TT_THREADPOOL_WORKER = 0x20,
- TT_THREADPOOL_IOCOMPLETION = 0x40,
- TT_ADUNLOAD = 0x80,
- TT_USER = 0x100,
- TT_THREADPOOL_WAIT = 0x200,
-
- TT_UNKNOWN = 0x80000000,
-} ETaskType;
-
typedef enum {
// Default to minidump
DUMP_FLAVOR_Mini = 0,
size_t m_dwTotalAlloc;
- size_t * m_pPrivatePerfCounter_LoaderBytes;
-
DWORD m_Options;
LoaderHeapFreeBlock *m_pFirstFreeBlock;
DWORD dwCommitBlockSize,
const BYTE* dwReservedRegionAddress,
SIZE_T dwReservedRegionSize,
- size_t *pPrivatePerfCounter_LoaderBytes = NULL,
RangeList *pRangeList = NULL,
BOOL fMakeExecutable = FALSE);
public:
LoaderHeap(DWORD dwReserveBlockSize,
DWORD dwCommitBlockSize,
- size_t *pPrivatePerfCounter_LoaderBytes = NULL,
RangeList *pRangeList = NULL,
BOOL fMakeExecutable = FALSE
)
: UnlockedLoaderHeap(dwReserveBlockSize,
dwCommitBlockSize,
NULL, 0,
- pPrivatePerfCounter_LoaderBytes,
pRangeList,
fMakeExecutable)
{
DWORD dwCommitBlockSize,
const BYTE* dwReservedRegionAddress,
SIZE_T dwReservedRegionSize,
- size_t *pPrivatePerfCounter_LoaderBytes = NULL,
RangeList *pRangeList = NULL,
BOOL fMakeExecutable = FALSE
)
dwCommitBlockSize,
dwReservedRegionAddress,
dwReservedRegionSize,
- pPrivatePerfCounter_LoaderBytes,
pRangeList,
fMakeExecutable)
{
{
#ifndef DACCESS_COMPILE
public:
- ExplicitControlLoaderHeap(size_t *pPrivatePerfCounter_LoaderBytes = NULL,
- RangeList *pRangeList = NULL,
+ ExplicitControlLoaderHeap(RangeList *pRangeList = NULL,
BOOL fMakeExecutable = FALSE
)
: UnlockedLoaderHeap(0, 0, NULL, 0,
- pPrivatePerfCounter_LoaderBytes,
pRangeList,
fMakeExecutable)
{
WAIT_NOTINDEADLOCK = 0x4
} WAIT_OPTION;
-typedef
-enum ETaskType
- {
- TT_DEBUGGERHELPER = 0x1,
- TT_GC = 0x2,
- TT_FINALIZER = 0x4,
- TT_THREADPOOL_TIMER = 0x8,
- TT_THREADPOOL_GATE = 0x10,
- TT_THREADPOOL_WORKER = 0x20,
- TT_THREADPOOL_IOCOMPLETION = 0x40,
- TT_ADUNLOAD = 0x80,
- TT_USER = 0x100,
- TT_THREADPOOL_WAIT = 0x200,
- TT_UNKNOWN = 0x80000000
- } ETaskType;
-
typedef /* [public] */
enum __MIDL___MIDL_itf_mscoree_0000_0000_0004
{
DWORD dwCommitBlockSize,
const BYTE* dwReservedRegionAddress,
SIZE_T dwReservedRegionSize,
- size_t *pPrivatePerfCounter_LoaderBytes,
RangeList *pRangeList,
BOOL fMakeExecutable)
{
m_fStubUnwindInfoUnregistered= FALSE;
#endif
- m_pPrivatePerfCounter_LoaderBytes = pPrivatePerfCounter_LoaderBytes;
-
m_Options = 0;
#ifndef CROSSGEN_COMPILE
_ASSERTE(fSuccess);
}
- if (m_pPrivatePerfCounter_LoaderBytes)
- *m_pPrivatePerfCounter_LoaderBytes = *m_pPrivatePerfCounter_LoaderBytes - (DWORD) m_dwTotalAlloc;
-
INDEBUG(s_dwNumInstancesOfLoaderHeaps --;)
}
return FALSE;
}
- if (m_pPrivatePerfCounter_LoaderBytes)
- *m_pPrivatePerfCounter_LoaderBytes = *m_pPrivatePerfCounter_LoaderBytes + (DWORD) dwSizeToCommit;
-
// Record reserved range in range list, if one is specified
// Do this AFTER the commit - otherwise we'll have bogus ranges included.
if (m_pRangeList != NULL)
if (pData == NULL)
return FALSE;
- if (m_pPrivatePerfCounter_LoaderBytes)
- *m_pPrivatePerfCounter_LoaderBytes = *m_pPrivatePerfCounter_LoaderBytes + (DWORD) dwSizeToCommit;
-
m_dwTotalAlloc += dwSizeToCommit;
m_pPtrToEndOfCommittedRegion += dwSizeToCommit;
MAKE_CURRENT_THREAD_AVAILABLE(); \
DECLARE_CPFH_EH_RECORD(CURRENT_THREAD); \
_ASSERTE(CURRENT_THREAD); \
- _ASSERTE(!CURRENT_THREAD->IsAbortPrevented() || \
- CURRENT_THREAD->IsAbortCheckDisabled()); \
_ASSERTE((CURRENT_THREAD->m_StateNC & Thread::TSNC_OwnsSpinLock) == 0); \
/* This bit should never be set when we call into managed code. The */ \
/* stack walking code explicitly clears this around any potential calls */ \
}
CONTRACT_END
- if (!m_pThunkHeap)
- {
- size_t * pPrivatePCLBytes = NULL;
- size_t * pGlobalPCLBytes = NULL;
-
- LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize
- 0, // DWORD dwCommitBlockSize
- pPrivatePCLBytes,
- ThunkHeapStubManager::g_pManager->GetRangeList(),
- TRUE); // BOOL fMakeExecutable
+ if (!m_pThunkHeap)
+ {
+ LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize
+ 0, // DWORD dwCommitBlockSize
+ ThunkHeapStubManager::g_pManager->GetRangeList(),
+ TRUE); // BOOL fMakeExecutable
- if (FastInterlockCompareExchangePointer(&m_pThunkHeap, pNewHeap, 0) != 0)
- {
- delete pNewHeap;
- }
+ if (FastInterlockCompareExchangePointer(&m_pThunkHeap, pNewHeap, 0) != 0)
+ {
+ delete pNewHeap;
}
+ }
RETURN m_pThunkHeap;
}
_ASSERTE(!"EE Shutting down after an assert");
#endif
-
-#ifdef LOGGING
- extern unsigned FcallTimeHist[11];
-#endif
- LOG((LF_STUBS, LL_INFO10, "FcallHist %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
- FcallTimeHist[0], FcallTimeHist[1], FcallTimeHist[2], FcallTimeHist[3],
- FcallTimeHist[4], FcallTimeHist[5], FcallTimeHist[6], FcallTimeHist[7],
- FcallTimeHist[8], FcallTimeHist[9], FcallTimeHist[10]));
-
WriteJitHelperCountToSTRESSLOG();
STRESS_LOG0(LF_STARTUP, LL_INFO10, "EEShutdown shutting down logging");
//**************************************************************************
-LoaderCodeHeap::LoaderCodeHeap(size_t * pPrivatePCLBytes)
- : m_LoaderHeap(pPrivatePCLBytes,
- 0, // RangeList *pRangeList
+LoaderCodeHeap::LoaderCodeHeap()
+ : m_LoaderHeap(NULL, // RangeList *pRangeList
TRUE), // BOOL fMakeExecutable
m_cbMinNextPad(0)
{
POSTCONDITION((RETVAL != NULL) || !pInfo->getThrowOnOutOfMemoryWithinRange());
} CONTRACT_END;
- size_t * pPrivatePCLBytes = NULL;
size_t reserveSize = pInfo->getReserveSize();
size_t initialRequestSize = pInfo->getRequestSize();
const BYTE * loAddr = pInfo->m_loAddr;
EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
}
-#ifdef ENABLE_PERF_COUNTERS
- pPrivatePCLBytes = &(GetPerfCounters().m_Loading.cbLoaderHeapSize);
-#endif
-
LOG((LF_JIT, LL_INFO100,
"Request new LoaderCodeHeap::CreateCodeHeap(%08x, %08x, for loader allocator" FMT_ADDR "in" FMT_ADDR ".." FMT_ADDR ")\n",
(DWORD) reserveSize, (DWORD) initialRequestSize, DBG_ADDR(pInfo->m_pAllocator), DBG_ADDR(loAddr), DBG_ADDR(hiAddr)
));
- NewHolder<LoaderCodeHeap> pCodeHeap(new LoaderCodeHeap(pPrivatePCLBytes));
+ NewHolder<LoaderCodeHeap> pCodeHeap(new LoaderCodeHeap());
BYTE * pBaseAddr = NULL;
DWORD dwSizeAcquiredFromInitialBlock = 0;
ExplicitControlLoaderHeap m_LoaderHeap;
SSIZE_T m_cbMinNextPad;
- LoaderCodeHeap(size_t * pPrivatePCLBytes);
+ LoaderCodeHeap();
public:
static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap);
bool needReset =
priority != ThreadNative::PRIORITY_NORMAL ||
- pThread->HasThreadStateNC(Thread::TSNC_SOWorkNeeded) ||
!pThread->IsBackground();
bool shouldAdjustWorkers = ThreadpoolMgr::ShouldAdjustMaxWorkersActive();
return (hr);
}
-
-//-----------------------------------------------------------------------------
-// MapFile - Maps a file into the runtime in a non-standard way
-//-----------------------------------------------------------------------------
-
-static PEImage *MapFileHelper(HANDLE hFile)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- GCX_PREEMP();
-
- HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
- if (hFileMap == NULL)
- ThrowLastError();
-
- CLRMapViewHolder base(CLRMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0));
- if (base == NULL)
- ThrowLastError();
-
- DWORD dwSize = SafeGetFileSize(hFile, NULL);
- if (dwSize == 0xffffffff && GetLastError() != NOERROR)
- {
- ThrowLastError();
- }
- PEImageHolder pImage(PEImage::LoadFlat(base, dwSize));
- return pImage.Extract();
-}
-
LONG CorHost2::m_RefCount = 0;
-static Volatile<BOOL> fOneOnly = 0;
-
///////////////////////////////////////////////////////////////////////////////
// ICLRRuntimeHost::SetHostControl
///////////////////////////////////////////////////////////////////////////////
return E_NOTIMPL;
}
-void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- pMSEX->dwLength = sizeof(MEMORYSTATUSEX);
- BOOL fRet = GlobalMemoryStatusEx(pMSEX);
- _ASSERTE (fRet);
-}
-
// This is the instance that exposes interfaces out to all the other DLLs of the CLR
// so they can use our services for TLS, synchronization, memory allocation, etc.
static BYTE g_CEEInstance[sizeof(CExecutionEngine)];
}
CONTRACTL_END;
- Thread::LoadingFileHolder holder(GetThread());
- GetThread()->SetLoadingFile(this);
GetFile()->LoadLibrary();
}
// Doing rude abort. Skip all non-constrained execution region code.
// When rude abort is initiated, we cannot intercept any exceptions.
- if ((pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pcfThisFrame)))
+ if (pThread->IsRudeAbortInitiated())
{
// If we are unwinding to find the real resume frame, then we cannot ignore frames yet.
// We need to make sure we find the correct resume frame before starting to ignore frames.
pThread->m_dwIndexClauseForCatch = dwPreFilterTACatchHandlerClauseIndex;
pThread->m_sfEstablisherOfActualHandlerFrame = sfPreFilterEstablisherOfActualHandlerFrame;
- if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pcfThisFrame))
+ if (pThread->IsRudeAbortInitiated())
{
EH_LOG((LL_INFO100, " IGNOREFRAME: rude abort\n"));
goto lExit;
}
}
-void ThreadExceptionState::ClearThrowablesForUnload(IGCHandleStore* handleStore)
-{
- WRAPPER_NO_CONTRACT;
-
-#ifdef FEATURE_EH_FUNCLETS
- ExceptionTracker* pNode = m_pCurrentTracker;
-#else // FEATURE_EH_FUNCLETS
- ExInfo* pNode = &m_currentExInfo;
-#endif // FEATURE_EH_FUNCLETS
-
- for ( ;
- pNode != NULL;
- pNode = pNode->m_pPrevNestedInfo)
- {
- if (handleStore->ContainsHandle(pNode->m_hThrowable))
- {
- pNode->DestroyExceptionHandle();
- }
- }
-}
-
-
-// After unwinding from an SO, there may be stale exception state.
-void ThreadExceptionState::ClearExceptionStateAfterSO(void* pStackFrameSP)
-{
- WRAPPER_NO_CONTRACT;
-
- #if defined(FEATURE_EH_FUNCLETS)
- ExceptionTracker::PopTrackers(pStackFrameSP);
- #else
- // After unwinding from an SO, there may be stale exception state. We need to
- // get rid of any state that assumes the handlers that have been unwound/unlinked.
- //
- // Because the ExState chains to entries that may be on the stack, and the
- // stack has been unwound, it may not be safe to reference any entries
- // other than the one of the Thread object.
- //
- // Consequently, we will simply Init() the ExInfo on the Thread object.
- m_currentExInfo.Init();
- #endif
-} // void ThreadExceptionState::ClearExceptionStateAfterSO()
-
OBJECTREF ThreadExceptionState::GetThrowable()
{
CONTRACTL
public:
void FreeAllStackTraces();
- void ClearThrowablesForUnload(IGCHandleStore* handleStore);
#ifdef _DEBUG
typedef enum
void EnumChainMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif // DACCESS_COMPILE
- // After unwinding from an SO, there may be stale exception state.
- void ClearExceptionStateAfterSO(void* pStackFrameSP);
-
enum ThreadExceptionFlag
{
TEF_None = 0x00000000,
return objToProtect;
}
-#ifdef _DEBUG
-
-unsigned FcallTimeHist[11];
-
-#endif
-
#ifdef ENABLE_CONTRACTS
/**************************************************************************************/
#endif // FEATURE_PAL
+static void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ pMSEX->dwLength = sizeof(MEMORYSTATUSEX);
+ BOOL fRet = GlobalMemoryStatusEx(pMSEX);
+ _ASSERTE(fRet);
+}
+
// Initialize the interface implementation
// Return:
// true if it has succeeded, false if it has failed
LIMITED_METHOD_CONTRACT;
MEMORYSTATUSEX memStatus;
- ::GetProcessMemoryLoad(&memStatus);
+ GetProcessMemoryLoad(&memStatus);
return (size_t)memStatus.ullTotalVirtual;
}
job_physical_memory_limit = min (job_physical_memory_limit, job_workingset_limit);
MEMORYSTATUSEX ms;
- ::GetProcessMemoryLoad(&ms);
+ GetProcessMemoryLoad(&ms);
total_virtual = ms.ullTotalVirtual;
total_physical = ms.ullAvailPhys;
if (total_virtual == 0)
{
MEMORYSTATUSEX ms;
- ::GetProcessMemoryLoad(&ms);
+ GetProcessMemoryLoad(&ms);
total_virtual = ms.ullTotalVirtual;
total_physical = ms.ullTotalPhys;
}
#endif // FEATURE_PAL
-
// Get the physical memory that this process can use.
// Return:
// non zero if it has succeeded, 0 if it has failed
}
MEMORYSTATUSEX memStatus;
- ::GetProcessMemoryLoad(&memStatus);
+ GetProcessMemoryLoad(&memStatus);
return memStatus.ullTotalPhys;
}
}
MEMORYSTATUSEX ms;
- ::GetProcessMemoryLoad(&ms);
+ GetProcessMemoryLoad(&ms);
#ifndef FEATURE_PAL
if (g_UseRestrictedVirtualMemory)
if (!pFunc)
return SWA_CONTINUE;
- if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pCf))
+ if (pThread->IsRudeAbortInitiated())
{
return SWA_CONTINUE;
}
pExInfo->m_EHClauseInfo.ResetInfo();
- if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pCf))
+ if (pThread->IsRudeAbortInitiated())
{
if (fGiveDebuggerAndProfilerNotification)
EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pFunc);
Thread *pThread = GetThread();
// If the thread is being RudeAbort, we will not run any finally
- if (pThread->IsRudeAbortInitiated() && !pThread->IsWithinCer(pCf))
+ if (pThread->IsRudeAbortInitiated())
{
return SWA_CONTINUE;
}
#endif
#include "comcallablewrapper.h"
-//*****************************************************************************
-// Used by LoaderAllocator::Init for easier readability.
-#ifdef ENABLE_PERF_COUNTERS
-#define LOADERHEAP_PROFILE_COUNTER (&(GetPerfCounters().m_Loading.cbLoaderHeapSize))
-#else
-#define LOADERHEAP_PROFILE_COUNTER (NULL)
-#endif
-
#ifndef CROSSGEN_COMPILE
#define STUBMANAGER_RANGELIST(stubManager) (stubManager::g_pManager->GetRangeList())
#else
m_pLowFrequencyHeap = new (&m_LowFreqHeapInstance) LoaderHeap(LOW_FREQUENCY_HEAP_RESERVE_SIZE,
LOW_FREQUENCY_HEAP_COMMIT_SIZE,
initReservedMem,
- dwLowFrequencyHeapReserveSize,
- LOADERHEAP_PROFILE_COUNTER);
+ dwLowFrequencyHeapReserveSize);
initReservedMem += dwLowFrequencyHeapReserveSize;
}
STUB_HEAP_COMMIT_SIZE,
initReservedMem,
dwExecutableHeapReserveSize,
- LOADERHEAP_PROFILE_COUNTER,
NULL,
TRUE /* Make heap executable */
);
m_pHighFrequencyHeap = new (&m_HighFreqHeapInstance) LoaderHeap(HIGH_FREQUENCY_HEAP_RESERVE_SIZE,
HIGH_FREQUENCY_HEAP_COMMIT_SIZE,
initReservedMem,
- dwHighFrequencyHeapReserveSize,
- LOADERHEAP_PROFILE_COUNTER);
+ dwHighFrequencyHeapReserveSize);
initReservedMem += dwHighFrequencyHeapReserveSize;
if (IsCollectible())
STUB_HEAP_COMMIT_SIZE,
initReservedMem,
dwStubHeapReserveSize,
- LOADERHEAP_PROFILE_COUNTER,
STUBMANAGER_RANGELIST(StubLinkStubManager),
TRUE /* Make heap executable */);
}
CONTRACT_END
- if (!m_DllThunkHeap)
- {
- size_t * pPrivatePCLBytes = NULL;
- size_t * pGlobalPCLBytes = NULL;
-
- LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize
- 0, // DWORD dwCommitBlockSize
- pPrivatePCLBytes,
- ThunkHeapStubManager::g_pManager->GetRangeList(),
- TRUE); // BOOL fMakeExecutable
+ if (!m_DllThunkHeap)
+ {
+ LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize
+ 0, // DWORD dwCommitBlockSize
+ ThunkHeapStubManager::g_pManager->GetRangeList(),
+ TRUE); // BOOL fMakeExecutable
- if (FastInterlockCompareExchangePointer((PVOID*)&m_DllThunkHeap, (VOID*)pNewHeap, (VOID*)0) != 0)
- {
- delete pNewHeap;
- }
+ if (FastInterlockCompareExchangePointer((PVOID*)&m_DllThunkHeap, (VOID*)pNewHeap, (VOID*)0) != 0)
+ {
+ delete pNewHeap;
}
+ }
RETURN m_DllThunkHeap;
}
LONG Thread::m_DebugWillSyncCount = -1;
LONG Thread::m_DetachCount = 0;
LONG Thread::m_ActiveDetachCount = 0;
-int Thread::m_offset_counter = 0;
-Volatile<LONG> Thread::m_threadsAtUnsafePlaces = 0;
//-------------------------------------------------------------------------
// Public function: SetupThreadNoThrow()
_ASSERTE(g_fEEShutDown || th->m_dwLockCount == 0 || th->m_fRudeAborted);
- th->FinishSOWork();
-
GCX_PREEMP_NO_DTOR();
if (th->IsAbortRequested()) {
_ASSERTE (this == GetThread());
- FinishSOWork();
-
FastInterlockIncrement(&Thread::m_DetachCount);
if (IsAbortRequested()) {
m_RequestedStackSize = 0;
m_PreventAsync = 0;
- m_PreventAbort = 0;
- m_nNestedMarshalingExceptions = 0;
m_pDomain = NULL;
#ifdef FEATURE_COMINTEROP
m_fDisableComObjectEagerCleanup = false;
m_OSContext = NULL;
m_ThreadTasks = (ThreadTasks)0;
m_pLoadLimiter= NULL;
- m_pLoadingFile = NULL;
// The state and the tasks must be 32-bit aligned for atomicity to be guaranteed.
_ASSERTE((((size_t) &m_State) & 3) == 0);
SetProfilerCallbacksAllowed(TRUE);
m_pCreatingThrowableForException = NULL;
-#ifdef _DEBUG
- m_dwDisableAbortCheckCount = 0;
-#endif // _DEBUG
#ifdef FEATURE_EH_FUNCLETS
m_dwIndexClauseForCatch = 0;
return bRet;
}
-
-// This is to avoid the 64KB/1MB aliasing problem present on Pentium 4 processors,
-// which can significantly impact performance with HyperThreading enabled
-DWORD WINAPI Thread::intermediateThreadProc(PVOID arg)
-{
- WRAPPER_NO_CONTRACT;
-
- m_offset_counter++;
- if (m_offset_counter * offset_multiplier > (int) GetOsPageSize())
- m_offset_counter = 0;
-
- (void)_alloca(m_offset_counter * offset_multiplier);
-
- intermediateThreadParam* param = (intermediateThreadParam*)arg;
-
- LPTHREAD_START_ROUTINE ThreadFcnPtr = param->lpThreadFunction;
- PVOID args = param->lpArg;
- delete param;
-
- return ThreadFcnPtr(args);
-}
-
HANDLE Thread::CreateUtilityThread(Thread::StackSizeBucket stackSizeBucket, LPTHREAD_START_ROUTINE start, void *args, LPCWSTR pName, DWORD flags, DWORD* pThreadId)
{
LIMITED_METHOD_CONTRACT;
}
#endif // !FEATURE_PAL
- intermediateThreadParam* lpThreadArgs = new (nothrow) intermediateThreadParam;
- if (lpThreadArgs == NULL)
- {
- return FALSE;
- }
- NewHolder<intermediateThreadParam> argHolder(lpThreadArgs);
-
// Make sure we have all our handles, in case someone tries to suspend us
// as we are starting up.
if (!AllocHandles())
return FALSE;
}
- lpThreadArgs->lpThreadFunction = start;
- lpThreadArgs->lpArg = args;
-
#ifdef FEATURE_PAL
h = ::PAL_CreateThread64(NULL /*=SECURITY_ATTRIBUTES*/,
#else
h = ::CreateThread( NULL /*=SECURITY_ATTRIBUTES*/,
#endif
sizeToCommitOrReserve,
- intermediateThreadProc,
- lpThreadArgs,
+ start,
+ args,
dwCreationFlags,
&ourId);
if (h == NULL)
return FALSE;
- argHolder.SuppressRelease();
-
_ASSERTE(!m_fPreemptiveGCDisabled); // leave in preemptive until HasStarted.
SetThreadHandle(h);
}
CONTRACTL_END;
- // If thread abort is prevented, we do not want this thread to see thread abort and thread interrupt exception.
- if (IsAbortPrevented())
- {
- return;
- }
-
// A word about ordering for Interrupt. If someone tries to interrupt a thread
// that's in the interruptible state, we queue an APC. But if they try to interrupt
// a thread that's not in the interruptible state, we just record that fact. So
}
}
- FinishSOWork();
-
INDEBUG(DebugLogStackMBIs());
return;
_ASSERTE (this == GetThread());
- FinishSOWork();
-
INT32 nPriority = ThreadNative::PRIORITY_NORMAL;
if (!fNotFinalizerThread && this == FinalizerThread::GetFinalizerThread())
}
}
-ETaskType GetCurrentTaskType()
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
-
- ETaskType TaskType = TT_UNKNOWN;
- size_t type = (size_t)ClrFlsGetValue (TlsIdx_ThreadType);
- if (type & ThreadType_DbgHelper)
- {
- TaskType = TT_DEBUGGERHELPER;
- }
- else if (type & ThreadType_GC)
- {
- TaskType = TT_GC;
- }
- else if (type & ThreadType_Finalizer)
- {
- TaskType = TT_FINALIZER;
- }
- else if (type & ThreadType_Timer)
- {
- TaskType = TT_THREADPOOL_TIMER;
- }
- else if (type & ThreadType_Gate)
- {
- TaskType = TT_THREADPOOL_GATE;
- }
- else if (type & ThreadType_Wait)
- {
- TaskType = TT_THREADPOOL_WAIT;
- }
- else if (type & ThreadType_Threadpool_IOCompletion)
- {
- TaskType = TT_THREADPOOL_IOCOMPLETION;
- }
- else if (type & ThreadType_Threadpool_Worker)
- {
- TaskType = TT_THREADPOOL_WORKER;
- }
- else
- {
- Thread *pThread = GetThread();
- if (pThread)
- {
- TaskType = TT_USER;
- }
- }
-
- return TaskType;
-}
-
DeadlockAwareLock::DeadlockAwareLock(const char *description)
: m_pHoldingThread(NULL)
#ifdef _DEBUG
return (BYTE)ofs;
}
- void SetLoadingFile(DomainFile *pFile)
- {
- }
-
- typedef Holder<Thread *, DoNothing, DoNothing> LoadingFileHolder;
-
enum ThreadState
{
};
TSNC_WaitUntilGCFinished = 0x00000010, // The current thread is waiting for GC. If host returns
// SO during wait, we will either spin or make GC wait.
TSNC_BlockedForShutdown = 0x00000020, // Thread is blocked in WaitForEndOfShutdown. We should not hit WaitForEndOfShutdown again.
- TSNC_SOWorkNeeded = 0x00000040, // The thread needs to wake up AD unload helper thread to finish SO work
+ // unused = 0x00000040,
TSNC_CLRCreatedThread = 0x00000080, // The thread was created through Thread::CreateNewThread
TSNC_ExistInThreadStore = 0x00000100, // For dtor to know if it needs to be removed from ThreadStore
TSNC_UnsafeSkipEnterCooperative = 0x00000200, // This is a "fix" for deadlocks caused when cleaning up COM
// After the thread is interrupted once, we turn off interruption
// at the beginning of wait.
// unused = 0x00040000,
- TSNC_CannotRecycle = 0x00080000, // A host can not recycle this Thread object. When a thread
- // has orphaned lock, we will apply this.
+ // unused = 0x00080000,
TSNC_RaiseUnloadEvent = 0x00100000, // Finalize thread is raising managed unload event which
// may call AppDomain.Unload.
TSNC_UnbalancedLocks = 0x00200000, // Do not rely on lock accounting for this thread:
static LONG m_DetachCount;
static LONG m_ActiveDetachCount; // Count how many non-background detached
- static Volatile<LONG> m_threadsAtUnsafePlaces;
-
// Offsets for the following variables need to fit in 1 byte, so keep near
// the top of the object. Also, we want cache line filling to work for us
// so the critical stuff is ordered based on frequency of use.
typedef StateHolder<Thread::IncPreventAsync, Thread::DecPreventAsync> ThreadPreventAsyncHolder;
- // During a <clinit>, this thread must not be asynchronously
- // stopped or interrupted. That would leave the class unavailable
- // and is therefore a security hole.
- static void IncPreventAbort()
- {
- WRAPPER_NO_CONTRACT;
- Thread *pThread = GetThread();
- FastInterlockIncrement((LONG*)&pThread->m_PreventAbort);
- }
- static void DecPreventAbort()
- {
- WRAPPER_NO_CONTRACT;
- Thread *pThread = GetThread();
- FastInterlockDecrement((LONG*)&pThread->m_PreventAbort);
- }
-
- BOOL IsAbortPrevented()
- {
- return m_PreventAbort != 0;
- }
-
- typedef StateHolder<Thread::IncPreventAbort, Thread::DecPreventAbort> ThreadPreventAbortHolder;
-
// The ThreadStore manages a list of all the threads in the system. I
// can't figure out how to expand the ThreadList template type without
// making m_Link public.
}
#endif // !DACCESS_COMPILE
-private:
-
- //-------------------------------------------------------------------------
- // Support creation of assemblies in DllMain (see ceemain.cpp)
- //-------------------------------------------------------------------------
- DomainFile* m_pLoadingFile;
-
-
public:
void SetInteropDebuggingHijacked(BOOL f)
typedef ConditionalStateHolder<Thread *, Thread::EnterHijackLock, Thread::LeaveHijackLock> HijackLockHolder;
//-------------------------------------------------------------------------
- static bool ThreadsAtUnsafePlaces(void)
- {
- LIMITED_METHOD_CONTRACT;
-
- return (m_threadsAtUnsafePlaces != (LONG)0);
- }
-
- static void IncThreadsAtUnsafePlaces(void)
- {
- LIMITED_METHOD_CONTRACT;
- InterlockedIncrement(&m_threadsAtUnsafePlaces);
- }
-
- static void DecThreadsAtUnsafePlaces(void)
- {
- LIMITED_METHOD_CONTRACT;
- InterlockedDecrement(&m_threadsAtUnsafePlaces);
- }
-
void PrepareForEERestart(BOOL SuspendSucceeded)
{
WRAPPER_NO_CONTRACT;
static LPVOID GetStaticFieldAddress(FieldDesc *pFD);
TADDR GetStaticFieldAddrNoCreate(FieldDesc *pFD);
- void SetLoadingFile(DomainFile *pFile)
- {
- LIMITED_METHOD_CONTRACT;
- CONSISTENCY_CHECK(m_pLoadingFile == NULL);
- m_pLoadingFile = pFile;
- }
-
- void ClearLoadingFile()
- {
- LIMITED_METHOD_CONTRACT;
- m_pLoadingFile = NULL;
- }
-
- DomainFile *GetLoadingFile()
- {
- LIMITED_METHOD_CONTRACT;
- return m_pLoadingFile;
- }
-
-private:
- static void LoadingFileRelease(Thread *pThread)
- {
- WRAPPER_NO_CONTRACT;
- pThread->ClearLoadingFile();
- }
-
-public:
- typedef Holder<Thread *, DoNothing, Thread::LoadingFileRelease> LoadingFileHolder;
-
private:
// Don't allow a thread to be asynchronously stopped or interrupted (e.g. because
// it is performing a <clinit>)
int m_PreventAsync;
- int m_PreventAbort;
- int m_nNestedMarshalingExceptions;
- BOOL IsMarshalingException()
- {
- LIMITED_METHOD_CONTRACT;
- return (m_nNestedMarshalingExceptions != 0);
- }
- int StartedMarshalingException()
- {
- LIMITED_METHOD_CONTRACT;
- return m_nNestedMarshalingExceptions++;
- }
- void FinishedMarshalingException()
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(m_nNestedMarshalingExceptions > 0);
- m_nNestedMarshalingExceptions--;
- }
static LONG m_DebugWillSyncCount;
- // IP cache used by QueueCleanupIP.
- #define CLEANUP_IPS_PER_CHUNK 4
- struct CleanupIPs {
- IUnknown *m_Slots[CLEANUP_IPS_PER_CHUNK];
- CleanupIPs *m_Next;
- CleanupIPs() {LIMITED_METHOD_CONTRACT; memset(this, 0, sizeof(*this)); }
- };
- CleanupIPs m_CleanupIPs;
-
#define BEGIN_FORBID_TYPELOAD() _ASSERTE_IMPL((GetThreadNULLOk() == 0) || ++GetThreadNULLOk()->m_ulForbidTypeLoad)
#define END_FORBID_TYPELOAD() _ASSERTE_IMPL((GetThreadNULLOk() == 0) || GetThreadNULLOk()->m_ulForbidTypeLoad--)
#define TRIGGERS_TYPELOAD() _ASSERTE_IMPL((GetThreadNULLOk() == 0) || !GetThreadNULLOk()->m_ulForbidTypeLoad)
// Is the current thread currently executing within a constrained execution region?
static BOOL IsExecutingWithinCer();
- // Determine whether the method at the given frame in the thread's execution stack is executing within a CER.
- BOOL IsWithinCer(CrawlFrame *pCf);
-
-private:
- // used to pad stack on thread creation to avoid aliasing penalty in P4 HyperThread scenarios
-
- static DWORD WINAPI intermediateThreadProc(PVOID arg);
- static int m_offset_counter;
- static const int offset_multiplier = 128;
-
- typedef struct {
- LPTHREAD_START_ROUTINE lpThreadFunction;
- PVOID lpArg;
- } intermediateThreadParam;
-
#ifdef _DEBUG
// when the thread is doing a stressing GC, some Crst violation could be ignored, by a non-elegant solution.
private:
typedef ConditionalStateHolder<Thread *, Thread::EnterWorkingOnThreadContext, Thread::LeaveWorkingOnThreadContext> WorkingOnThreadContextHolder;
-public:
- void PrepareThreadForSOWork()
- {
- WRAPPER_NO_CONTRACT;
-
-#ifdef FEATURE_HIJACK
- UnhijackThread();
-#endif // FEATURE_HIJACK
-
- ResetThrowControlForThread();
-
- // Since this Thread has taken an SO, there may be state left-over after we
- // short-circuited exception or other error handling, and so we don't want
- // to risk recycling it.
- SetThreadStateNC(TSNC_CannotRecycle);
- }
-
- void SetSOWorkNeeded()
- {
- SetThreadStateNC(TSNC_SOWorkNeeded);
- }
-
- BOOL IsSOWorkNeeded()
- {
- return HasThreadStateNC(TSNC_SOWorkNeeded);
- }
-
- void FinishSOWork();
-
- void ClearExceptionStateAfterSO(void* pStackFrameSP)
- {
- WRAPPER_NO_CONTRACT;
-
- // Clear any stale exception state.
- m_ExceptionState.ClearExceptionStateAfterSO(pStackFrameSP);
- }
-
private:
BOOL m_fAllowProfilerCallbacks;
Exception *m_pCreatingThrowableForException;
friend OBJECTREF CLRException::GetThrowable();
-#ifdef _DEBUG
-private:
- int m_dwDisableAbortCheckCount; // Disable check before calling managed code.
- // !!! Use this very carefully. If managed code runs user code
- // !!! or blocks on locks, the thread may not be aborted.
-public:
- static void DisableAbortCheck()
- {
- WRAPPER_NO_CONTRACT;
- Thread *pThread = GetThread();
- FastInterlockIncrement((LONG*)&pThread->m_dwDisableAbortCheckCount);
- }
- static void EnableAbortCheck()
- {
- WRAPPER_NO_CONTRACT;
- Thread *pThread = GetThread();
- _ASSERTE (pThread->m_dwDisableAbortCheckCount > 0);
- FastInterlockDecrement((LONG*)&pThread->m_dwDisableAbortCheckCount);
- }
-
- BOOL IsAbortCheckDisabled()
- {
- return m_dwDisableAbortCheckCount > 0;
- }
-
- typedef StateHolder<Thread::DisableAbortCheck, Thread::EnableAbortCheck> DisableAbortCheckHolder;
-#endif
-
private:
// At the end of a catch, we may raise ThreadAbortException. If catch clause set IP to resume in the
// corresponding try block, our exception system will execute the same catch clause again and again.
typedef Thread::ForbidSuspendThreadHolder ForbidSuspendThreadHolder;
typedef Thread::ThreadPreventAsyncHolder ThreadPreventAsyncHolder;
-typedef Thread::ThreadPreventAbortHolder ThreadPreventAbortHolder;
-
-// Combines ForBindSuspendThreadHolder and CrstHolder into one.
-class ForbidSuspendThreadCrstHolder
-{
-public:
- // Note: member initialization is intentionally ordered.
- ForbidSuspendThreadCrstHolder(CrstBase * pCrst)
- : m_forbid_suspend_holder()
- , m_lock_holder(pCrst)
- { WRAPPER_NO_CONTRACT; }
-
-private:
- ForbidSuspendThreadHolder m_forbid_suspend_holder;
- CrstHolder m_lock_holder;
-};
-
-ETaskType GetCurrentTaskType();
-
-
-
typedef Thread::AVInRuntimeImplOkayHolder AVInRuntimeImplOkayHolder;
BOOL RevertIfImpersonated(BOOL *bReverted, HANDLE *phToken);
return ObjectFromHandle(m_ExposedObject);
}
-inline void Thread::FinishSOWork()
-{
- WRAPPER_NO_CONTRACT;
- _ASSERTE(!HasThreadStateNC(TSNC_SOWorkNeeded));
-}
-
#ifdef FEATURE_COMINTEROP
inline void Thread::RevokeApartmentSpy()
{
return sContext.fWithinCer;
}
-
-// Context structure used during stack walks to determine whether a given method is executing within a CER.
-struct CerStackCrawlContext
-{
- MethodDesc *m_pStartMethod; // First method we crawl (here for debug purposes)
- bool m_fFirstFrame; // True for first callback only
- bool m_fWithinCer; // The result
-};
-
-
-// Determine whether the method at the given depth in the thread's execution stack is executing within a CER.
-BOOL Thread::IsWithinCer(CrawlFrame *pCf)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return FALSE;
-}
-
#if defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
BOOL Thread::IsSafeToInjectThreadAbort(PTR_CONTEXT pContextToCheck)
{
return FALSE;
}
- if (IsAbortRequested() && HasThreadStateNC(TSNC_SOWorkNeeded))
- {
- return TRUE;
- }
-
if (GetThread() == this && HasThreadStateNC (TSNC_PreparingAbort) && !IsRudeAbort() )
{
STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort PreparingAbort\n");
return FALSE;
}
- if (IsAbortPrevented())
- {
- //
- // If the thread is marked to have a FuncEval abort request, then allow that to go through
- // since we dont want to block funcEval aborts. Such requests are initiated by the
- // right-side when the thread is doing funcEval and the exception would be caught in the
- // left-side's funcEval implementation that will then clear the funcEval-abort-state from the thread.
- //
- // If another thread also marked this one for a non-FuncEval abort, then the left-side will
- // proceed to [re]throw that exception post funcEval abort. When we come here next, we would follow
- // the usual rules to raise the exception and if raised, to prevent the abort if applicable.
- //
- if (!IsFuncEvalAbort())
- {
- STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort prevent abort\n");
- return FALSE;
- }
- }
-
// The thread requests not to be aborted. Honor this for safe abort.
if (!IsRudeAbort() && IsAsyncPrevented())
{
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_TRIGGERS;
- // It's possible we could go through here if we hit a hard SO and MC++ has called back
- // into the runtime on this thread
-
- FinishSOWork();
-
if (IsAbortRequested() && GetAbortEndTime() < CLRGetTickCount64())
{
HandleThreadAbortTimeout();
|| ThreadStore::HoldingThreadStore())
return;
- if (Thread::ThreadsAtUnsafePlaces())
- return;
-
#ifdef DEBUGGING_SUPPORTED
// Don't collect if the debugger is attach and either 1) there
// are any threads held at unsafe places or 2) this thread is
// at a safepoint - since this is the exact same behaviour
// that the debugger needs, just use it's code.
if ((hr == ERROR_TIMEOUT)
- || Thread::ThreadsAtUnsafePlaces()
-#ifdef DEBUGGING_SUPPORTED // seriously? When would we want to disable debugging support? :)
+#ifdef DEBUGGING_SUPPORTED
|| (CORDebuggerAttached() &&
// When the debugger is synchronizing, trying to perform a GC could deadlock. The GC has the
// threadstore lock and synchronization cannot complete until the debugger can get the
#endif
#endif // FEATURE_PAL
-void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX);
-
#define SetupThreadForComCall(OOMRetVal) \
MAKE_CURRENT_THREAD_AVAILABLE_EX(GetThreadNULLOk()); \
if (CURRENT_THREAD == NULL) \
NewHolder<LoaderHeap> indcell_heap_holder(
new LoaderHeap(indcell_heap_reserve_size, indcell_heap_commit_size,
initReservedMem, indcell_heap_reserve_size,
- NULL, NULL, FALSE));
+ NULL, FALSE));
initReservedMem += indcell_heap_reserve_size;
NewHolder<LoaderHeap> cache_entry_heap_holder(
new LoaderHeap(cache_entry_heap_reserve_size, cache_entry_heap_commit_size,
initReservedMem, cache_entry_heap_reserve_size,
- NULL,
&cache_entry_rangeList, FALSE));
initReservedMem += cache_entry_heap_reserve_size;
NewHolder<LoaderHeap> lookup_heap_holder(
new LoaderHeap(lookup_heap_reserve_size, lookup_heap_commit_size,
initReservedMem, lookup_heap_reserve_size,
- NULL,
&lookup_rangeList, TRUE));
initReservedMem += lookup_heap_reserve_size;
NewHolder<LoaderHeap> dispatch_heap_holder(
new LoaderHeap(dispatch_heap_reserve_size, dispatch_heap_commit_size,
initReservedMem, dispatch_heap_reserve_size,
- NULL,
&dispatch_rangeList, TRUE));
initReservedMem += dispatch_heap_reserve_size;
NewHolder<LoaderHeap> resolve_heap_holder(
new LoaderHeap(resolve_heap_reserve_size, resolve_heap_commit_size,
initReservedMem, resolve_heap_reserve_size,
- NULL,
&resolve_rangeList, TRUE));
initReservedMem += resolve_heap_reserve_size;
NewHolder<LoaderHeap> vtable_heap_holder(
new LoaderHeap(vtable_heap_reserve_size, vtable_heap_commit_size,
initReservedMem, vtable_heap_reserve_size,
- NULL,
&vtable_rangeList, TRUE));
initReservedMem += vtable_heap_reserve_size;
// Cacheline aligned, hot variable
DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) unsigned int ThreadpoolMgr::LastDequeueTime; // used to determine if work items are getting thread starved
-// Move out of from preceeding variables' cache line
-DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) int ThreadpoolMgr::offset_counter = 0;
-
SPTR_IMPL(WorkRequest,ThreadpoolMgr,WorkRequestHead); // Head of work request queue
SPTR_IMPL(WorkRequest,ThreadpoolMgr,WorkRequestTail); // Head of work request queue
}
}
-#define THROTTLE_RATE 0.10 /* rate by which we increase the delay as number of threads increase */
-
-// This is to avoid the 64KB/1MB aliasing problem present on Pentium 4 processors,
-// which can significantly impact performance with HyperThreading enabled
-DWORD WINAPI ThreadpoolMgr::intermediateThreadProc(PVOID arg)
-{
- WRAPPER_NO_CONTRACT;
-
- offset_counter++;
- if (offset_counter * offset_multiplier > (int)GetOsPageSize())
- offset_counter = 0;
-
- (void)_alloca(offset_counter * offset_multiplier);
-
- intermediateThreadParam* param = (intermediateThreadParam*)arg;
-
- LPTHREAD_START_ROUTINE ThreadFcnPtr = param->lpThreadFunction;
- PVOID args = param->lpArg;
- delete param;
-
- return ThreadFcnPtr(args);
-}
-
Thread* ThreadpoolMgr::CreateUnimpersonatedThread(LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpArgs, BOOL *pIsCLRThread)
{
STATIC_CONTRACT_NOTHROW;
if (bOK != TRUE)
return NULL;
#endif // !FEATURE_PAL
- NewHolder<intermediateThreadParam> lpThreadArgs(new (nothrow) intermediateThreadParam);
- if (lpThreadArgs != NULL)
- {
- lpThreadArgs->lpThreadFunction = lpStartAddress;
- lpThreadArgs->lpArg = lpArgs;
- threadHandle = CreateThread(NULL, // security descriptor
- 0, // default stack size
- intermediateThreadProc,
- lpThreadArgs, // arguments
- CREATE_SUSPENDED,
- &threadId);
-
- SetThreadName(threadHandle, W(".NET ThreadPool Worker"));
- if (threadHandle != NULL)
- lpThreadArgs.SuppressRelease();
- }
+ threadHandle = CreateThread(NULL, // security descriptor
+ 0, // default stack size
+ lpStartAddress,
+ lpArgs,
+ CREATE_SUSPENDED,
+ &threadId);
+
+ SetThreadName(threadHandle, W(".NET ThreadPool Worker"));
#ifndef FEATURE_PAL
UndoRevert(bReverted, token);
#endif // !FEATURE_PAL
// Private methods
- static DWORD WINAPI intermediateThreadProc(PVOID arg);
-
- typedef struct {
- LPTHREAD_START_ROUTINE lpThreadFunction;
- PVOID lpArg;
- } intermediateThreadParam;
-
static Thread* CreateUnimpersonatedThread(LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpArgs, BOOL *pIsCLRThread);
static BOOL CreateWorkerThread();
#ifdef _DEBUG
static DWORD TickCountAdjustment; // add this value to value returned by GetTickCount
#endif
-
- DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) static int offset_counter;
- static const int offset_multiplier = 128;
};