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.
7 // This file contains the implementation of thread suspension. The implementation of thread suspension
8 // used to be spread through multiple places. That is why, many methods still live in their own homes
9 // (class Thread, class ThreadStore, etc.). They should be eventually refactored into class ThreadSuspend.
14 #include "threadsuspend.h"
16 #include "finalizerthread.h"
17 #include "dbginterface.h"
19 #include "mdaassistants.h"
22 #define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS)0xC000004AL)
24 #define HIJACK_NONINTERRUPTIBLE_THREADS
26 bool ThreadSuspend::s_fSuspendRuntimeInProgress = false;
28 CLREvent* ThreadSuspend::g_pGCSuspendEvent = NULL;
30 ThreadSuspend::SUSPEND_REASON ThreadSuspend::m_suspendReason;
31 Thread* ThreadSuspend::m_pThreadAttemptingSuspendForGC;
33 CLREventBase * ThreadSuspend::s_hAbortEvt = NULL;
34 CLREventBase * ThreadSuspend::s_hAbortEvtCache = NULL;
36 // If you add any thread redirection function, make sure the debugger can 1) recognize the redirection
37 // function, and 2) retrieve the original CONTEXT. See code:Debugger.InitializeHijackFunctionAddress and
38 // code:DacDbiInterfaceImpl.RetrieveHijackedContext.
39 extern "C" void RedirectedHandledJITCaseForGCThreadControl_Stub(void);
40 extern "C" void RedirectedHandledJITCaseForDbgThreadControl_Stub(void);
41 extern "C" void RedirectedHandledJITCaseForUserSuspend_Stub(void);
43 #define GetRedirectHandlerForGCThreadControl() \
44 ((PFN_REDIRECTTARGET) GetEEFuncEntryPoint(RedirectedHandledJITCaseForGCThreadControl_Stub))
45 #define GetRedirectHandlerForDbgThreadControl() \
46 ((PFN_REDIRECTTARGET) GetEEFuncEntryPoint(RedirectedHandledJITCaseForDbgThreadControl_Stub))
47 #define GetRedirectHandlerForUserSuspend() \
48 ((PFN_REDIRECTTARGET) GetEEFuncEntryPoint(RedirectedHandledJITCaseForUserSuspend_Stub))
50 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
51 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
52 extern "C" void RedirectedHandledJITCaseForGCStress_Stub(void);
53 #define GetRedirectHandlerForGCStress() \
54 ((PFN_REDIRECTTARGET) GetEEFuncEntryPoint(RedirectedHandledJITCaseForGCStress_Stub))
55 #endif // HAVE_GCCOVER && USE_REDIRECT_FOR_GCSTRESS
56 #endif // _TARGET_AMD64_ || _TARGET_ARM_
59 // Every PING_JIT_TIMEOUT ms, check to see if a thread in JITted code has wandered
60 // into some fully interruptible code (or should have a different hijack to improve
61 // our chances of snagging it at a safe spot).
62 #define PING_JIT_TIMEOUT 10
64 // When we find a thread in a spot that's not safe to abort -- how long to wait before
66 #define ABORT_POLL_TIMEOUT 10
68 #define ABORT_FAIL_TIMEOUT 40000
72 // CANNOT USE IsBad*Ptr() methods here. They are *banned* APIs because of various
73 // reasons (see http://winweb/wincet/bannedapis.htm).
75 #define IS_VALID_WRITE_PTR(addr, size) _ASSERTE(addr != NULL)
76 #define IS_VALID_CODE_PTR(addr) _ASSERTE(addr != NULL)
79 void ThreadSuspend::SetSuspendRuntimeInProgress()
81 LIMITED_METHOD_CONTRACT;
82 _ASSERTE(ThreadStore::HoldingThreadStore() || IsAtProcessExit());
83 _ASSERTE(!s_fSuspendRuntimeInProgress || IsAtProcessExit());
84 s_fSuspendRuntimeInProgress = true;
87 void ThreadSuspend::ResetSuspendRuntimeInProgress()
89 LIMITED_METHOD_CONTRACT;
90 _ASSERTE(ThreadStore::HoldingThreadStore() || IsAtProcessExit());
91 _ASSERTE(s_fSuspendRuntimeInProgress || IsAtProcessExit());
92 s_fSuspendRuntimeInProgress = false;
96 // When SuspendThread returns, target thread may still be executing user code.
97 // We can not access data, e.g. m_fPreemptiveGCDisabled, changed by target thread.
98 // But our code depends on reading these data. To make this operation safe, we
99 // call GetThreadContext which returns only after target thread does not execute
102 // Message from David Cutler
104 After SuspendThread returns, can the suspended thread continue to execute code in user mode?
106 [David Cutler] The suspended thread cannot execute any more user code, but it might be currently "running"
107 on a logical processor whose other logical processor is currently actually executing another thread.
108 In this case the target thread will not suspend until the hardware switches back to executing instructions
109 on its logical processor. In this case even the memory barrier would not necessarily work - a better solution
110 would be to use interlocked operations on the variable itself.
112 After SuspendThread returns, does the store buffer of the CPU for the suspended thread still need to drain?
114 Historically, we've assumed that the answer to both questions is No. But on one 4/8 hyper-threaded machine
115 running Win2K3 SP1 build 1421, we've seen two stress failures where SuspendThread returns while writes seem to still be in flight.
117 Usually after we suspend a thread, we then call GetThreadContext. This seems to guarantee consistency.
118 But there are places we would like to avoid GetThreadContext, if it's safe and legal.
120 [David Cutler] Get context delivers a APC to the target thread and waits on an event that will be set
121 when the target thread has delivered its context.
126 // Message from Neill Clift
128 What SuspendThread does is insert an APC block into a target thread and request an inter-processor interrupt to
129 do the APC interrupt. It doesn't wait till the thread actually enters some state or the interrupt has been serviced.
131 I took a quick look at the APIC spec in the Intel manuals this morning. Writing to the APIC posts a message on a bus.
132 Processors accept messages and presumably queue the s/w interrupts at this time. We don't wait for this acceptance
133 when we send the IPI so at least on APIC machines when you suspend a thread it continues to execute code for some short time
134 after the routine returns. We use other mechanisms for IPI and so it could work differently on different h/w.
137 BOOL EnsureThreadIsSuspended (HANDLE hThread, Thread* pThread)
139 STATIC_CONTRACT_NOTHROW;
140 STATIC_CONTRACT_GC_NOTRIGGER;
145 ctx.ContextFlags = CONTEXT_INTEGER;
148 ret = ::GetThreadContext(hThread, &ctx);
152 FORCEINLINE VOID MyEnterLogLock()
156 FORCEINLINE VOID MyLeaveLogLock()
161 // On non-Windows CORECLR platforms remove Thread::SuspendThread support
162 #ifndef DISABLE_THREADSUSPEND
164 // Attempts to OS-suspend the thread, whichever GC mode it is in.
166 // fOneTryOnly - If TRUE, report failure if the thread has its
167 // m_dwForbidSuspendThread flag set. If FALSE, retry.
168 // pdwSuspendCount - If non-NULL, will contain the return code
169 // of the underlying OS SuspendThread call on success,
170 // undefined on any kind of failure.
172 // A SuspendThreadResult value indicating success or failure.
173 Thread::SuspendThreadResult Thread::SuspendThread(BOOL fOneTryOnly, DWORD *pdwSuspendCount)
182 if (StressLog::StressLogOn((unsigned int)-1, 0))
184 // Make sure to create the stress log for the current thread
185 // (if needed) before we suspend the target thread. The target
186 // thread may be holding the stress log lock when we suspend it,
187 // which could cause a deadlock.
188 if (StressLog::CreateThreadStressLog() == NULL)
190 return STR_NoStressLog;
195 Volatile<HANDLE> hThread;
196 SuspendThreadResult str = (SuspendThreadResult) -1;
197 DWORD dwSuspendCount = 0;
201 bool bDiagSuspend = g_pConfig->GetDiagnosticSuspend();
202 ULONGLONG i64TimestampStart = CLRGetTickCount64();
203 ULONGLONG i64TimestampCur = i64TimestampStart;
204 ULONGLONG i64TimestampPrev = i64TimestampStart;
206 // This is the max allowed timestamp ticks to transpire from beginning of
207 // our attempt to suspend the thread, before we'll assert (implying we believe
208 // there might be a deadlock) - (default = 2000).
209 ULONGLONG i64TimestampTicksMax = g_pConfig->SuspendThreadDeadlockTimeoutMs();
213 // Stop the stress log from allocating any new memory while in this function
214 // as that can lead to deadlocks
215 CantAllocHolder hldrCantAlloc;
218 DWORD dwSwitchCount = 0;
221 StateHolder<MyEnterLogLock, MyLeaveLogLock> LogLockHolder(FALSE);
223 CounterHolder handleHolder(&m_dwThreadHandleBeingUsed);
225 // Whether or not "goto retry" should YieldProcessor and __SwitchToThread
226 BOOL doSwitchToThread = TRUE;
228 hThread = GetThreadHandle();
229 if (hThread == INVALID_HANDLE_VALUE) {
230 str = STR_UnstartedOrDead;
233 else if (hThread == SWITCHOUT_HANDLE_VALUE) {
234 str = STR_SwitchedOut;
239 // We do not want to suspend the target thread while it is holding the log lock.
240 // By acquiring the lock ourselves, we know that this is not the case.
241 LogLockHolder.Acquire();
243 // It is important to avoid two threads suspending each other.
244 // Before a thread suspends another, it increments its own m_dwForbidSuspendThread count first,
245 // then it checks the target thread's m_dwForbidSuspendThread.
246 ForbidSuspendThreadHolder forbidSuspend;
247 if ((m_dwForbidSuspendThread != 0))
250 // Enable the diagnostic ::SuspendThread() if the
251 // DiagnosticSuspend config setting is set.
252 // This will interfere with the mutual suspend race but it's
253 // here only for diagnostic purposes anyway
259 dwSuspendCount = ::SuspendThread(hThread);
262 // Since SuspendThread is asynchronous, we now must wait for the thread to
263 // actually be suspended before decrementing our own m_dwForbidSuspendThread count.
264 // Otherwise there would still be a chance for the "suspended" thread to suspend us
265 // before it really stops running.
267 if ((int)dwSuspendCount >= 0)
269 if (!EnsureThreadIsSuspended(hThread, this))
271 ::ResumeThread(hThread);
277 if ((int)dwSuspendCount >= 0)
279 if (hThread == GetThreadHandle())
281 if (m_dwForbidSuspendThread != 0)
284 // Log diagnostic below 8 times during the i64TimestampTicksMax period
285 if (i64TimestampCur-i64TimestampStart >= nCnt*(i64TimestampTicksMax>>3) )
289 ctx.ContextFlags = CONTEXT_CONTROL;
290 this->GetThreadContext(&ctx);
291 STRESS_LOG7(LF_SYNC, LL_INFO1000,
292 "Thread::SuspendThread[%p]: EIP=%p. nCnt=%d. result=%d.\n"
293 "\t\t\t\t\t\t\t\t\t forbidSuspend=%d. coop=%d. state=%x.\n",
294 this, GetIP(&ctx), nCnt, dwSuspendCount,
295 (LONG)this->m_dwForbidSuspendThread, (ULONG)this->m_fPreemptiveGCDisabled, this->GetSnapshotState());
297 // Enable a preemptive assert in diagnostic mode: before we
298 // resume the target thread to get its current state in the debugger
301 // triggered after 6 * 250msec
302 _ASSERTE(nCnt < 6 && "Timing out in Thread::SuspendThread");
308 ::ResumeThread(hThread);
311 // If the suspend diagnostics are enabled we need to spin here in order to avoid
312 // the case where we Suspend/Resume the target thread without giving it a chance to run.
313 if ((!fOneTryOnly) && bDiagSuspend)
315 while ( m_dwForbidSuspendThread != 0 &&
316 CLRGetTickCount64()-i64TimestampStart < nCnt*(i64TimestampTicksMax>>3) )
318 if (g_SystemInfo.dwNumberOfProcessors > 1)
320 if ((tries++) % 20 != 0)
322 YieldProcessor(); // play nice on hyperthreaded CPUs
324 __SwitchToThread(0, ++dwSwitchCount);
329 __SwitchToThread(0, ++dwSwitchCount); // don't spin on uniproc machines
336 // We suspend the right thread
338 Thread * pCurThread = GetThread();
339 if (pCurThread != NULL)
341 pCurThread->dbg_m_cSuspendedThreads ++;
342 _ASSERTE(pCurThread->dbg_m_cSuspendedThreads > 0);
347 m_ThreadHandleForResume = hThread;
353 // A thread was switch out but in again.
354 // We suspend a wrong thread.
355 ::ResumeThread(hThread);
356 doSwitchToThread = FALSE;
361 // We can get here either SuspendThread fails
362 // Or the fiber thread dies after this fiber switched out.
364 if ((int)dwSuspendCount != -1) {
365 STRESS_LOG1(LF_SYNC, LL_INFO1000, "In Thread::SuspendThread ::SuspendThread returned %x\n", dwSuspendCount);
367 if (GetThreadHandle() == SWITCHOUT_HANDLE_VALUE) {
368 str = STR_SwitchedOut;
372 // Our callers generally expect that STR_Failure means that
373 // the thread has exited.
375 _ASSERTE(NtCurrentTeb()->LastStatusValue != STATUS_SUSPEND_COUNT_EXCEEDED);
376 #endif // !FEATURE_PAL
383 handleHolder.Release();
384 LogLockHolder.Release();
393 i64TimestampPrev = i64TimestampCur;
394 i64TimestampCur = CLRGetTickCount64();
395 // CLRGetTickCount64() is global per machine (not per CPU, like getTimeStamp()).
396 // Next ASSERT states that CLRGetTickCount64() is increasing, or has wrapped.
397 // If it wrapped, the last iteration should have executed faster then 0.5 seconds.
398 _ASSERTE(i64TimestampCur >= i64TimestampPrev || i64TimestampCur <= 500);
400 if (i64TimestampCur - i64TimestampStart >= i64TimestampTicksMax)
402 dwSuspendCount = ::SuspendThread(hThread);
403 _ASSERTE(!"It takes too long to suspend a thread");
404 if ((int)dwSuspendCount >= 0)
405 ::ResumeThread(hThread);
409 if (doSwitchToThread)
411 // When looking for deadlocks we need to allow the target thread to run in order to make some progress.
412 // On multi processor machines we saw the suspending thread resuming immediately after the __SwitchToThread()
413 // because it has another few processors available. As a consequence the target thread was being Resumed and
414 // Suspended right away, w/o a real chance to make any progress.
415 if (g_SystemInfo.dwNumberOfProcessors > 1)
417 if ((tries++) % 20 != 0) {
418 YieldProcessor(); // play nice on hyperthreaded CPUs
420 __SwitchToThread(0, ++dwSwitchCount);
425 __SwitchToThread(0, ++dwSwitchCount); // don't spin on uniproc machines
431 #ifdef PROFILING_SUPPORTED
433 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
434 if (str == STR_Success)
436 g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this);
440 #endif // PROFILING_SUPPORTED
442 if (pdwSuspendCount != NULL)
444 *pdwSuspendCount = dwSuspendCount;
446 _ASSERTE(str != (SuspendThreadResult) -1);
450 #endif // DISABLE_THREADSUSPEND
452 // On non-Windows CORECLR platforms remove Thread::ResumeThread support
453 #ifndef DISABLE_THREADSUSPEND
454 DWORD Thread::ResumeThread()
465 _ASSERTE (m_ThreadHandleForResume != INVALID_HANDLE_VALUE);
467 _ASSERTE (GetThreadHandle() != SWITCHOUT_HANDLE_VALUE);
469 //DWORD res = ::ResumeThread(GetThreadHandle());
470 DWORD res = ::ResumeThread(m_ThreadHandleForResume);
471 _ASSERTE (res != 0 && "Thread is not previously suspended");
473 _ASSERTE (!m_Creater.IsCurrentThread());
474 if ((res != (DWORD)-1) && (res != 0))
476 Thread * pCurThread = GetThread();
477 if (pCurThread != NULL)
479 _ASSERTE(pCurThread->dbg_m_cSuspendedThreads > 0);
480 pCurThread->dbg_m_cSuspendedThreads --;
481 _ASSERTE(pCurThread->dbg_m_cSuspendedThreadsWithoutOSLock <= pCurThread->dbg_m_cSuspendedThreads);
485 if (res != (DWORD) -1 && res != 0)
489 #ifdef PROFILING_SUPPORTED
491 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
492 if ((res != 0) && (res != (DWORD)-1))
494 g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)this);
502 #endif // DISABLE_THREADSUSPEND
508 // Checks whether the given thread is currently suspended.
509 // Note that if we cannot determine the true suspension status
510 // of the thread, we succeed. Intended to be used in asserts
511 // in operations that require the target thread to be suspended.
513 // pThread - The thread to examine.
515 // FALSE, if the thread is definitely not suspended.
517 static inline BOOL CheckSuspended(Thread *pThread)
527 _ASSERTE(GetThread() != pThread);
528 _ASSERTE(CheckPointer(pThread));
530 #ifndef DISABLE_THREADSUSPEND
531 // Only perform this test if we're allowed to call back into the host.
532 // Thread::SuspendThread contains several potential calls into the host.
533 if (CanThisThreadCallIntoHost())
535 DWORD dwSuspendCount;
536 Thread::SuspendThreadResult str = pThread->SuspendThread(FALSE, &dwSuspendCount);
537 forceStackA = &dwSuspendCount;
538 if (str == Thread::STR_Success)
540 pThread->ResumeThread();
541 return dwSuspendCount >= 1;
544 #endif // !DISABLE_THREADSUSPEND
549 BOOL EEGetThreadContext(Thread *pThread, CONTEXT *pContext)
557 _ASSERTE(CheckSuspended(pThread));
559 BOOL ret = pThread->GetThreadContext(pContext);
561 STRESS_LOG6(LF_SYNC, LL_INFO1000, "Got thread context ret = %d EIP = %p ESP = %p EBP = %p, pThread = %p, ContextFlags = 0x%x\n",
562 ret, GetIP(pContext), GetSP(pContext), GetFP(pContext), pThread, pContext->ContextFlags);
568 BOOL EESetThreadContext(Thread *pThread, const CONTEXT *pContext)
577 _ASSERTE(CheckSuspended(pThread));
580 BOOL ret = pThread->SetThreadContext(pContext);
582 STRESS_LOG6(LF_SYNC, LL_INFO1000, "Set thread context ret = %d EIP = %p ESP = %p EBP = %p, pThread = %p, ContextFlags = 0x%x\n",
583 ret, GetIP((CONTEXT*)pContext), GetSP((CONTEXT*)pContext), GetFP((CONTEXT*)pContext), pThread, pContext->ContextFlags);
588 // The AbortReason must be cleared at the following times:
590 // 1. When the application performs a ResetAbort.
592 // 2. When the physical thread stops running. That's because we must eliminate any
593 // cycles that would otherwise be uncollectible, between the Reason and the Thread.
594 // Nobody can retrieve the Reason after the thread stops running anyway.
596 // We don't have to do any work when the AppDomain containing the Reason object is unloaded.
597 // That's because the HANDLE is released as part of the tear-down. The 'adid' prevents us
598 // from ever using the trash handle value thereafter.
600 void Thread::ClearAbortReason(BOOL pNoLock)
614 // Stash the fields so we can destroy the OBJECTHANDLE if appropriate.
616 adid = m_AbortReasonDomainID;
620 m_AbortReasonDomainID = ADID(INVALID_APPDOMAIN_ID);
623 // Scope the lock to stashing and clearing the two fields on the Thread object.
625 // Atomically get the OBJECTHANDLE and ADID of the object, and then
628 // NOTE: get the lock on this thread object, not on the executing thread.
629 Thread::AbortRequestLockHolder lock(this);
631 // Stash the fields so we can destroy the OBJECTHANDLE if appropriate.
633 adid = m_AbortReasonDomainID;
637 m_AbortReasonDomainID = ADID(INVALID_APPDOMAIN_ID);
640 // If there is an OBJECTHANDLE, try to clear it.
641 if (oh != 0 && adid.m_dwId != 0)
642 { // See if the domain is still valid; if so, destroy the ObjectHandle
643 AppDomainFromIDHolder ad(adid, TRUE);
644 if (!ad.IsUnloaded())
645 { // Still a valid domain, so destroy the handle.
652 // Context passed down through a stack crawl (see code below).
653 struct StackCrawlContext
657 SCC_CheckWithinEH = 0x00000001,
658 SCC_CheckWithinCer = 0x00000002,
662 BOOL fUnprotectedCode;
663 BOOL fWithinEHClause;
665 BOOL fHasManagedCodeOnStack;
666 BOOL fWriteToStressLog;
669 CrawlFrame LatchedCF;
672 // Crawl the stack looking for Thread Abort related information (whether we're executing inside a CER or an error handling clauses
674 static StackWalkAction TAStackCrawlCallBackWorker(CrawlFrame* pCf, StackCrawlContext *pData)
682 _ASSERTE(pData->eType & (StackCrawlContext::SCC_CheckWithinCer | StackCrawlContext::SCC_CheckWithinEH));
684 if(pCf->IsFrameless())
686 IJitManager* pJitManager = pCf->GetJitManager();
687 _ASSERTE(pJitManager);
688 if (pJitManager && !pData->fHasManagedCodeOnStack)
690 pData->fHasManagedCodeOnStack = TRUE;
694 // Get the method for this frame if it exists (might not be a managed method, so check the explicit frame if that's what we're
696 MethodDesc *pMD = pCf->GetFunction();
697 Frame *pFrame = pCf->GetFrame();
698 if (pMD == NULL && pFrame != NULL)
699 pMD = pFrame->GetFunction();
701 // Non-method frames don't interest us.
706 #define METHODNAME(pFunc) (pFunc?pFunc->m_pszDebugMethodName:"<n/a>")
708 #define METHODNAME(pFunc) "<n/a>"
710 if (pData->fWriteToStressLog)
712 STRESS_LOG5(LF_EH, LL_INFO100, "TAStackCrawlCallBack: STACKCRAWL method:%pM ('%s'), offset %x, Frame:%p, FrameVtable = %pV\n",
713 pMD, METHODNAME(pMD), pCf->IsFrameless()?pCf->GetRelOffset():0, pFrame, pCf->IsFrameless()?0:(*(void**)pFrame));
718 // If we weren't asked about EH clauses then we can return now (stop the stack trace if we have a definitive answer on the CER
719 // question, move to the next frame otherwise).
720 if ((pData->eType & StackCrawlContext::SCC_CheckWithinEH) == 0)
721 return ((pData->fWithinCer || pData->fUnprotectedCode) && pData->fHasManagedCodeOnStack) ? SWA_ABORT : SWA_CONTINUE;
723 // If we already discovered we're within an EH clause but are still processing (presumably to determine whether we're within a
724 // CER), then we can just skip to the next frame straight away. Also terminate here if the current frame is not frameless since
725 // there isn't any useful EH information for non-managed frames.
726 if (pData->fWithinEHClause || !pCf->IsFrameless())
729 IJitManager* pJitManager = pCf->GetJitManager();
730 _ASSERTE(pJitManager);
732 EH_CLAUSE_ENUMERATOR pEnumState;
733 unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
735 // We do not have finally clause here.
738 DWORD offs = (DWORD)pCf->GetRelOffset();
740 if (!pCf->IsActiveFrame())
742 // If we aren't the topmost method, then our IP is a return address and
743 // we can't use it to directly compare against the EH ranges because we
744 // may be in an cloned finally which has a call as the last instruction.
749 if (pData->fWriteToStressLog)
751 STRESS_LOG1(LF_EH, LL_INFO100, "TAStackCrawlCallBack: STACKCRAWL Offset 0x%x V\n", offs);
753 EE_ILEXCEPTION_CLAUSE EHClause;
755 StackWalkAction action = SWA_CONTINUE;
756 #ifndef WIN64EXCEPTIONS
757 // On X86, the EH encoding for catch clause is completely mess.
758 // If catch clause is in its own basic block, the end of catch includes everything in the basic block.
759 // For nested catch, the end of catch may include several jmp instructions after JIT_EndCatch call.
760 // To better decide if we are inside a nested catch, we check if offs-1 is in more than one catch clause.
761 DWORD countInCatch = 0;
762 BOOL fAtJitEndCatch = FALSE;
763 if (pData->pAbortee == GetThread() &&
764 pData->pAbortee->ThrewControlForThread() == Thread::InducedThreadRedirectAtEndOfCatch &&
765 GetControlPC(pCf->GetRegisterSet()) == (PCODE)GetIP(pData->pAbortee->GetAbortContext()))
767 fAtJitEndCatch = TRUE;
770 #endif // !WIN64EXCEPTIONS
772 for(ULONG i=0; i < EHCount; i++)
774 pJitManager->GetNextEHClause(&pEnumState, &EHClause);
775 _ASSERTE(IsValidClause(&EHClause));
777 // !!! If this function is called on Aborter thread, we should check for finally only.
779 // !!! If this function is called on Aborter thread, we should check for finally only.
780 // !!! Catch and filter clause are skipped. In UserAbort, the first thing after ReadyForAbort
781 // !!! is to check if the target thread is processing exception.
782 // !!! If exception is in flight, we don't induce ThreadAbort. Instead at the end of Jit_EndCatch
783 // !!! we will handle abort.
784 if (pData->pAbortee != GetThread() && !IsFaultOrFinally(&EHClause))
788 if (offs >= EHClause.HandlerStartPC &&
789 offs < EHClause.HandlerEndPC)
791 #ifndef WIN64EXCEPTIONS
794 // On X86, JIT's EH info may include the instruction after JIT_EndCatch inside the same catch
795 // clause if it is in the same basic block.
796 // So for this case, the offs is in at least one catch handler, but since we are at the end of
797 // catch, this one should not be counted.
799 if (countInCatch == 1)
804 #endif // !WIN64EXCEPTIONS
805 pData->fWithinEHClause = true;
806 // We're within an EH clause. If we're asking about CERs too then stop the stack walk if we've reached a conclusive
807 // result or continue looking otherwise. Else we can stop the stackwalk now.
808 if (pData->eType & StackCrawlContext::SCC_CheckWithinCer)
810 action = (pData->fWithinCer || pData->fUnprotectedCode) ? SWA_ABORT : SWA_CONTINUE;
820 #ifndef WIN64EXCEPTIONS
824 _ASSERTE (countInCatch > 0);
827 #endif // !WIN64EXCEPTIONS_
831 // Wrapper around code:TAStackCrawlCallBackWorker that abstracts away the differences between the reporting order
832 // of x86 and 64-bit stackwalker implementations, and also deals with interop calls that have an implicit reliability
833 // contract. If a P/Invoke or CLR->COM call returns SafeHandle or CriticalHandle, the IL stub could be aborted
834 // before having a chance to store the native handle into the Safe/CriticalHandle object. Therefore such calls are
835 // treated as unbreakable by convention.
836 StackWalkAction TAStackCrawlCallBack(CrawlFrame* pCf, void* data)
844 StackCrawlContext *pData = (StackCrawlContext *)data;
846 // We have the current frame in pCf and possibly one latched frame in pData->LatchedCF. This enumeration
847 // describes which of these should be passed to code:TAStackCrawlCallBackWorker and in what order.
848 enum LatchedFrameAction
850 DiscardLatchedFrame, // forget the latched frame, report the current one
851 DiscardCurrentFrame, // ignore the current frame, report the latched one
852 ProcessLatchedInOrder, // report the latched frame, then report the current frame
853 ProcessLatchedReversed, // report the current frame, then report the latched frame
854 LatchCurrentFrame // latch the current frame, don't report anything
856 frameAction = DiscardLatchedFrame;
859 // On X86 the IL stub method is reported to us before the frame with the actual interop method. We need to
860 // swap the order because if the worker saw the IL stub - which is a CER root - first, it would terminate the
861 // stack walk and wouldn't allow the thread to be aborted, regardless of how the interop method is annotated.
862 if (pData->fHaveLatchedCF)
864 // Does the current and latched frame represent the same call?
865 if (pCf->pFrame == pData->LatchedCF.pFrame)
867 if (pData->LatchedCF.GetFunction()->AsDynamicMethodDesc()->IsUnbreakable())
869 // Report only the latched IL stub frame which is a CER root.
870 frameAction = DiscardCurrentFrame;
874 // Report the interop method (current frame) which may be annotated, then the IL stub.
875 frameAction = ProcessLatchedReversed;
880 // The two frames are unrelated - process them in order.
881 frameAction = ProcessLatchedInOrder;
883 pData->fHaveLatchedCF = FALSE;
887 MethodDesc *pMD = pCf->GetFunction();
888 if (pMD != NULL && pMD->IsILStub() && InlinedCallFrame::FrameHasActiveCall(pCf->pFrame))
890 // This may be IL stub for an interesting interop call - latch it.
891 frameAction = LatchCurrentFrame;
894 #else // _TARGET_X86_
895 // On 64-bit the IL stub method is reported after the actual interop method so we don't have to swap them.
896 // However, we still want to discard the interop method frame if the call is unbreakable by convention.
897 if (pData->fHaveLatchedCF)
899 MethodDesc *pMD = pCf->GetFunction();
900 if (pMD != NULL && pMD->IsILStub() &&
901 pData->LatchedCF.GetFrame()->GetReturnAddress() == GetControlPC(pCf->GetRegisterSet()) &&
902 pMD->AsDynamicMethodDesc()->IsUnbreakable())
904 // The current and latched frame represent the same call and the IL stub is marked as unbreakable.
905 // We will discard the interop method and report only the IL stub which is a CER root.
906 frameAction = DiscardLatchedFrame;
910 // Otherwise process the two frames in order.
911 frameAction = ProcessLatchedInOrder;
913 pData->fHaveLatchedCF = FALSE;
917 MethodDesc *pMD = pCf->GetFunction();
918 if (pCf->GetFrame() != NULL && pMD != NULL && (pMD->IsNDirect() || pMD->IsComPlusCall()))
920 // This may be interop method of an interesting interop call - latch it.
921 frameAction = LatchCurrentFrame;
924 #endif // _TARGET_X86_
926 // Execute the "frame action".
927 StackWalkAction action;
930 case DiscardLatchedFrame:
931 action = TAStackCrawlCallBackWorker(pCf, pData);
934 case DiscardCurrentFrame:
935 action = TAStackCrawlCallBackWorker(&pData->LatchedCF, pData);
938 case ProcessLatchedInOrder:
939 action = TAStackCrawlCallBackWorker(&pData->LatchedCF, pData);
940 if (action == SWA_CONTINUE)
941 action = TAStackCrawlCallBackWorker(pCf, pData);
944 case ProcessLatchedReversed:
945 action = TAStackCrawlCallBackWorker(pCf, pData);
946 if (action == SWA_CONTINUE)
947 action = TAStackCrawlCallBackWorker(&pData->LatchedCF, pData);
950 case LatchCurrentFrame:
951 pData->LatchedCF = *pCf;
952 pData->fHaveLatchedCF = TRUE;
953 action = SWA_CONTINUE;
962 // Is the current thread currently executing within a constrained execution region?
963 BOOL Thread::IsExecutingWithinCer()
975 Thread *pThread = GetThread();
977 StackCrawlContext sContext = { pThread,
978 StackCrawlContext::SCC_CheckWithinCer,
986 pThread->StackWalkFrames(TAStackCrawlCallBack, &sContext);
989 if (sContext.fWithinCer && StressLog::StressLogOn(~0u, 0))
991 // If stress log is on, write info to stress log
992 StackCrawlContext sContext1 = { pThread,
993 StackCrawlContext::SCC_CheckWithinCer,
1001 pThread->StackWalkFrames(TAStackCrawlCallBack, &sContext1);
1005 return sContext.fWithinCer;
1009 // Context structure used during stack walks to determine whether a given method is executing within a CER.
1010 struct CerStackCrawlContext
1012 MethodDesc *m_pStartMethod; // First method we crawl (here for debug purposes)
1013 bool m_fFirstFrame; // True for first callback only
1014 bool m_fWithinCer; // The result
1018 // Determine whether the method at the given depth in the thread's execution stack is executing within a CER.
1019 BOOL Thread::IsWithinCer(CrawlFrame *pCf)
1031 #if defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
1032 BOOL Thread::IsSafeToInjectThreadAbort(PTR_CONTEXT pContextToCheck)
1039 PRECONDITION(pContextToCheck != NULL);
1043 EECodeInfo codeInfo(GetIP(pContextToCheck));
1044 _ASSERTE(codeInfo.IsValid());
1046 // Check if the method uses a frame register. If it does not, then RSP will be used by the OS as the frame register
1047 // and returned as the EstablisherFrame. This is fine at any instruction in the method (including epilog) since there is always a
1048 // difference of stackslot size between the callerSP and the callee SP due to return address having been pushed on the stack.
1049 if (!codeInfo.HasFrameRegister())
1054 BOOL fSafeToInjectThreadAbort = TRUE;
1056 if (IsIPInEpilog(pContextToCheck, &codeInfo, &fSafeToInjectThreadAbort))
1058 return fSafeToInjectThreadAbort;
1065 #endif // defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
1067 #ifdef _TARGET_AMD64_
1068 // CONTEXT_CONTROL does not include any nonvolatile registers that might be the frame pointer.
1069 #define CONTEXT_MIN_STACKWALK (CONTEXT_CONTROL | CONTEXT_INTEGER)
1071 #define CONTEXT_MIN_STACKWALK (CONTEXT_CONTROL)
1075 BOOL Thread::ReadyForAsyncException()
1084 if (!IsAbortRequested())
1089 if (IsAbortRequested() && HasThreadStateNC(TSNC_SOWorkNeeded))
1094 // This needs the probe with GenerateHardSO
1095 CONTRACT_VIOLATION(SOToleranceViolation);
1097 if (GetThread() == this && HasThreadStateNC (TSNC_PreparingAbort) && !IsRudeAbort() )
1099 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort PreparingAbort\n");
1100 // Avoid recursive call
1104 if (IsAbortPrevented())
1107 // If the thread is marked to have a FuncEval abort request, then allow that to go through
1108 // since we dont want to block funcEval aborts. Such requests are initiated by the
1109 // right-side when the thread is doing funcEval and the exception would be caught in the
1110 // left-side's funcEval implementation that will then clear the funcEval-abort-state from the thread.
1112 // If another thread also marked this one for a non-FuncEval abort, then the left-side will
1113 // proceed to [re]throw that exception post funcEval abort. When we come here next, we would follow
1114 // the usual rules to raise the exception and if raised, to prevent the abort if applicable.
1116 if (!IsFuncEvalAbort())
1118 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort prevent abort\n");
1123 // The thread requests not to be aborted. Honor this for safe abort.
1124 if (!IsRudeAbort() && IsAsyncPrevented())
1126 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort AsyncPrevented\n");
1130 // If we are doing safe abort, we can not abort a thread if it has locks.
1131 if (m_AbortType == EEPolicy::TA_Safe && HasLockInCurrentDomain()) {
1132 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort HasLock\n");
1138 Frame *pStartFrame = NULL;
1139 if (ThrewControlForThread() == Thread::InducedThreadRedirect ||
1140 ThrewControlForThread() == Thread::InducedThreadRedirectAtEndOfCatch)
1142 _ASSERTE(GetThread() == this);
1143 _ASSERTE(ExecutionManager::IsManagedCode(GetIP(m_OSContext)));
1144 FillRegDisplay(&rd, m_OSContext);
1146 if (ThrewControlForThread() == Thread::InducedThreadRedirectAtEndOfCatch)
1148 // On 64bit, this function may be called from COMPlusCheckForAbort when
1149 // stack has not unwound, but m_OSContext points to the place after unwind.
1151 TADDR sp = GetSP(m_OSContext);
1152 Frame *pFrameAddr = m_pFrame;
1153 while (pFrameAddr < (LPVOID)sp)
1155 pFrameAddr = pFrameAddr->Next();
1157 if (pFrameAddr != m_pFrame)
1159 pStartFrame = pFrameAddr;
1162 #if defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
1163 else if (ThrewControlForThread() == Thread::InducedThreadRedirect)
1165 if (!IsSafeToInjectThreadAbort(m_OSContext))
1167 STRESS_LOG0(LF_EH, LL_INFO10, "Thread::ReadyForAbort: Not injecting abort since we are at an unsafe instruction.\n");
1171 #endif // defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
1175 if (GetFilterContext())
1177 FillRegDisplay(&rd, GetFilterContext());
1184 FillRegDisplay(&rd, &ctx);
1190 if (StressLog::StressLogOn(~0u, 0))
1193 CopyRegDisplay(&rd, &rd1, &ctx1);
1197 // Walk the stack to determine if we are running in Constrained Execution Region or finally EH clause (in the non-rude abort
1198 // case). We cannot initiate an abort in these circumstances.
1199 StackCrawlContext TAContext =
1202 StackCrawlContext::SCC_CheckWithinCer | (IsRudeAbort() ? 0 : StackCrawlContext::SCC_CheckWithinEH),
1210 StackWalkFramesEx(&rd, TAStackCrawlCallBack, &TAContext, QUICKUNWIND, pStartFrame);
1212 if (!TAContext.fHasManagedCodeOnStack && IsAbortInitiated() && GetThread() == this)
1214 EEResetAbort(TAR_Thread);
1218 if (TAContext.fWithinCer)
1220 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort RunningCer\n");
1225 if (StressLog::StressLogOn(~0u, 0) &&
1226 (IsRudeAbort() || !TAContext.fWithinEHClause))
1228 //Save into stresslog.
1229 StackCrawlContext TAContext1 =
1232 StackCrawlContext::SCC_CheckWithinCer | (IsRudeAbort() ? 0 : StackCrawlContext::SCC_CheckWithinEH),
1240 StackWalkFramesEx(&rd1, TAStackCrawlCallBack, &TAContext1, QUICKUNWIND, pStartFrame);
1244 if (IsRudeAbort()) {
1245 // If it is rude abort, there is no additional restriction on abort.
1246 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort RudeAbort\n");
1250 if (TAContext.fWithinEHClause)
1252 STRESS_LOG0(LF_APPDOMAIN, LL_INFO10, "in Thread::ReadyForAbort RunningEHClause\n");
1255 //if (m_AbortType == EEPolicy::TA_V1Compatible) {
1259 // If we are running finally, we can not abort for Safe Abort.
1260 return !TAContext.fWithinEHClause;
1263 BOOL Thread::IsRudeAbort()
1272 return (IsAbortRequested() && (m_AbortType == EEPolicy::TA_Rude));
1275 BOOL Thread::IsRudeAbortOnlyForADUnload()
1283 return (IsAbortRequested() &&
1284 (m_AbortInfo & TAI_ADUnloadRudeAbort) &&
1285 !(m_AbortInfo & (TAI_ThreadRudeAbort | TAI_FuncEvalRudeAbort))
1289 BOOL Thread::IsRudeUnload()
1297 return (IsAbortRequested() && (m_AbortInfo & TAI_ADUnloadRudeAbort));
1300 BOOL Thread::IsFuncEvalAbort()
1308 return (IsAbortRequested() && (m_AbortInfo & TAI_AnyFuncEvalAbort));
1312 // If the OS is down in kernel mode when we do a GetThreadContext,any
1313 // updates we make to the context will not take effect if we try to do
1314 // a SetThreadContext. As a result, newer OSes expose the idea of
1315 // "trap frame reporting" which will tell us if it is unsafe to modify
1316 // the context and pass it along to SetThreadContext.
1318 // On OSes that support trap frame reporting, we will return FALSE if
1319 // we can determine that the OS is not in user mode. Otherwise, we
1322 BOOL Thread::IsContextSafeToRedirect(CONTEXT* pContext)
1332 BOOL isSafeToRedirect = TRUE;
1336 #if !defined(_TARGET_X86_)
1337 // In some cases (x86 WOW64, ARM32 on ARM64) Windows will not set the CONTEXT_EXCEPTION_REPORTING flag
1338 // if the thread is executing in kernel mode (i.e. in the middle of a syscall or exception handling).
1339 // Therefore, we should treat the absence of the CONTEXT_EXCEPTION_REPORTING flag as an indication that
1340 // it is not safe to manipulate with the current state of the thread context.
1341 // Note: the x86 WOW64 case is already handled in GetSafelyRedirectableThreadContext; in addition, this
1342 // flag is never set on Windows7 x86 WOW64. So this check is valid for non-x86 architectures only.
1343 isSafeToRedirect = (pContext->ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0;
1344 #endif // !defined(_TARGET_X86_)
1346 if (pContext->ContextFlags & CONTEXT_EXCEPTION_REPORTING)
1348 if (pContext->ContextFlags & (CONTEXT_SERVICE_ACTIVE|CONTEXT_EXCEPTION_ACTIVE))
1350 // cannot process exception
1351 LOG((LF_ALWAYS, LL_WARNING, "thread [os id=0x08%x id=0x08%x] redirect failed due to ContextFlags of 0x%08x\n", m_OSThreadId, m_ThreadId, pContext->ContextFlags));
1352 isSafeToRedirect = FALSE;
1356 #endif // !FEATURE_PAL
1358 return isSafeToRedirect;
1361 void Thread::SetAbortEndTime(ULONGLONG endTime, BOOL fRudeAbort)
1363 LIMITED_METHOD_CONTRACT;
1366 AbortRequestLockHolder lh(this);
1369 if (endTime < m_RudeAbortEndTime)
1371 m_RudeAbortEndTime = endTime;
1376 if (endTime < m_AbortEndTime)
1378 m_AbortEndTime = endTime;
1386 #pragma warning(push)
1387 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1390 Thread::UserAbort(ThreadAbortRequester requester,
1391 EEPolicy::ThreadAbortTypes abortType,
1393 UserAbort_Client client
1399 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
1403 STRESS_LOG2(LF_SYNC | LF_APPDOMAIN, LL_INFO100, "UserAbort Thread %p Thread Id = %x\n", this, GetThreadId());
1405 AddFiberInfo(ThreadTrackInfo_Abort);
1408 BOOL fHoldingThreadStoreLock = ThreadStore::HoldingThreadStore();
1410 // For SafeAbort from FuncEval abort, we do not apply escalation policy. Debugger
1411 // tries SafeAbort first with a short timeout. The thread will return to debugger.
1412 // After some break, the thread is going to do RudeAbort if abort has not finished.
1413 EClrOperation operation;
1414 if (abortType == EEPolicy::TA_Rude)
1416 if (HasLockInCurrentDomain())
1418 operation = OPR_ThreadRudeAbortInCriticalRegion;
1422 operation = OPR_ThreadRudeAbortInNonCriticalRegion;
1427 operation = OPR_ThreadAbort;
1430 // Debugger func-eval aborts (both rude + normal) don't have any escalation policy. They are invoked
1431 // by the debugger and the debugger handles the consequences.
1432 // Furthermore, in interop-debugging, threads will be hard-suspened in preemptive mode while we try to abort them.
1433 // So any abort strategy that relies on a timeout and the target thread slipping is dangerous. Escalation policy would let a
1434 // host circumvent the timeout and thus we may wait forever for the target thread to slip. We'd deadlock here. Since the escalation
1435 // policy doesn't let the host break this deadlock (and certianly doesn't let the debugger break the deadlock), it's unsafe
1436 // to have an escalation policy for func-eval aborts at all.
1437 BOOL fEscalation = (requester != TAR_FuncEval);
1440 EPolicyAction action = GetEEPolicy()->GetDefaultAction(operation, this);
1444 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
1446 case eRudeAbortThread:
1447 if (abortType != EEPolicy::TA_Rude)
1449 abortType = EEPolicy::TA_Rude;
1451 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
1453 case eUnloadAppDomain:
1455 AppDomain *pDomain = GetDomain();
1456 if (!pDomain->IsDefaultDomain())
1458 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
1459 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
1462 // AD unload does not abort finalizer thread.
1463 if (this != FinalizerThread::GetFinalizerThread())
1465 if (this == GetThread())
1467 Join(INFINITE,TRUE);
1472 case eRudeUnloadAppDomain:
1474 AppDomain *pDomain = GetDomain();
1475 if (!pDomain->IsDefaultDomain())
1477 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
1478 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
1481 // AD unload does not abort finalizer thread.
1482 if (this != FinalizerThread::GetFinalizerThread())
1484 if (this == GetThread())
1486 Join(INFINITE,TRUE);
1492 case eFastExitProcess:
1493 case eRudeExitProcess:
1494 case eDisableRuntime:
1495 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
1496 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT);
1497 _ASSERTE (!"Should not reach here");
1500 _ASSERTE (!"unknown policy for thread abort");
1503 DWORD timeoutFromPolicy;
1504 if (abortType != EEPolicy::TA_Rude)
1506 timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadAbort);
1508 else if (!HasLockInCurrentDomain())
1510 timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInNonCriticalRegion);
1514 timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion);
1516 if (timeout > timeoutFromPolicy)
1518 timeout = timeoutFromPolicy;
1522 AbortControlHolder AbortController(this);
1525 if (timeout != INFINITE)
1527 ULONG64 curTime = CLRGetTickCount64();
1528 ULONG64 newEndTime = curTime + timeout;
1530 SetAbortEndTime(newEndTime, abortType == EEPolicy::TA_Rude);
1533 // If the abort comes from the thread abort watchdog, proceed with the abort only
1534 // if the abort is still requested. This handles race between watchdog and UnmarkThreadForAbort.
1535 BOOL fTentative = (requester == Thread::TAR_Thread) && (client == UAC_WatchDog);
1536 MarkThreadForAbort(requester, abortType, fTentative);
1538 Thread *pCurThread = GetThread();
1541 if (this == pCurThread)
1543 SetAbortInitiated();
1548 if (CLRHosted() && GetAbortEndTime() != MAXULONGLONG)
1550 // ToDo: Skip debugger funcval
1551 // Use our helper thread to watch abort.
1552 AppDomain::EnableADUnloadWorkerForThreadAbort();
1557 OBJECTREF exceptObj;
1561 exceptObj = CLRException::GetPreallocatedRudeThreadAbortException();
1565 EEException eeExcept(kThreadAbortException);
1566 exceptObj = CLRException::GetThrowableFromException(&eeExcept);
1569 RaiseTheExceptionInternalOnly(exceptObj, FALSE);
1572 #ifdef MDA_SUPPORTED
1573 if (requester != TAR_FuncEval)
1575 // FuncEval abort is always aborting another thread. No need to trigger MDA.
1576 MDA_TRIGGER_ASSISTANT(AsynchronousThreadAbort, ReportViolation(GetThread(), this));
1580 _ASSERTE(this != pCurThread); // Aborting another thread.
1582 if (client == UAC_Host)
1584 // A host may call ICLRTask::Abort on a critical thread. We don't want to
1585 // block this thread.
1586 AppDomain::EnableADUnloadWorkerForThreadAbort();
1591 DWORD elapsed_time = 0;
1594 // We do not want this thread to be alerted.
1595 ThreadPreventAsyncHolder preventAsync(pCurThread != NULL);
1598 // If UserAbort times out, put up msgbox once.
1599 BOOL fAlreadyAssert = FALSE;
1602 BOOL fOneTryOnly = (client == UAC_WatchDog) || (client == UAC_FinalizerTimeout);
1603 BOOL fFirstRun = TRUE;
1604 BOOL fNeedEscalation;
1606 #if !defined(DISABLE_THREADSUSPEND)
1607 DWORD dwSwitchCount = 0;
1608 #endif // !defined(DISABLE_THREADSUSPEND)
1611 fNeedEscalation = FALSE;
1622 // Lock the thread store
1623 LOG((LF_SYNC, INFO3, "UserAbort obtain lock\n"));
1625 ULONGLONG abortEndTime = GetAbortEndTime();
1626 if (abortEndTime != MAXULONGLONG)
1628 ULONGLONG now_time = CLRGetTickCount64();
1630 if (now_time >= abortEndTime)
1632 EPolicyAction action1 = eNoAction;
1633 DWORD timeout1 = INFINITE;
1638 action1 = GetEEPolicy()->GetActionOnTimeout(OPR_ThreadAbort, this);
1639 timeout1 = GetEEPolicy()->GetTimeout(OPR_ThreadAbort);
1641 else if (HasLockInCurrentDomain())
1643 action1 = GetEEPolicy()->GetActionOnTimeout(OPR_ThreadRudeAbortInCriticalRegion, this);
1644 timeout1 = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion);
1648 action1 = GetEEPolicy()->GetActionOnTimeout(OPR_ThreadRudeAbortInNonCriticalRegion, this);
1649 timeout1 = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInNonCriticalRegion);
1652 if (action1 == eNoAction)
1654 // timeout, but no action on timeout.
1655 // Debugger can call this function to about func-eval with a timeout
1656 return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
1658 if (timeout1 != INFINITE)
1660 // There is an escalation policy.
1661 fNeedEscalation = TRUE;
1667 // Thread abort needs to walk stack to decide if thread abort can proceed.
1668 // It is unsafe to crawl a stack of thread if the thread is OS-suspended which we do during
1669 // thread abort. For example, Thread T1 aborts thread T2. T2 is suspended by T1. Inside SQL
1670 // this means that no thread sharing the same scheduler with T2 can run. If T1 needs a lock which
1671 // is owned by one thread on the scheduler, T1 will wait forever.
1672 // Our solution is to move T2 to a safe point, resume it, and then do stack crawl.
1674 // We need to make sure that ThreadStoreLock is released after CheckForAbort. This makes sure
1675 // that ThreadAbort does not race against GC.
1680 BOOL m_fHoldingThreadStoreLock;
1683 CheckForAbort(Thread *pThread, BOOL fHoldingThreadStoreLock)
1684 : m_pThread(pThread),
1685 m_fHoldingThreadStoreLock(fHoldingThreadStoreLock),
1688 if (!fHoldingThreadStoreLock)
1690 ThreadSuspend::LockThreadStore(ThreadSuspend::SUSPEND_OTHER);
1692 ThreadStore::ResetStackCrawlEvent();
1694 // The thread being aborted may clear the TS_AbortRequested bit and the matching increment
1695 // of g_TrapReturningThreads behind our back. Increment g_TrapReturningThreads here
1696 // to ensure that we stop for the stack crawl even if the TS_AbortRequested bit is cleared.
1697 ThreadStore::TrapReturningThreads(TRUE);
1699 void NeedStackCrawl()
1701 m_pThread->SetThreadState(Thread::TS_StackCrawlNeeded);
1711 m_NeedRelease = FALSE;
1712 ThreadStore::TrapReturningThreads(FALSE);
1713 ThreadStore::SetStackCrawlEvent();
1714 m_pThread->ResetThreadState(TS_StackCrawlNeeded);
1715 if (!m_fHoldingThreadStoreLock)
1717 ThreadSuspend::UnlockThreadStore();
1722 CheckForAbort checkForAbort(this, fHoldingThreadStoreLock);
1724 // We own TS lock. The state of the Thread can not be changed.
1725 if (m_State & TS_Unstarted)
1727 // This thread is not yet started.
1731 if(requester == Thread::TAR_Thread)
1736 if (GetThreadHandle() == INVALID_HANDLE_VALUE &&
1737 (m_State & TS_Unstarted) == 0)
1739 // The thread is going to die or is already dead.
1740 UnmarkThreadForAbort(Thread::TAR_ALL);
1744 if(requester == Thread::TAR_Thread)
1749 // What if someone else has this thread suspended already? It'll depend where the
1750 // thread got suspended.
1753 // We'll just set the abort bit and hope for the best on the resume.
1756 // If it's suspended in jitted code, we'll hijack the IP.
1757 // <REVISIT_TODO> Consider race w/ GC suspension</REVISIT_TODO>
1758 // If it's suspended but not in jitted code, we'll get suspended for GC, the GC
1759 // will complete, and then we'll abort the target thread.
1762 // It's possible that the thread has completed the abort already.
1764 if (!(m_State & TS_AbortRequested))
1769 if(requester == Thread::TAR_Thread)
1774 // If a thread is Dead or Detached, abort is a NOP.
1776 if (m_State & (TS_Dead | TS_Detached | TS_TaskReset))
1778 UnmarkThreadForAbort(Thread::TAR_ALL);
1779 if(requester == Thread::TAR_Thread)
1787 // It's possible that some stub notices the AbortRequested bit -- even though we
1788 // haven't done any real magic yet. If the thread has already started it's abort, we're
1791 // Two more cases can be folded in here as well. If the thread is unstarted, it'll
1792 // abort when we start it.
1794 // If the thread is user suspended (SyncSuspended) -- we're out of luck. Set the bit and
1795 // hope for the best on resume.
1797 if ((m_State & TS_AbortInitiated) && !IsRudeAbort())
1805 BOOL fOutOfRuntime = FALSE;
1806 BOOL fNeedStackCrawl = FALSE;
1808 #ifdef DISABLE_THREADSUSPEND
1809 // On platforms that do not support safe thread suspension we have to
1810 // rely on the GCPOLL mechanism; the mechanism is activated above by
1811 // TrapReturningThreads. However when reading shared state we need
1812 // to erect appropriate memory barriers. So the interlocked operation
1813 // below ensures that any future reads on this thread will happen after
1814 // any earlier writes on a different thread have taken effect.
1815 FastInterlockOr((DWORD*)&m_State, 0);
1817 #else // DISABLE_THREADSUSPEND
1819 // Win32 suspend the thread, so it isn't moving under us.
1820 SuspendThreadResult str = SuspendThread();
1827 case STR_UnstartedOrDead:
1828 case STR_NoStressLog:
1829 checkForAbort.Release();
1830 __SwitchToThread(0, ++dwSwitchCount);
1833 case STR_SwitchedOut:
1834 // If the thread is in preemptive gc mode, we can erect a barrier to block the
1835 // thread to return to cooperative mode. Then we can do stack crawl and make decision.
1836 if (!m_fPreemptiveGCDisabled)
1838 checkForAbort.NeedStackCrawl();
1839 if (GetThreadHandle() != SWITCHOUT_HANDLE_VALUE || m_fPreemptiveGCDisabled)
1841 checkForAbort.Release();
1842 __SwitchToThread(0, ++dwSwitchCount);
1859 _ASSERTE(str == STR_Success);
1861 #endif // DISABLE_THREADSUSPEND
1863 // It's possible that the thread has completed the abort already.
1865 if (!(m_State & TS_AbortRequested))
1867 #ifndef DISABLE_THREADSUSPEND
1870 if(requester == Thread::TAR_Thread)
1873 m_dwAbortPoint = 63;
1878 // Check whether some stub noticed the AbortRequested bit in-between our test above
1879 // and us suspending the thread.
1880 if ((m_State & TS_AbortInitiated) && !IsRudeAbort())
1882 #ifndef DISABLE_THREADSUSPEND
1886 m_dwAbortPoint = 65;
1891 // If Threads is stopped under a managed debugger, it will have both
1892 // TS_DebugSuspendPending and TS_SyncSuspended, regardless of whether
1893 // the thread is actually suspended or not.
1894 // If it's suspended w/o the debugger (eg, by via Thread.Suspend), it will
1895 // also have TS_UserSuspendPending set.
1896 if (m_State & TS_SyncSuspended)
1898 #ifndef DISABLE_THREADSUSPEND
1901 checkForAbort.Release();
1906 // CoreCLR does not support user-requested thread suspension
1907 _ASSERTE(!(m_State & TS_UserSuspendPending));
1910 // If it's stopped by the debugger, we don't want to throw an exception.
1911 // Debugger suspension is to have no effect of the runtime behaviour.
1913 if (m_State & TS_DebugSuspendPending)
1918 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_ABORT_WHILE_SUSPEND);
1921 // If the thread has no managed code on it's call stack, abort is a NOP. We're about
1922 // to touch the unmanaged thread's stack -- for this to be safe, we can't be
1923 // Dead/Detached/Unstarted.
1925 _ASSERTE(!(m_State & ( TS_Dead
1929 #if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
1930 // TODO WIN64: consider this if there is a way to detect of managed code on stack.
1931 if ((m_pFrame == FRAME_TOP)
1932 && (GetFirstCOMPlusSEHRecord(this) == EXCEPTION_CHAIN_END)
1935 #ifndef DISABLE_THREADSUSPEND
1942 if(requester == Thread::TAR_Thread)
1946 #endif // _TARGET_X86_
1949 if (!m_fPreemptiveGCDisabled)
1951 if ((m_pFrame != FRAME_TOP) && m_pFrame->IsTransitionToNativeFrame()
1952 #if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
1953 && ((size_t) GetFirstCOMPlusSEHRecord(this) > ((size_t) m_pFrame) - 20)
1954 #endif // _TARGET_X86_
1957 fOutOfRuntime = TRUE;
1961 checkForAbort.NeedStackCrawl();
1962 if (!m_fPreemptiveGCDisabled)
1964 fNeedStackCrawl = TRUE;
1966 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
1969 HandleJITCaseForAbort();
1971 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
1973 #ifndef DISABLE_THREADSUSPEND
1974 // The thread is not suspended now.
1978 if (!fNeedStackCrawl)
1983 #ifndef DISABLE_THREADSUSPEND
1985 #endif // DISABLE_THREADSUSPEND
1987 if (!ReadyForAbort()) {
1991 // !!! Check for Exception in flight should happen before induced thread abort.
1992 // !!! ReadyForAbort skips catch and filter clause.
1994 // If an exception is currently being thrown, one of two things will happen. Either, we'll
1995 // catch, and notice the abort request in our end-catch, or we'll not catch [in which case
1996 // we're leaving managed code anyway. The top-most handler is responsible for resetting
1999 if (HasException() &&
2000 // For rude abort, we will initiated abort
2009 // If the thread is in sleep, wait, or join interrupt it
2010 // However, we do NOT want to interrupt if the thread is already processing an exception
2011 if (m_State & TS_Interruptible)
2013 UserInterrupt(TI_Abort); // if the user wakes up because of this, it will read the
2014 // abort requested bit and initiate the abort
2016 m_dwAbortPoint = 10;
2023 // If the thread is running outside the EE, and is behind a stub that's going
2026 m_dwAbortPoint = 11;
2031 // Ok. It's not in managed code, nor safely out behind a stub that's going to catch
2032 // it on the way in. We have to poll.
2036 checkForAbort.Release();
2043 // Don't do a Sleep. It's possible that the thread we are trying to abort is
2044 // stuck in unmanaged code trying to get into the apartment that we are supposed
2045 // to be pumping! Instead, ping the current thread's handle. Obviously this
2046 // will time out, but it will pump if we need it to.
2049 pCurThread->Join(ABORT_POLL_TIMEOUT, TRUE);
2053 ClrSleepEx(ABORT_POLL_TIMEOUT, FALSE);
2058 elapsed_time += ABORT_POLL_TIMEOUT;
2059 if (g_pConfig->GetGCStressLevel() == 0 && !fAlreadyAssert)
2061 _ASSERTE(elapsed_time < ABORT_FAIL_TIMEOUT);
2062 fAlreadyAssert = TRUE;
2068 if (fOneTryOnly && !fNeedEscalation)
2073 if ((GetAbortEndTime() != MAXULONGLONG) && IsAbortRequested())
2077 if (!IsAbortRequested())
2081 ULONGLONG curTime = CLRGetTickCount64();
2082 if (curTime >= GetAbortEndTime())
2089 pCurThread->Join(100, TRUE);
2093 ClrSleepEx(100, FALSE);
2098 if (IsAbortRequested() && fEscalation)
2100 EPolicyAction action1;
2101 EClrOperation operation1;
2104 operation1 = OPR_ThreadAbort;
2106 else if (HasLockInCurrentDomain())
2108 operation1 = OPR_ThreadRudeAbortInCriticalRegion;
2112 operation1 = OPR_ThreadRudeAbortInNonCriticalRegion;
2114 action1 = GetEEPolicy()->GetActionOnTimeout(operation1, this);
2117 case eRudeAbortThread:
2118 GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
2119 MarkThreadForAbort(requester, EEPolicy::TA_Rude);
2120 SetRudeAbortEndTimeFromEEPolicy();
2122 case eUnloadAppDomain:
2124 AppDomain *pDomain = GetDomain();
2125 if (!pDomain->IsDefaultDomain())
2127 GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
2128 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
2131 // AD unload does not abort finalizer thread.
2132 if (this == FinalizerThread::GetFinalizerThread())
2134 GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
2135 MarkThreadForAbort(requester, EEPolicy::TA_Rude);
2136 SetRudeAbortEndTimeFromEEPolicy();
2141 if (this == GetThread())
2143 Join(INFINITE,TRUE);
2148 case eRudeUnloadAppDomain:
2150 AppDomain *pDomain = GetDomain();
2151 if (!pDomain->IsDefaultDomain())
2153 GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
2154 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
2157 // AD unload does not abort finalizer thread.
2158 if (this == FinalizerThread::GetFinalizerThread())
2160 MarkThreadForAbort(requester, EEPolicy::TA_Rude);
2161 SetRudeAbortEndTimeFromEEPolicy();
2166 if (this == GetThread())
2168 Join(INFINITE,TRUE);
2174 case eFastExitProcess:
2175 case eRudeExitProcess:
2176 case eDisableRuntime:
2177 GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
2178 EEPolicy::HandleExitProcessFromEscalation(action1, HOST_E_EXITPROCESS_TIMEOUT);
2179 _ASSERTE (!"Should not reach here");
2186 return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
2189 if(requester == Thread::TAR_Thread)
2194 #pragma warning(pop)
2197 void Thread::SetRudeAbortEndTimeFromEEPolicy()
2199 LIMITED_METHOD_CONTRACT;
2201 DWORD timeout = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion);
2203 ULONGLONG newEndTime;
2204 if (timeout == INFINITE)
2206 newEndTime = MAXULONGLONG;
2210 newEndTime = CLRGetTickCount64() + timeout;
2213 SetAbortEndTime(newEndTime, TRUE);
2216 ULONGLONG Thread::s_NextSelfAbortEndTime = MAXULONGLONG;
2218 void Thread::ThreadAbortWatchDogAbort(Thread *pThread)
2223 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
2227 EEPolicy::ThreadAbortTypes abortType = EEPolicy::TA_Safe;
2228 if (pThread->m_AbortInfo & TAI_ThreadRudeAbort)
2230 abortType = EEPolicy::TA_Rude;
2232 else if (pThread->m_AbortInfo & TAI_ThreadV1Abort)
2234 abortType = EEPolicy::TA_V1Compatible;
2236 else if (pThread->m_AbortInfo & TAI_ThreadAbort)
2238 abortType = EEPolicy::TA_Safe;
2247 pThread->UserAbort(Thread::TAR_Thread, abortType, INFINITE, Thread::UAC_WatchDog);
2252 EX_END_CATCH(SwallowAllExceptions);
2255 void Thread::ThreadAbortWatchDogEscalate(Thread *pThread)
2260 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
2264 EPolicyAction action = eNoAction;
2265 EClrOperation operation = OPR_ThreadRudeAbortInNonCriticalRegion;
2266 if (!pThread->IsRudeAbort())
2268 operation = OPR_ThreadAbort;
2270 else if (pThread->HasLockInCurrentDomain())
2272 operation = OPR_ThreadRudeAbortInCriticalRegion;
2276 operation = OPR_ThreadRudeAbortInNonCriticalRegion;
2278 action = GetEEPolicy()->GetActionOnTimeout(operation, pThread);
2279 // We only support escalation to rude abort
2284 case eRudeAbortThread:
2285 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
2286 pThread->UserAbort(Thread::TAR_Thread, EEPolicy::TA_Rude, INFINITE, Thread::UAC_WatchDog);
2288 case eUnloadAppDomain:
2290 AppDomain *pDomain = pThread->GetDomain();
2291 if (!pDomain->IsDefaultDomain())
2293 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
2294 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
2298 case eRudeUnloadAppDomain:
2300 AppDomain *pDomain = pThread->GetDomain();
2301 if (!pDomain->IsDefaultDomain())
2303 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
2304 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
2309 case eFastExitProcess:
2310 case eRudeExitProcess:
2311 case eDisableRuntime:
2312 // HandleExitProcessFromEscalation will try to grab ThreadStore again.
2313 _ASSERTE (ThreadStore::HoldingThreadStore());
2314 ThreadStore::UnlockThreadStore();
2315 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
2316 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT);
2317 _ASSERTE (!"Should not reach here");
2322 _ASSERTE (!"unknown policy for thread abort");
2327 EX_END_CATCH(SwallowAllExceptions);
2330 // If a thread is self-aborted and has a timeout, we need to watch the thread
2331 void Thread::ThreadAbortWatchDog()
2336 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
2342 ThreadStoreLockHolder tsLock;
2344 ULONGLONG curTime = CLRGetTickCount64();
2346 s_NextSelfAbortEndTime = MAXULONGLONG;
2348 Thread *thread = NULL;
2349 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
2351 if (!thread->IsAbortRequested())
2356 if (thread == FinalizerThread::GetFinalizerThread() && !g_FinalizerIsRunning)
2358 // if finalizer method is not running, don't try to abort the finalizer thread
2362 BOOL fNeedsToInitiateAbort = !thread->IsAbortInitiated() || thread->IsRudeAbort();
2363 ULONGLONG endTime = thread->GetAbortEndTime();
2364 if (fNeedsToInitiateAbort)
2366 s_NextSelfAbortEndTime = 0;
2368 else if (endTime < s_NextSelfAbortEndTime)
2370 s_NextSelfAbortEndTime = endTime;
2373 if (thread->m_AbortController == 0)
2375 STRESS_LOG3(LF_ALWAYS, LL_ALWAYS, "ThreadAbortWatchDog for Thread %p Thread Id = %x with timeout %x\n",
2376 thread, thread->GetThreadId(), endTime);
2378 if (endTime != MAXULONGLONG && curTime >= endTime)
2380 ThreadAbortWatchDogEscalate(thread);
2382 else if (fNeedsToInitiateAbort)
2384 ThreadAbortWatchDogAbort(thread);
2391 void Thread::LockAbortRequest(Thread* pThread)
2393 WRAPPER_NO_CONTRACT;
2395 DWORD dwSwitchCount = 0;
2398 for (unsigned i = 0; i < 10000; i ++) {
2399 if (VolatileLoad(&(pThread->m_AbortRequestLock)) == 0) {
2402 YieldProcessor(); // indicate to the processor that we are spinning
2404 if (FastInterlockCompareExchange(&(pThread->m_AbortRequestLock),1,0) == 0) {
2407 __SwitchToThread(0, ++dwSwitchCount);
2411 void Thread::UnlockAbortRequest(Thread *pThread)
2413 LIMITED_METHOD_CONTRACT;
2415 _ASSERTE (pThread->m_AbortRequestLock == 1);
2416 FastInterlockExchange(&pThread->m_AbortRequestLock, 0);
2419 void Thread::MarkThreadForAbort(ThreadAbortRequester requester, EEPolicy::ThreadAbortTypes abortType, BOOL fTentative /*=FALSE*/)
2428 _ASSERTE ((requester & TAR_StackOverflow) == 0 || (requester & TAR_Thread) == TAR_Thread);
2430 AbortRequestLockHolder lh(this);
2434 if (!IsAbortRequested())
2436 STRESS_LOG0(LF_SYNC, LL_INFO1000, "Tentative thread abort abandoned\n");
2442 if (abortType == EEPolicy::TA_Rude)
2444 m_fRudeAborted = TRUE;
2448 DWORD abortInfo = 0;
2450 if (requester & TAR_Thread)
2452 if (abortType == EEPolicy::TA_Safe)
2454 abortInfo |= TAI_ThreadAbort;
2456 else if (abortType == EEPolicy::TA_Rude)
2458 abortInfo |= TAI_ThreadRudeAbort;
2460 else if (abortType == EEPolicy::TA_V1Compatible)
2462 abortInfo |= TAI_ThreadV1Abort;
2466 if (requester & TAR_ADUnload)
2468 if (abortType == EEPolicy::TA_Safe)
2470 abortInfo |= TAI_ADUnloadAbort;
2472 else if (abortType == EEPolicy::TA_Rude)
2474 abortInfo |= TAI_ADUnloadRudeAbort;
2476 else if (abortType == EEPolicy::TA_V1Compatible)
2478 abortInfo |= TAI_ADUnloadV1Abort;
2480 if (IsADUnloadHelperThread())
2482 abortInfo |= TAI_ForADUnloadThread;
2486 if (requester & TAR_FuncEval)
2488 if (abortType == EEPolicy::TA_Safe)
2490 abortInfo |= TAI_FuncEvalAbort;
2492 else if (abortType == EEPolicy::TA_Rude)
2494 abortInfo |= TAI_FuncEvalRudeAbort;
2496 else if (abortType == EEPolicy::TA_V1Compatible)
2498 abortInfo |= TAI_FuncEvalV1Abort;
2504 ASSERT(!"Invalid abort information");
2508 if (requester == TAR_Thread)
2510 DWORD timeoutFromPolicy;
2511 if (abortType != EEPolicy::TA_Rude)
2513 timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadAbort);
2515 else if (!HasLockInCurrentDomain())
2517 timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInNonCriticalRegion);
2521 timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion);
2523 if (timeoutFromPolicy != INFINITE)
2525 ULONGLONG endTime = CLRGetTickCount64() + timeoutFromPolicy;
2526 if (abortType != EEPolicy::TA_Rude)
2528 if (endTime < m_AbortEndTime)
2530 m_AbortEndTime = endTime;
2533 else if (endTime < m_RudeAbortEndTime)
2535 m_RudeAbortEndTime = endTime;
2537 // We can not call into host if we are in the middle of stack overflow.
2538 // And we don't need to wake up our watchdog if there is no timeout.
2539 if (GetThread() == this && (requester & TAR_StackOverflow) == 0)
2541 AppDomain::EnableADUnloadWorkerForThreadAbort();
2546 if (abortInfo == (m_AbortInfo & abortInfo))
2549 // We are already doing this kind of abort.
2554 m_AbortInfo |= abortInfo;
2556 if (m_AbortType >= (DWORD)abortType)
2558 // another thread is aborting at a higher level
2562 m_AbortType = abortType;
2564 if (!IsAbortRequested())
2566 // We must set this before we start flipping thread bits to avoid races where
2567 // trap returning threads is already high due to other reasons.
2569 // The thread is asked for abort the first time
2570 SetAbortRequestBit();
2573 AddFiberInfo(ThreadTrackInfo_Abort);
2576 STRESS_LOG4(LF_APPDOMAIN, LL_ALWAYS, "Mark Thread %p Thread Id = %x for abort from requester %d (type %d)\n", this, GetThreadId(), requester, abortType);
2579 void Thread::SetAbortRequestBit()
2581 WRAPPER_NO_CONTRACT;
2584 Volatile<LONG> curValue = (LONG)m_State;
2585 if ((curValue & TS_AbortRequested) != 0)
2589 if (FastInterlockCompareExchange((LONG*)&m_State, curValue|TS_AbortRequested, curValue) == curValue)
2591 ThreadStore::TrapReturningThreads(TRUE);
2598 void Thread::RemoveAbortRequestBit()
2606 // There's a race between removing the TS_AbortRequested bit and decrementing g_TrapReturningThreads
2607 // We may remove the bit, but before we have a chance to call ThreadStore::TrapReturningThreads(FALSE)
2608 // DbgFindThread() may execute, and find too few threads with the bit set.
2609 // To ensure the assert in DbgFindThread does not fire under such a race we set the ChgInFlight before hand.
2610 CounterHolder trtHolder(&g_trtChgInFlight);
2614 Volatile<LONG> curValue = (LONG)m_State;
2615 if ((curValue & TS_AbortRequested) == 0)
2619 if (FastInterlockCompareExchange((LONG*)&m_State, curValue&(~TS_AbortRequested), curValue) == curValue)
2621 ThreadStore::TrapReturningThreads(FALSE);
2628 // Make sure that when AbortRequest bit is cleared, we also dec TrapReturningThreads count.
2629 void Thread::UnmarkThreadForAbort(ThreadAbortRequester requester, BOOL fForce)
2638 // Switch to COOP (for ClearAbortReason) before acquiring AbortRequestLock
2641 AbortRequestLockHolder lh(this);
2644 // Unmark the bits that are being turned off
2646 if (requester & TAR_Thread)
2648 if ((m_AbortInfo != TAI_ThreadRudeAbort) || fForce)
2650 m_AbortInfo &= ~(TAI_ThreadAbort |
2652 TAI_ThreadRudeAbort );
2657 ClearAbortReason(TRUE);
2661 if (requester & TAR_ADUnload)
2663 m_AbortInfo &= ~(TAI_ADUnloadAbort |
2664 TAI_ADUnloadV1Abort |
2665 TAI_ADUnloadRudeAbort);
2668 if (requester & TAR_FuncEval)
2670 m_AbortInfo &= ~(TAI_FuncEvalAbort |
2671 TAI_FuncEvalV1Abort |
2672 TAI_FuncEvalRudeAbort);
2676 // Decide which type of abort to do based on the new bit field.
2678 if (m_AbortInfo & TAI_AnyRudeAbort)
2680 m_AbortType = EEPolicy::TA_Rude;
2682 else if (m_AbortInfo & TAI_AnyV1Abort)
2684 m_AbortType = EEPolicy::TA_V1Compatible;
2686 else if (m_AbortInfo & TAI_AnySafeAbort)
2688 m_AbortType = EEPolicy::TA_Safe;
2692 m_AbortType = EEPolicy::TA_None;
2696 // If still aborting, do nothing
2698 if (m_AbortType != EEPolicy::TA_None)
2703 m_AbortEndTime = MAXULONGLONG;
2704 m_RudeAbortEndTime = MAXULONGLONG;
2706 if (IsAbortRequested())
2708 RemoveAbortRequestBit();
2709 FastInterlockAnd((DWORD*)&m_State,~(TS_AbortInitiated));
2710 m_fRudeAbortInitiated = FALSE;
2711 ResetUserInterrupted();
2714 AddFiberInfo(ThreadTrackInfo_Abort);
2718 STRESS_LOG3(LF_APPDOMAIN, LL_ALWAYS, "Unmark Thread %p Thread Id = %x for abort from requester %d\n", this, GetThreadId(), requester);
2721 // Make sure that when AbortRequest bit is cleared, we also dec TrapReturningThreads count.
2722 void Thread::ResetBeginAbortedForADUnload()
2731 AbortRequestLockHolder lh(this);
2733 m_AbortInfo &= ~TAI_ForADUnloadThread;
2736 void Thread::InternalResetAbort(ThreadAbortRequester requester, BOOL fResetRudeAbort)
2744 _ASSERTE(this == GetThread());
2745 _ASSERTE(!IsDead());
2747 // managed code can not reset Rude thread abort
2748 UnmarkThreadForAbort(requester, fResetRudeAbort);
2750 AddFiberInfo(ThreadTrackInfo_Abort);
2755 // Throw a thread abort request when a suspended thread is resumed. Make sure you know what you
2756 // are doing when you call this routine.
2757 void Thread::SetAbortRequest(EEPolicy::ThreadAbortTypes abortType)
2765 MarkThreadForAbort(TAR_ADUnload, abortType);
2767 if (m_State & TS_Interruptible)
2769 UserInterrupt(TI_Abort);
2774 void ThreadSuspend::LockThreadStore(ThreadSuspend::SUSPEND_REASON reason)
2778 if ((GetThread() != NULL) && GetThread()->PreemptiveGCDisabled()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
2782 // There's a nasty problem here. Once we start shutting down because of a
2783 // process detach notification, threads are disappearing from under us. There
2784 // are a surprising number of cases where the dying thread holds the ThreadStore
2785 // lock. For example, the finalizer thread holds this during startup in about
2786 // 10 of our COM BVTs.
2787 if (!IsAtProcessExit())
2789 BOOL gcOnTransitions;
2791 Thread *pCurThread = GetThread();
2793 gcOnTransitions = GC_ON_TRANSITIONS(FALSE); // dont do GC for GCStress 3
2795 BOOL toggleGC = ( pCurThread != NULL
2796 && pCurThread->PreemptiveGCDisabled()
2797 && reason != ThreadSuspend::SUSPEND_FOR_GC);
2799 // Note: there is logic in gc.cpp surrounding suspending all
2800 // runtime threads for a GC that depends on the fact that we
2801 // do an EnablePreemptiveGC and a DisablePreemptiveGC around
2802 // taking this lock.
2804 pCurThread->EnablePreemptiveGC();
2806 LOG((LF_SYNC, INFO3, "Locking thread store\n"));
2808 // Any thread that holds the thread store lock cannot be stopped by unmanaged breakpoints and exceptions when
2809 // we're doing managed/unmanaged debugging. Calling SetDebugCantStop(true) on the current thread helps us
2812 pCurThread->SetDebugCantStop(true);
2814 // This is used to avoid thread starvation if non-GC threads are competing for
2815 // the thread store lock when there is a real GC-thread waiting to get in.
2816 // This is initialized lazily when the first non-GC thread backs out because of
2817 // a waiting GC thread.
2818 if (s_hAbortEvt != NULL &&
2819 !(reason == ThreadSuspend::SUSPEND_FOR_GC ||
2820 reason == ThreadSuspend::SUSPEND_FOR_GC_PREP ||
2821 reason == ThreadSuspend::SUSPEND_FOR_DEBUGGER_SWEEP) &&
2822 m_pThreadAttemptingSuspendForGC != NULL &&
2823 m_pThreadAttemptingSuspendForGC != pCurThread)
2825 CLREventBase * hAbortEvt = s_hAbortEvt;
2827 if (hAbortEvt != NULL)
2829 LOG((LF_SYNC, INFO3, "Performing suspend abort wait.\n"));
2830 hAbortEvt->Wait(INFINITE, FALSE);
2831 LOG((LF_SYNC, INFO3, "Release from suspend abort wait.\n"));
2835 // This is shutdown aware. If we're in shutdown, and not helper/finalizer/shutdown
2836 // then this will not take the lock and just block forever.
2837 ThreadStore::s_pThreadStore->Enter();
2840 _ASSERTE(ThreadStore::s_pThreadStore->m_holderthreadid.IsUnknown());
2841 ThreadStore::s_pThreadStore->m_holderthreadid.SetToCurrentThread();
2843 LOG((LF_SYNC, INFO3, "Locked thread store\n"));
2845 // Established after we obtain the lock, so only useful for synchronous tests.
2846 // A thread attempting to suspend us asynchronously already holds this lock.
2847 ThreadStore::s_pThreadStore->m_HoldingThread = pCurThread;
2851 pCurThread->DisablePreemptiveGC();
2854 GC_ON_TRANSITIONS(gcOnTransitions);
2858 LOG((LF_SYNC, INFO3, "Locking thread store skipped upon detach\n"));
2862 void ThreadSuspend::UnlockThreadStore(BOOL bThreadDestroyed, ThreadSuspend::SUSPEND_REASON reason)
2870 // There's a nasty problem here. Once we start shutting down because of a
2871 // process detach notification, threads are disappearing from under us. There
2872 // are a surprising number of cases where the dying thread holds the ThreadStore
2873 // lock. For example, the finalizer thread holds this during startup in about
2874 // 10 of our COM BVTs.
2875 if (!IsAtProcessExit())
2877 Thread *pCurThread = GetThread();
2879 LOG((LF_SYNC, INFO3, "Unlocking thread store\n"));
2880 _ASSERTE(GetThread() == NULL || ThreadStore::s_pThreadStore->m_HoldingThread == GetThread());
2883 // If Thread object has been destroyed, we need to reset the ownership info in Crst.
2884 _ASSERTE(!bThreadDestroyed || GetThread() == NULL);
2885 if (bThreadDestroyed) {
2886 ThreadStore::s_pThreadStore->m_Crst.m_holderthreadid.SetToCurrentThread();
2890 ThreadStore::s_pThreadStore->m_HoldingThread = NULL;
2891 ThreadStore::s_pThreadStore->m_holderthreadid.Clear();
2892 ThreadStore::s_pThreadStore->Leave();
2894 // We're out of the critical area for managed/unmanaged debugging.
2895 if (!bThreadDestroyed && pCurThread)
2896 pCurThread->SetDebugCantStop(false);
2900 LOG((LF_SYNC, INFO3, "Unlocking thread store skipped upon detach\n"));
2905 void ThreadStore::AllocateOSContext()
2907 LIMITED_METHOD_CONTRACT;
2908 _ASSERTE(HoldingThreadStore());
2909 if (s_pOSContext == NULL
2911 || s_pOSContext == (CONTEXT*)0x1
2915 s_pOSContext = new (nothrow) CONTEXT();
2918 if (s_pOSContext == NULL)
2920 s_pOSContext = (CONTEXT*)0x1;
2925 CONTEXT *ThreadStore::GrabOSContext()
2927 LIMITED_METHOD_CONTRACT;
2928 _ASSERTE(HoldingThreadStore());
2929 CONTEXT *pContext = s_pOSContext;
2930 s_pOSContext = NULL;
2932 if (pContext == (CONTEXT*)0x1)
2940 extern void WaitForEndOfShutdown();
2942 //----------------------------------------------------------------------------
2944 // Suspending threads, rendezvousing with threads that reach safe places, etc.
2946 //----------------------------------------------------------------------------
2948 // A note on SUSPENSIONS.
2950 // We must not suspend a thread while it is holding the ThreadStore lock, or
2951 // the lock on the thread. Why? Because we need those locks to resume the
2952 // thread (and to perform a GC, use the debugger, spawn or kill threads, etc.)
2954 // There are two types of suspension we must consider to enforce the above
2955 // rule. Synchronous suspensions are where we persuade the thread to suspend
2956 // itself. This is CommonTripThread and its cousins. In other words, the
2957 // thread toggles the GC mode, or it hits a hijack, or certain opcodes in the
2958 // interpreter, etc. In these cases, the thread can simply check whether it
2959 // is holding these locks before it suspends itself.
2961 // The other style is an asynchronous suspension. This is where another
2962 // thread looks to see where we are. If we are in a fully interruptible region
2963 // of JIT code, we will be left suspended. In this case, the thread performing
2964 // the suspension must hold the locks on the thread and the threadstore. This
2965 // ensures that we aren't suspended while we are holding these locks.
2967 // Note that in the asynchronous case it's not enough to just inspect the thread
2968 // to see if it's holding these locks. Since the thread must be in preemptive
2969 // mode to block to acquire these locks, and since there will be a few inst-
2970 // ructions between acquiring the lock and noting in our state that we've
2971 // acquired it, then there would be a window where we would seem eligible for
2972 // suspension -- but in fact would not be.
2974 //----------------------------------------------------------------------------
2976 // We can't leave preemptive mode and enter cooperative mode, if a GC is
2977 // currently in progress. This is the situation when returning back into
2978 // the EE from outside. See the comments in DisablePreemptiveGC() to understand
2979 // why we Enable GC here!
2980 void Thread::RareDisablePreemptiveGC()
2982 BEGIN_PRESERVE_LAST_ERROR;
2987 DISABLED(GC_TRIGGERS); // I think this is actually wrong: prevents a p->c->p mode switch inside a NOTRIGGER region.
2991 CONTRACT_VIOLATION(SOToleranceViolation);
2993 if (IsAtProcessExit())
3000 AddFiberInfo(ThreadTrackInfo_GCMode);
3003 // This should NEVER be called if the TSNC_UnsafeSkipEnterCooperative bit is set!
3004 _ASSERTE(!(m_StateNC & TSNC_UnsafeSkipEnterCooperative) && "DisablePreemptiveGC called while the TSNC_UnsafeSkipEnterCooperative bit is set");
3006 // Holding a spin lock in preemp mode and switch to coop mode could cause other threads spinning
3008 _ASSERTE ((m_StateNC & Thread::TSNC_OwnsSpinLock) == 0);
3010 if (!GCHeapUtilities::IsGCHeapInitialized())
3015 // CoreCLR does not support user-requested thread suspension
3016 _ASSERTE(!(m_State & TS_UserSuspendPending));
3018 // Note IsGCInProgress is also true for say Pause (anywhere SuspendEE happens) and GCThread is the
3019 // thread that did the Pause. While in Pause if another thread attempts Rev/Pinvoke it should get inside the following and
3020 // block until resume
3021 if (((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) ||
3022 (m_State & (TS_UserSuspendPending | TS_DebugSuspendPending | TS_StackCrawlNeeded))) &&
3023 (!g_fSuspendOnShutdown || IsFinalizerThread() || IsShutdownSpecialThread()))
3025 if (!ThreadStore::HoldingThreadStore(this))
3027 STRESS_LOG1(LF_SYNC, LL_INFO1000, "RareDisablePreemptiveGC: entering. Thread state = %x\n", m_State.Load());
3029 DWORD dwSwitchCount = 0;
3033 // CoreCLR does not support user-requested thread suspension
3034 _ASSERTE(!(m_State & TS_UserSuspendPending));
3036 EnablePreemptiveGC();
3038 // Cannot use GCX_PREEMP_NO_DTOR here because we're inside of the thread
3039 // PREEMP->COOP switch mechanism and GCX_PREEMP's assert's will fire.
3040 // Instead we use BEGIN_GCX_ASSERT_PREEMP to inform Scan of the mode
3042 BEGIN_GCX_ASSERT_PREEMP;
3044 // just wait until the GC is over.
3045 if (this != ThreadSuspend::GetSuspensionThread())
3047 #ifdef PROFILING_SUPPORTED
3048 // If profiler desires GC events, notify it that this thread is waiting until the GC is over
3049 // Do not send suspend notifications for debugger suspensions
3051 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
3052 if (!(m_State & TS_DebugSuspendPending))
3054 g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this);
3058 #endif // PROFILING_SUPPORTED
3062 DWORD status = S_OK;
3063 SetThreadStateNC(TSNC_WaitUntilGCFinished);
3064 status = GCHeapUtilities::GetGCHeap()->WaitUntilGCComplete();
3065 ResetThreadStateNC(TSNC_WaitUntilGCFinished);
3067 if (status == (DWORD)COR_E_STACKOVERFLOW)
3069 // One of two things can happen here:
3070 // 1. GC is suspending the process. GC needs to wait.
3071 // 2. GC is proceeding after suspension. The current thread needs to spin.
3072 SetThreadState(TS_BlockGCForSO);
3073 while (GCHeapUtilities::IsGCInProgress() && m_fPreemptiveGCDisabled.Load() == 0)
3076 // We can not go to a host for blocking operation due ot lack of stack.
3077 // Instead we will spin here until
3078 // 1. GC is finished; Or
3079 // 2. GC lets this thread to run and will wait for it
3081 #define Sleep(a) Dont_Use_Sleep(a)
3083 ResetThreadState(TS_BlockGCForSO);
3084 if (m_fPreemptiveGCDisabled.Load() == 1)
3086 // GC suspension has allowed this thread to switch back to cooperative mode.
3090 if (!GCHeapUtilities::IsGCInProgress())
3092 if (HasThreadState(TS_StackCrawlNeeded))
3094 SetThreadStateNC(TSNC_WaitUntilGCFinished);
3095 ThreadStore::WaitForStackCrawlEvent();
3096 ResetThreadStateNC(TSNC_WaitUntilGCFinished);
3100 __SwitchToThread(0, ++dwSwitchCount);
3104 #ifdef PROFILING_SUPPORTED
3105 // Let the profiler know that this thread is resuming
3107 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
3108 g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)this);
3111 #endif // PROFILING_SUPPORTED
3114 END_GCX_ASSERT_PREEMP;
3116 // disable preemptive gc.
3117 FastInterlockOr(&m_fPreemptiveGCDisabled, 1);
3119 // The fact that we check whether 'this' is the GC thread may seem
3120 // strange. After all, we determined this before entering the method.
3121 // However, it is possible for the current thread to become the GC
3122 // thread while in this loop. This happens if you use the COM+
3123 // debugger to suspend this thread and then release it.
3125 } while ((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) ||
3126 (m_State & (TS_UserSuspendPending | TS_DebugSuspendPending | TS_StackCrawlNeeded)));
3128 STRESS_LOG0(LF_SYNC, LL_INFO1000, "RareDisablePreemptiveGC: leaving\n");
3131 // Block all threads except finalizer and shutdown thread during shutdown.
3132 // If g_fSuspendFinalizerOnShutdown is set, block the finalizer too.
3133 if ((g_fSuspendOnShutdown && !IsFinalizerThread() && !IsShutdownSpecialThread()) ||
3134 (g_fSuspendFinalizerOnShutdown && IsFinalizerThread()))
3136 STRESS_LOG1(LF_SYNC, LL_INFO1000, "RareDisablePreemptiveGC: entering. Thread state = %x\n", m_State.Load());
3138 EnablePreemptiveGC();
3140 // Cannot use GCX_PREEMP_NO_DTOR here because we're inside of the thread
3141 // PREEMP->COOP switch mechanism and GCX_PREEMP's assert's will fire.
3142 // Instead we use BEGIN_GCX_ASSERT_PREEMP to inform Scan of the mode
3144 BEGIN_GCX_ASSERT_PREEMP;
3146 #ifdef PROFILING_SUPPORTED
3147 // If profiler desires GC events, notify it that this thread is waiting until the GC is over
3148 // Do not send suspend notifications for debugger suspensions
3150 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
3151 if (!(m_State & TS_DebugSuspendPending))
3153 g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this);
3157 #endif // PROFILING_SUPPORTED
3161 // The thread is blocked for shutdown. We do not concern for GC violation.
3162 CONTRACT_VIOLATION(GCViolation);
3164 WaitForEndOfShutdown();
3166 END_GCX_ASSERT_PREEMP;
3168 __SwitchToThread(INFINITE, CALLER_LIMITS_SPINNING);
3169 _ASSERTE(!"Cannot reach here");
3173 END_PRESERVE_LAST_ERROR;
3176 void Thread::HandleThreadAbortTimeout()
3178 WRAPPER_NO_CONTRACT;
3180 EPolicyAction action = eNoAction;
3181 EClrOperation operation = OPR_ThreadRudeAbortInNonCriticalRegion;
3183 if (IsFuncEvalAbort())
3185 // There can't be escalation policy for FuncEvalAbort timeout.
3186 // The debugger should retain control of the policy. For example, if a RudeAbort times out, it's
3187 // probably because the debugger had some other thread frozen. When the thread is thawed, things might
3188 // be fine, so we don't want to escelate the FuncEvalRudeAbort (which will be swalled by FuncEvalHijackWorker)
3189 // into a user RudeThreadAbort (which will at least rip the entire thread).
3195 operation = OPR_ThreadAbort;
3197 else if (HasLockInCurrentDomain())
3199 operation = OPR_ThreadRudeAbortInCriticalRegion;
3203 operation = OPR_ThreadRudeAbortInNonCriticalRegion;
3205 action = GetEEPolicy()->GetActionOnTimeout(operation, this);
3206 // We only support escalation to rude abort
3211 case eRudeAbortThread:
3212 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
3213 MarkThreadForAbort(TAR_Thread, EEPolicy::TA_Rude);
3215 case eUnloadAppDomain:
3217 AppDomain *pDomain = GetDomain();
3218 if (!pDomain->IsDefaultDomain())
3220 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
3221 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
3225 case eRudeUnloadAppDomain:
3227 AppDomain *pDomain = GetDomain();
3228 if (!pDomain->IsDefaultDomain())
3230 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
3231 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
3236 case eFastExitProcess:
3237 case eRudeExitProcess:
3238 case eDisableRuntime:
3239 GetEEPolicy()->NotifyHostOnTimeout(operation,action);
3240 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT);
3241 _ASSERTE (!"Should not reach here");
3246 _ASSERTE (!"unknown policy for thread abort");
3251 EX_END_CATCH(SwallowAllExceptions);
3254 void Thread::HandleThreadAbort (BOOL fForce)
3256 BEGIN_PRESERVE_LAST_ERROR;
3258 STATIC_CONTRACT_THROWS;
3259 STATIC_CONTRACT_GC_TRIGGERS;
3260 STATIC_CONTRACT_SO_TOLERANT;
3262 BEGIN_SO_INTOLERANT_CODE(this);
3263 TESTHOOKCALL(AppDomainCanBeUnloaded(GetDomain()->GetId().m_dwId,FALSE));
3265 // It's possible we could go through here if we hit a hard SO and MC++ has called back
3266 // into the runtime on this thread
3270 if (IsAbortRequested() && GetAbortEndTime() < CLRGetTickCount64())
3272 HandleThreadAbortTimeout();
3275 // @TODO: we should consider treating this function as an FCALL or HCALL and use FCThrow instead of COMPlusThrow
3277 // Sometimes we call this without any CLR SEH in place. An example is UMThunkStubRareDisableWorker.
3278 // That's okay since COMPlusThrow will eventually erect SEH around the RaiseException. It prevents
3279 // us from stating CONTRACT here.
3281 if (fForce || ReadyForAbort())
3283 ResetThreadState ((ThreadState)(TS_Interrupted | TS_Interruptible));
3284 // We are going to abort. Abort satisfies Thread.Interrupt requirement.
3285 FastInterlockExchange (&m_UserInterrupt, 0);
3287 // generate either a ThreadAbort exception
3288 STRESS_LOG1(LF_APPDOMAIN, LL_INFO100, "Thread::HandleThreadAbort throwing abort for %x\n", GetThreadId());
3292 // Can not use holder. GCX_COOP forces the thread back to the original state during
3293 // exception unwinding, which may put the thread back to cooperative mode.
3296 if (!IsAbortInitiated() ||
3297 (IsRudeAbort() && !IsRudeAbortInitiated()))
3299 PreWorkForThreadAbort();
3302 PreparingAbortHolder paHolder;
3304 OBJECTREF exceptObj;
3308 exceptObj = CLRException::GetPreallocatedRudeThreadAbortException();
3312 EEException eeExcept(kThreadAbortException);
3313 exceptObj = CLRException::GetThrowableFromException(&eeExcept);
3317 AddFiberInfo(ThreadTrackInfo_Abort);
3319 RaiseTheExceptionInternalOnly(exceptObj, FALSE);
3321 END_SO_INTOLERANT_CODE;
3323 END_PRESERVE_LAST_ERROR;
3326 void Thread::PreWorkForThreadAbort()
3328 WRAPPER_NO_CONTRACT;
3330 SetAbortInitiated();
3331 // if an abort and interrupt happen at the same time (e.g. on a sleeping thread),
3332 // the abort is favored. But we do need to reset the interrupt bits.
3333 FastInterlockAnd((ULONG *) &m_State, ~(TS_Interruptible | TS_Interrupted));
3334 ResetUserInterrupted();
3336 if (IsRudeAbort() && !(m_AbortInfo & (TAI_ADUnloadAbort |
3337 TAI_ADUnloadRudeAbort |
3338 TAI_ADUnloadV1Abort)
3340 if (HasLockInCurrentDomain()) {
3341 AppDomain *pDomain = GetAppDomain();
3342 // Cannot enable the following assertion.
3343 // We may take the lock, but the lock will be released during exception backout.
3344 //_ASSERTE(!pDomain->IsDefaultDomain());
3345 EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ThreadRudeAbortInCriticalRegion, this);
3348 case eRudeUnloadAppDomain:
3349 if (!pDomain->IsDefaultDomain())
3351 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ThreadRudeAbortInCriticalRegion,action);
3352 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
3356 case eFastExitProcess:
3357 case eRudeExitProcess:
3358 case eDisableRuntime:
3360 // We're about to exit the process, if we take an SO here we'll just exit faster right???
3361 CONTRACT_VIOLATION(SOToleranceViolation);
3363 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ThreadRudeAbortInCriticalRegion,action);
3364 GetEEPolicy()->HandleExitProcessFromEscalation(action,HOST_E_EXITPROCESS_ADUNLOAD);
3374 #if defined(STRESS_HEAP) && defined(_DEBUG)
3376 // This function is for GC stress testing. Before we enable preemptive GC, let us do a GC
3377 // because GC may happen while the thread is in preemptive GC mode.
3378 void Thread::PerformPreemptiveGC()
3382 DISABLED(GC_TRIGGERS); // I think this is actually wrong: prevents a p->c->p mode switch inside a NOTRIGGER region.
3387 if (IsAtProcessExit())
3390 if (!GCStressPolicy::IsEnabled() || !GCStress<cfg_transition>::IsEnabled())
3393 if (!GCHeapUtilities::IsGCHeapInitialized())
3396 if (!m_GCOnTransitionsOK
3397 #ifdef ENABLE_CONTRACTS
3401 || GCHeapUtilities::IsGCInProgress(TRUE)
3402 || GCHeapUtilities::GetGCHeap()->GetGcCount() == 0 // Need something that works for isolated heap.
3403 || ThreadStore::HoldingThreadStore())
3406 if (Thread::ThreadsAtUnsafePlaces())
3409 #ifdef DEBUGGING_SUPPORTED
3410 // Don't collect if the debugger is attach and either 1) there
3411 // are any threads held at unsafe places or 2) this thread is
3412 // under the control of the debugger's dispatch logic (as
3413 // evidenced by having a non-NULL filter context.)
3414 if ((CORDebuggerAttached() &&
3415 (g_pDebugInterface->ThreadsAtUnsafePlaces() ||
3416 (GetFilterContext() != NULL))))
3418 #endif // DEBUGGING_SUPPORTED
3420 _ASSERTE(m_fPreemptiveGCDisabled.Load() == 0); // we are in preemptive mode when we call this
3422 m_GCOnTransitionsOK = FALSE;
3425 m_bGCStressing = TRUE;
3427 // BUG(github #10318) - when not using allocation contexts, the alloc lock
3428 // must be acquired here. Until fixed, this assert prevents random heap corruption.
3429 _ASSERTE(GCHeapUtilities::UseThreadAllocationContexts());
3430 GCHeapUtilities::GetGCHeap()->StressHeap(GetThread()->GetAllocContext());
3431 m_bGCStressing = FALSE;
3433 m_GCOnTransitionsOK = TRUE;
3435 #endif // STRESS_HEAP && DEBUG
3437 // To leave cooperative mode and enter preemptive mode, if a GC is in progress, we
3438 // no longer care to suspend this thread. But if we are trying to suspend the thread
3439 // for other reasons (e.g. Thread.Suspend()), now is a good time.
3441 // Note that it is possible for an N/Direct call to leave the EE without explicitly
3442 // enabling preemptive GC.
3443 void Thread::RareEnablePreemptiveGC()
3447 DISABLED(GC_TRIGGERS); // I think this is actually wrong: prevents a p->c->p mode switch inside a NOTRIGGER region.
3452 // @todo - Needs a hard SO probe
3453 CONTRACT_VIOLATION(GCViolation|FaultViolation|SOToleranceViolation);
3455 // If we have already received our PROCESS_DETACH during shutdown, there is only one thread in the
3456 // process and no coordination is necessary.
3457 if (IsAtProcessExit())
3461 AddFiberInfo(ThreadTrackInfo_GCMode);
3464 // EnablePreemptiveGC already set us to preemptive mode before triggering the Rare path.
3465 // Force other threads to see this update, since the Rare path implies that someone else
3466 // is observing us (e.g. SuspendRuntime).
3468 _ASSERTE (!m_fPreemptiveGCDisabled);
3470 // holding a spin lock in coop mode and transit to preemp mode will cause deadlock on GC
3471 _ASSERTE ((m_StateNC & Thread::TSNC_OwnsSpinLock) == 0);
3473 FastInterlockOr (&m_fPreemptiveGCDisabled, 0);
3475 #if defined(STRESS_HEAP) && defined(_DEBUG)
3477 PerformPreemptiveGC();
3480 STRESS_LOG1(LF_SYNC, LL_INFO100000, "RareEnablePreemptiveGC: entering. Thread state = %x\n", m_State.Load());
3481 if (!ThreadStore::HoldingThreadStore(this))
3483 #ifdef FEATURE_HIJACK
3484 // Remove any hijacks we might have.
3486 #endif // FEATURE_HIJACK
3488 // wake up any threads waiting to suspend us, like the GC thread.
3489 ThreadSuspend::g_pGCSuspendEvent->Set();
3491 // for GC, the fact that we are leaving the EE means that it no longer needs to
3492 // suspend us. But if we are doing a non-GC suspend, we need to block now.
3493 // Give the debugger precedence over user suspensions:
3494 while (m_State & (TS_DebugSuspendPending | TS_UserSuspendPending))
3496 // CoreCLR does not support user-requested thread suspension
3497 _ASSERTE(!(m_State & TS_UserSuspendPending));
3499 #ifdef DEBUGGING_SUPPORTED
3500 // We don't notify the debugger that this thread is now suspended. We'll just
3501 // let the debugger's helper thread sweep and pick it up.
3502 // We also never take the TSL in here either.
3503 // Life's much simpler this way...
3506 #endif // DEBUGGING_SUPPORTED
3510 LOG((LF_CORDB, LL_INFO1000, "[0x%x] SUSPEND: suspended while enabling gc.\n", GetThreadId()));
3514 WaitSuspendEvents(); // sets bits, too
3518 STRESS_LOG0(LF_SYNC, LL_INFO100000, " RareEnablePreemptiveGC: leaving.\n");
3521 // Called when we are passing through a safe point in CommonTripThread or
3522 // HandleGCSuspensionForInterruptedThread. Do the right thing with this thread,
3523 // which can either mean waiting for the GC to complete, or performing a
3524 // pending suspension.
3525 void Thread::PulseGCMode()
3533 _ASSERTE(this == GetThread());
3535 if (PreemptiveGCDisabled() && CatchAtSafePoint())
3537 EnablePreemptiveGC();
3538 DisablePreemptiveGC();
3542 // Indicate whether threads should be trapped when returning to the EE (i.e. disabling
3543 // preemptive GC mode)
3544 Volatile<LONG> g_fTrapReturningThreadsLock;
3545 void ThreadStore::TrapReturningThreads(BOOL yes)
3552 // make sure that a thread doesn't get suspended holding g_fTrapReturningThreadsLock
3553 // if a suspended thread held this lock and then the suspending thread called in
3554 // here (which it does) the suspending thread would deadlock causing the suspension
3555 // as a whole to deadlock
3556 ForbidSuspendThreadHolder suspend;
3558 DWORD dwSwitchCount = 0;
3559 while (1 == FastInterlockExchange(&g_fTrapReturningThreadsLock, 1))
3561 // we can't forbid suspension while we are sleeping and don't hold the lock
3562 // this will trigger an assert on SQLCLR but is a general issue
3564 __SwitchToThread(0, ++dwSwitchCount);
3571 CounterHolder trtHolder(&g_trtChgInFlight);
3572 FastInterlockIncrement(&g_trtChgStamp);
3575 GCHeapUtilities::GetGCHeap()->SetSuspensionPending(true);
3576 FastInterlockIncrement (&g_TrapReturningThreads);
3577 #ifdef ENABLE_FAST_GCPOLL_HELPER
3580 _ASSERTE(g_TrapReturningThreads > 0);
3583 trtHolder.Release();
3588 FastInterlockDecrement (&g_TrapReturningThreads);
3589 GCHeapUtilities::GetGCHeap()->SetSuspensionPending(false);
3591 #ifdef ENABLE_FAST_GCPOLL_HELPER
3592 if (0 == g_TrapReturningThreads)
3598 _ASSERTE(g_TrapReturningThreads >= 0);
3600 #ifdef ENABLE_FAST_GCPOLL_HELPER
3601 //Ensure that we flush the cache line containing the GC Poll Helper.
3603 #endif //ENABLE_FAST_GCPOLL_HELPER
3604 g_fTrapReturningThreadsLock = 0;
3608 #ifdef FEATURE_HIJACK
3610 void RedirectedThreadFrame::ExceptionUnwind()
3621 STRESS_LOG1(LF_SYNC, LL_INFO1000, "In RedirectedThreadFrame::ExceptionUnwind pFrame = %p\n", this);
3623 Thread* pThread = GetThread();
3625 if (pThread->GetSavedRedirectContext())
3631 // Save it for future use to avoid repeatedly new'ing
3632 pThread->SetSavedRedirectContext(m_Regs);
3638 #ifndef PLATFORM_UNIX
3641 //****************************************************************************************
3642 // This will check who caused the exception. If it was caused by the the redirect function,
3643 // the reason is to resume the thread back at the point it was redirected in the first
3644 // place. If the exception was not caused by the function, then it was caused by the call
3645 // out to the I[GC|Debugger]ThreadControl client and we need to determine if it's an
3646 // exception that we can just eat and let the runtime resume the thread, or if it's an
3647 // uncatchable exception that we need to pass on to the runtime.
3649 int RedirectedHandledJITCaseExceptionFilter(
3650 PEXCEPTION_POINTERS pExcepPtrs, // Exception data
3651 RedirectedThreadFrame *pFrame, // Frame on stack
3652 BOOL fDone, // Whether redirect completed without exception
3653 CONTEXT *pCtx) // Saved context
3655 // !!! Do not use a non-static contract here.
3656 // !!! Contract may insert an exception handling record.
3657 // !!! This function assumes that GetCurrentSEHRecord() returns the exception record set up in
3658 // !!! Thread::RedirectedHandledJITCase
3660 // !!! Do not use an object with dtor, since it injects a fs:0 entry.
3661 STATIC_CONTRACT_NOTHROW;
3662 STATIC_CONTRACT_GC_TRIGGERS;
3663 STATIC_CONTRACT_MODE_ANY;
3665 if (pExcepPtrs->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
3667 return EXCEPTION_CONTINUE_SEARCH;
3670 // Get the thread handle
3671 Thread *pThread = GetThread();
3675 STRESS_LOG2(LF_SYNC, LL_INFO100, "In RedirectedHandledJITCaseExceptionFilter fDone = %d pFrame = %p\n", fDone, pFrame);
3677 // If we get here via COM+ exception, gc-mode is unknown. We need it to
3678 // be cooperative for this function.
3681 // If the exception was due to the called client, then we need to figure out if it
3682 // is an exception that can be eaten or if it needs to be handled elsewhere.
3685 if (pExcepPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
3687 return (EXCEPTION_CONTINUE_SEARCH);
3690 // Get the latest thrown object
3691 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExcepPtrs->ExceptionRecord);
3693 // If this is an uncatchable exception, then let the exception be handled elsewhere
3694 if (IsUncatchable(&throwable))
3696 pThread->EnablePreemptiveGC();
3697 return (EXCEPTION_CONTINUE_SEARCH);
3703 _ASSERTE(pExcepPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_HIJACK);
3707 // Unlink the frame in preparation for resuming in managed code
3710 // Copy the saved context record into the EH context;
3711 ReplaceExceptionContextRecord(pExcepPtrs->ContextRecord, pCtx);
3713 DWORD espValue = pCtx->Esp;
3714 if (pThread->GetSavedRedirectContext())
3720 // Save it for future use to avoid repeatedly new'ing
3721 pThread->SetSavedRedirectContext(pCtx);
3724 /////////////////////////////////////////////////////////////////////////////
3725 // NOTE: Ugly, ugly workaround.
3726 // We need to resume the thread into the managed code where it was redirected,
3727 // and the corresponding ESP is below the current one. But C++ expects that
3728 // on an EXCEPTION_CONTINUE_EXECUTION that the ESP will be above where it has
3729 // installed the SEH handler. To solve this, we need to remove all handlers
3730 // that reside above the resumed ESP, but we must leave the OS-installed
3731 // handler at the top, so we grab the top SEH handler, call
3732 // PopSEHRecords which will remove all SEH handlers above the target ESP and
3733 // then link the OS handler back in with SetCurrentSEHRecord.
3735 // Get the special OS handler and save it until PopSEHRecords is done
3736 EXCEPTION_REGISTRATION_RECORD *pCurSEH = GetCurrentSEHRecord();
3738 // Unlink all records above the target resume ESP
3739 PopSEHRecords((LPVOID)(size_t)espValue);
3741 // Link the special OS handler back in to the top
3742 pCurSEH->Next = GetCurrentSEHRecord();
3744 // Register the special OS handler as the top handler with the OS
3745 SetCurrentSEHRecord(pCurSEH);
3747 // Resume execution at point where thread was originally redirected
3748 return (EXCEPTION_CONTINUE_EXECUTION);
3750 #endif // _TARGET_X86_
3752 void NotifyHostOnGCSuspension()
3765 // This function is called from the assembly functions used to redirect a thread. It must not cause
3766 // an exception (except SO).
3767 extern "C" PCONTEXT __stdcall GetCurrentSavedRedirectContext()
3769 LIMITED_METHOD_CONTRACT;
3771 DWORD dwLastError = GetLastError();
3772 PCONTEXT pContext = GetThread()->GetSavedRedirectContext();
3773 SetLastError(dwLastError);
3778 void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason)
3780 STATIC_CONTRACT_THROWS;
3781 STATIC_CONTRACT_GC_TRIGGERS;
3782 STATIC_CONTRACT_MODE_COOPERATIVE;
3784 // We must preserve this in case we've interrupted an IL pinvoke stub before it
3785 // was able to save the error.
3786 DWORD dwLastError = GetLastError();
3788 Thread *pThread = GetThread();
3791 #ifdef FEATURE_STACK_PROBE
3792 if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
3794 RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), pThread);
3798 BEGIN_CONTRACT_VIOLATION(SOToleranceViolation);
3800 // Get the saved context
3801 CONTEXT *pCtx = pThread->GetSavedRedirectContext();
3804 INDEBUG(Thread::ObjectRefFlush(pThread));
3806 // Create a frame on the stack
3807 FrameWithCookie<RedirectedThreadFrame> frame(pCtx);
3809 STRESS_LOG5(LF_SYNC, LL_INFO1000, "In RedirectedHandledJITcase reason 0x%x pFrame = %p pc = %p sp = %p fp = %p", reason, &frame, GetIP(pCtx), GetSP(pCtx), GetFP(pCtx));
3812 // This will indicate to the exception filter whether or not the exception is caused
3813 // by us or the client.
3815 int filter_count = 0; // A counter to avoid a nasty case where an
3816 // up-stack filter throws another exception
3817 // causing our filter to be run again for
3818 // some unrelated exception.
3821 #endif // _TARGET_X86_
3823 // Make sure this thread doesn't reuse the context memory in re-entrancy cases
3824 _ASSERTE(pThread->GetSavedRedirectContext() != NULL);
3825 pThread->SetSavedRedirectContext(NULL);
3827 // Link in the frame
3830 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
3831 if (reason == RedirectReason_GCStress)
3833 _ASSERTE(pThread->PreemptiveGCDisabledOther());
3834 DoGcStress(frame.GetContext(), NULL);
3837 #endif // HAVE_GCCOVER && USE_REDIRECT_FOR_GCSTRESS
3839 // Enable PGC before calling out to the client to allow runtime suspend to finish
3840 GCX_PREEMP_NO_DTOR();
3842 // Notify the interface of the pending suspension
3844 case RedirectReason_GCSuspension:
3846 case RedirectReason_DebugSuspension:
3848 case RedirectReason_UserSuspension:
3852 _ASSERTE(!"Invalid redirect reason");
3856 // Disable preemptive GC so we can unlink the frame
3857 GCX_PREEMP_NO_DTOR_END();
3861 pThread->HandleThreadAbort(); // Might throw an exception.
3863 // Indicate that the call to the service went without an exception, and that
3864 // we're raising our own exception to resume the thread to where it was
3868 // Save the instruction pointer where we redirected last. This does not race with the check
3869 // against this variable in HandledJitCase because the GC will not attempt to redirect the
3870 // thread until the instruction pointer of this thread is back in managed code.
3871 pThread->m_LastRedirectIP = GetIP(pCtx);
3872 pThread->m_SpinCount = 0;
3874 RaiseException(EXCEPTION_HIJACK, 0, 0, NULL);
3876 #else // _TARGET_X86_
3878 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
3880 // If GCStress interrupts an IL stub or inlined p/invoke while it's running in preemptive mode, it switches the mode to
3881 // cooperative - but we will resume to preemptive below. We should not trigger an abort in that case, as it will fail
3882 // due to the GC mode.
3884 if (!pThread->m_fPreemptiveGCDisabledForGCStress)
3888 UINT_PTR uAbortAddr;
3889 UINT_PTR uResumePC = (UINT_PTR)GetIP(pCtx);
3890 CopyOSContext(pThread->m_OSContext, pCtx);
3891 uAbortAddr = (UINT_PTR)COMPlusCheckForAbort();
3894 LOG((LF_EH, LL_INFO100, "thread abort in progress, resuming thread under control... (handled jit case)\n"));
3896 CONSISTENCY_CHECK(CheckPointer(pCtx));
3898 STRESS_LOG1(LF_EH, LL_INFO10, "resume under control: ip: %p (handled jit case)\n", uResumePC);
3900 SetIP(pThread->m_OSContext, uResumePC);
3902 #if defined(_TARGET_ARM_)
3903 // Save the original resume PC in Lr
3904 pCtx->Lr = uResumePC;
3906 // Since we have set a new IP, we have to clear conditional execution flags too.
3907 ClearITState(pThread->m_OSContext);
3908 #endif // _TARGET_ARM_
3910 SetIP(pCtx, uAbortAddr);
3914 // Unlink the frame in preparation for resuming in managed code
3918 // Free the context struct if we already have one cached
3919 if (pThread->GetSavedRedirectContext())
3921 CONTEXT* pCtxTemp = (CONTEXT*)_alloca(sizeof(CONTEXT));
3922 memcpy(pCtxTemp, pCtx, sizeof(CONTEXT));
3928 // Save it for future use to avoid repeatedly new'ing
3929 pThread->SetSavedRedirectContext(pCtx);
3932 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
3933 if (pThread->m_fPreemptiveGCDisabledForGCStress)
3935 pThread->EnablePreemptiveGC();
3936 pThread->m_fPreemptiveGCDisabledForGCStress = false;
3940 LOG((LF_SYNC, LL_INFO1000, "Resuming execution with RtlRestoreContext\n"));
3942 SetLastError(dwLastError);
3944 RtlRestoreContext(pCtx, NULL);
3946 #endif // _TARGET_X86_
3949 __except (++filter_count == 1
3950 ? RedirectedHandledJITCaseExceptionFilter(GetExceptionInformation(), &frame, fDone, pCtx)
3951 : EXCEPTION_CONTINUE_SEARCH)
3953 _ASSERTE(!"Reached body of __except in Thread::RedirectedHandledJITCase");
3956 #endif // _TARGET_X86_
3958 END_CONTRACT_VIOLATION;
3962 //****************************************************************************************
3963 // This helper is called when a thread suspended in managed code at a sequence point while
3964 // suspending the runtime and there is a client interested in re-assigning the thread to
3965 // do interesting work while the runtime is suspended. This will call into the client
3966 // notifying it that the thread will be suspended for a runtime suspension.
3968 void __stdcall Thread::RedirectedHandledJITCaseForDbgThreadControl()
3970 WRAPPER_NO_CONTRACT;
3971 RedirectedHandledJITCase(RedirectReason_DebugSuspension);
3974 //****************************************************************************************
3975 // This helper is called when a thread suspended in managed code at a sequence point when
3976 // suspending the runtime.
3978 // We do this because the obvious code sequence:
3980 // SuspendThread(t1);
3981 // GetContext(t1, &ctx);
3982 // ctx.Ecx = <some new value>;
3983 // SetContext(t1, &ctx);
3984 // ResumeThread(t1);
3986 // simply does not work due to a nasty race with exception handling in the OS. If the
3987 // thread that is suspended has just faulted, then the update can disappear without ever
3988 // modifying the real thread ... and there is no way to tell.
3990 // Updating the EIP may not work ... but when it doesn't, we're ok ... an exception ends
3991 // up getting dispatched anyway.
3993 // If the host is interested in getting control, then we give control to the host. If the
3994 // host is not interested in getting control, then we call out to the host. After that,
3995 // we raise an exception and will end up waiting for the GC to finish inside the filter.
3997 void __stdcall Thread::RedirectedHandledJITCaseForGCThreadControl()
3999 WRAPPER_NO_CONTRACT;
4000 RedirectedHandledJITCase(RedirectReason_GCSuspension);
4003 //***********************
4004 // Like the above, but called for a UserSuspend.
4006 void __stdcall Thread::RedirectedHandledJITCaseForUserSuspend()
4008 WRAPPER_NO_CONTRACT;
4009 RedirectedHandledJITCase(RedirectReason_UserSuspension);
4012 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
4014 //***********************
4015 // Like the above, but called for GC stress.
4017 void __stdcall Thread::RedirectedHandledJITCaseForGCStress()
4019 WRAPPER_NO_CONTRACT;
4020 RedirectedHandledJITCase(RedirectReason_GCStress);
4023 #endif // HAVE_GCCOVER && _DEBUG && USE_REDIRECT_FOR_GCSTRESS
4025 //****************************************************************************************
4026 // This will take a thread that's been suspended in managed code at a sequence point and
4027 // will Redirect the thread. It will save all register information, build a frame on the
4028 // thread's stack, put a pointer to the frame at the top of the stack and set the IP of
4029 // the thread to pTgt. pTgt is then responsible for unlinking the thread,
4031 // NOTE: Cannot play with a suspended thread's stack memory, since the OS will use the
4032 // top of the stack to store information. The thread must be resumed and play with it's
4037 #define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_FLOATING_POINT | \
4038 CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST)
4040 #define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_EXCEPTION_REQUEST)
4043 BOOL Thread::RedirectThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt)
4051 _ASSERTE(HandledJITCase());
4052 _ASSERTE(GetThread() != this);
4054 ////////////////////////////////////////////////////////////////
4055 // Acquire a context structure to save the thread state into
4057 // We need to distinguish between two types of callers:
4058 // - Most callers, including GC, operate while holding the ThreadStore
4059 // lock. This means that we can pre-allocate a context structure
4060 // globally in the ThreadStore and use it in this function.
4061 // - Some callers (currently only YieldTask) cannot take the ThreadStore
4062 // lock. Therefore we always allocate a SavedRedirectContext in the
4063 // Thread constructor. (Since YieldTask currently is the only caller
4064 // that does not hold the ThreadStore lock, we only do this when
4067 // Check whether we have a SavedRedirectContext we can reuse:
4068 CONTEXT *pCtx = GetSavedRedirectContext();
4070 // If we've never allocated a context for this thread, do so now
4073 // If our caller took the ThreadStore lock, then it pre-allocated
4074 // a context in the ThreadStore:
4075 if (ThreadStore::HoldingThreadStore())
4077 pCtx = ThreadStore::GrabOSContext();
4082 // Even when our caller is YieldTask, we can find a NULL
4083 // SavedRedirectContext in this function: Consider the scenario
4084 // where GC is in progress and has already redirected a thread.
4085 // That thread will set its SavedRedirectContext to NULL to enable
4086 // reentrancy. Now assume that the host calls YieldTask for the
4087 // redirected thread. In this case, this function will simply
4088 // fail, but that is fine: The redirected thread will check,
4089 // before it resumes execution, whether it should yield.
4093 // Save the pointer for the redirect function
4094 _ASSERTE(GetSavedRedirectContext() == NULL);
4095 SetSavedRedirectContext(pCtx);
4098 //////////////////////////////////////
4099 // Get and save the thread's context
4101 // Always get complete context
4102 pCtx->ContextFlags = CONTEXT_COMPLETE;
4103 BOOL bRes = EEGetThreadContext(this, pCtx);
4104 _ASSERTE(bRes && "Failed to GetThreadContext in RedirectThreadAtHandledJITCase - aborting redirect.");
4109 if (!IsContextSafeToRedirect(pCtx))
4112 ////////////////////////////////////////////////////
4113 // Now redirect the thread to the helper function
4115 // Temporarily set the IP of the context to the target for SetThreadContext
4116 PCODE dwOrigEip = GetIP(pCtx);
4118 // Redirection can be required when in IT Block.
4119 // In that case must reset the IT state before redirection.
4120 DWORD dwOrigCpsr = pCtx->Cpsr;
4123 _ASSERTE(ExecutionManager::IsManagedCode(dwOrigEip));
4124 SetIP(pCtx, (PCODE)pTgt);
4127 STRESS_LOG4(LF_SYNC, LL_INFO10000, "Redirecting thread %p(tid=%x) from address 0x%08x to address 0x%p\n",
4128 this, this->GetThreadId(), dwOrigEip, pTgt);
4130 bRes = EESetThreadContext(this, pCtx);
4131 _ASSERTE(bRes && "Failed to SetThreadContext in RedirectThreadAtHandledJITCase - aborting redirect.");
4133 // Restore original IP
4134 SetIP(pCtx, dwOrigEip);
4136 // restore IT State in the context
4137 pCtx->Cpsr = dwOrigCpsr;
4141 //////////////////////////////////////////////////
4142 // Indicate whether or not the redirect succeeded
4147 BOOL Thread::CheckForAndDoRedirect(PFN_REDIRECTTARGET pRedirectTarget)
4157 _ASSERTE(this != GetThread());
4158 _ASSERTE(PreemptiveGCDisabledOther());
4159 _ASSERTE(IsAddrOfRedirectFunc(pRedirectTarget));
4162 fRes = RedirectThreadAtHandledJITCase(pRedirectTarget);
4163 LOG((LF_GC, LL_INFO1000, "RedirectThreadAtHandledJITCase %s.\n", fRes ? "SUCCEEDED" : "FAILED"));
4168 BOOL Thread::RedirectCurrentThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt, CONTEXT *pCurrentThreadCtx)
4176 // REVISIT_TODO need equivalent of this for the current thread
4177 //_ASSERTE(HandledJITCase());
4179 _ASSERTE(GetThread() == this);
4180 _ASSERTE(PreemptiveGCDisabledOther());
4181 _ASSERTE(IsAddrOfRedirectFunc(pTgt));
4182 _ASSERTE(pCurrentThreadCtx);
4183 _ASSERTE((pCurrentThreadCtx->ContextFlags & (CONTEXT_COMPLETE - CONTEXT_EXCEPTION_REQUEST))
4184 == (CONTEXT_COMPLETE - CONTEXT_EXCEPTION_REQUEST));
4185 _ASSERTE(ExecutionManager::IsManagedCode(GetIP(pCurrentThreadCtx)));
4187 ////////////////////////////////////////////////////////////////
4188 // Allocate a context structure to save the thread state into
4190 // Check to see if we've already got memory allocated for this purpose.
4191 CONTEXT *pCtx = GetSavedRedirectContext();
4193 // If we've never allocated a context for this thread, do so now
4196 pCtx = new (nothrow) CONTEXT();
4201 // Save the pointer for the redirect function
4202 _ASSERTE(GetSavedRedirectContext() == NULL);
4203 SetSavedRedirectContext(pCtx);
4206 //////////////////////////////////////
4207 // Get and save the thread's context
4209 CopyMemory(pCtx, pCurrentThreadCtx, sizeof(CONTEXT));
4211 // Clear any new bits we don't understand (like XSAVE) in case we pass
4212 // this context to RtlRestoreContext (like for gcstress)
4213 pCtx->ContextFlags &= CONTEXT_ALL;
4215 // Ensure that this flag is set for the next time through the normal path,
4216 // RedirectThreadAtHandledJITCase.
4217 pCtx->ContextFlags |= CONTEXT_EXCEPTION_REQUEST;
4219 ////////////////////////////////////////////////////
4220 // Now redirect the thread to the helper function
4222 SetIP(pCurrentThreadCtx, (PCODE)pTgt);
4225 // Redirection can be required when in IT Block
4226 // Clear the IT State before redirecting
4227 ClearITState(pCurrentThreadCtx);
4230 //////////////////////////////////////////////////
4231 // Indicate whether or not the redirect succeeded
4236 //************************************************************************
4237 // Exception handling needs to special case the redirection. So provide
4238 // a helper to identify redirection targets and keep the exception
4239 // checks in sync with the redirection here.
4240 // See CPFH_AdjustContextForThreadSuspensionRace for details.
4241 BOOL Thread::IsAddrOfRedirectFunc(void * pFuncAddr)
4243 WRAPPER_NO_CONTRACT;
4245 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
4246 if (pFuncAddr == GetRedirectHandlerForGCStress())
4248 #endif // HAVE_GCCOVER && USE_REDIRECT_FOR_GCSTRESS
4251 (pFuncAddr == GetRedirectHandlerForGCThreadControl()) ||
4252 (pFuncAddr == GetRedirectHandlerForDbgThreadControl()) ||
4253 (pFuncAddr == GetRedirectHandlerForUserSuspend());
4256 //************************************************************************
4257 // Redirect thread at a GC suspension.
4258 BOOL Thread::CheckForAndDoRedirectForGC()
4268 LOG((LF_GC, LL_INFO1000, "Redirecting thread %08x for GCThreadSuspension", GetThreadId()));
4269 return CheckForAndDoRedirect(GetRedirectHandlerForGCThreadControl());
4272 //************************************************************************
4273 // Redirect thread at a debug suspension.
4274 BOOL Thread::CheckForAndDoRedirectForDbg()
4284 LOG((LF_CORDB, LL_INFO1000, "Redirecting thread %08x for DebugSuspension", GetThreadId()));
4285 return CheckForAndDoRedirect(GetRedirectHandlerForDbgThreadControl());
4288 //*************************************************************************
4289 // Redirect thread at a user suspend.
4290 BOOL Thread::CheckForAndDoRedirectForUserSuspend()
4300 LOG((LF_SYNC, LL_INFO1000, "Redirecting thread %08x for UserSuspension", GetThreadId()));
4301 return CheckForAndDoRedirect(GetRedirectHandlerForUserSuspend());
4304 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
4305 //*************************************************************************
4306 // Redirect thread at a GC stress point.
4307 BOOL Thread::CheckForAndDoRedirectForGCStress (CONTEXT *pCurrentThreadCtx)
4309 WRAPPER_NO_CONTRACT;
4311 LOG((LF_CORDB, LL_INFO1000, "Redirecting thread %08x for GCStress", GetThreadId()));
4313 m_fPreemptiveGCDisabledForGCStress = !PreemptiveGCDisabled();
4316 BOOL fSuccess = RedirectCurrentThreadAtHandledJITCase(GetRedirectHandlerForGCStress(), pCurrentThreadCtx);
4320 GCX_COOP_NO_DTOR_END();
4321 m_fPreemptiveGCDisabledForGCStress = false;
4326 #endif // HAVE_GCCOVER && USE_REDIRECT_FOR_GCSTRESS
4328 #endif // !PLATFORM_UNIX
4329 #endif // FEATURE_HIJACK
4332 #ifdef PROFILING_SUPPORTED
4333 // Simple helper to convert the GC's SUSPEND_REASON enum to the profiling API's public
4334 // COR_PRF_SUSPEND_REASON enum. Used in code:Thread::SuspendRuntime to help with
4335 // sending the suspension event to the profiler.
4336 COR_PRF_SUSPEND_REASON GCSuspendReasonToProfSuspendReason(ThreadSuspend::SUSPEND_REASON gcReason)
4338 LIMITED_METHOD_CONTRACT;
4343 return COR_PRF_SUSPEND_OTHER;
4344 case ThreadSuspend::SUSPEND_FOR_GC:
4345 return COR_PRF_SUSPEND_FOR_GC;
4346 case ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN:
4347 return COR_PRF_SUSPEND_FOR_APPDOMAIN_SHUTDOWN;
4348 case ThreadSuspend::SUSPEND_FOR_REJIT:
4349 return COR_PRF_SUSPEND_FOR_REJIT;
4350 case ThreadSuspend::SUSPEND_FOR_SHUTDOWN:
4351 return COR_PRF_SUSPEND_FOR_SHUTDOWN;
4352 case ThreadSuspend::SUSPEND_FOR_DEBUGGER:
4353 return COR_PRF_SUSPEND_FOR_INPROC_DEBUGGER;
4354 case ThreadSuspend::SUSPEND_FOR_GC_PREP:
4355 return COR_PRF_SUSPEND_FOR_GC_PREP;
4358 #endif // PROFILING_SUPPORTED
4360 //************************************************************************************
4361 // To support fast application switch (FAS), one requirement is that the CPU
4362 // consumption during the time the CLR is paused should be 0. Given that the process
4363 // will be anyway suspended this should've been an NOP for CLR. However, in Mango
4364 // we ensured that no handle timed out or no other such context switch happens
4365 // during the pause time. To match that and also to ensure that in-between the
4366 // pause and when the process is suspended (~60 sec) no context switch happens due to
4367 // CLR handles (like Waits/sleeps due to calls from BCL) we call APC on these
4368 // Threads and make them wait on the resume handle
4369 void __stdcall PauseAPC(__in ULONG_PTR dwParam)
4379 if(g_IsPaused && (GetThread()->m_State & Thread::TS_Interruptible))
4381 _ASSERTE(g_ClrResumeEvent.IsValid());
4383 g_ClrResumeEvent.Wait(INFINITE, FALSE);
4386 // Assert on debug builds
4389 EX_END_CATCH(SwallowAllExceptions);
4394 //************************************************************************************
4396 // SuspendRuntime is responsible for ensuring that all managed threads reach a
4397 // "safe point." It returns when all threads are known to be in "preemptive" mode.
4398 // This is *only* called by ThreadSuspend::SuspendEE; these two methods should really
4399 // be refactored into a separate "managed execution lock."
4401 // Note that we use this method for more than just GC suspension. We also suspend
4402 // for debugging, etc.
4404 // The basic algorithm is this:
4406 // while there are threads in cooperative mode:
4407 // for each thread in cooprative mode:
4408 // suspend the native thread.
4409 // if it's still in cooperative mode, and it's running JIT'd code:
4410 // Redirect/hijack the thread
4412 // Redirection vs. Hijacking:
4414 // JIT'd code does not generally poll to see if a GC wants to run. Instead, the JIT
4415 // records "GC info" describing where the "safe points" are in the code. While we
4416 // have a native thread suspended in JIT'd code, we can see which instruction it
4417 // is currently executing. If that instruction is a safe point, then the GC may proceed.
4418 // Returning from a managed method is *always* a safe point, so if the thread is not
4419 // currently at a safe point we can "hijack" its return address. Once that it done,
4420 // if/when the method tried to return the thread will be sent to a hijack routine
4421 // that will leave cooperative mode and wait for the GC to complete.
4423 // If the thread is already at a safe point, you might think we could simply leave it
4424 // suspended and proceed with the GC. In principle, this should be what we do.
4425 // However, various historical OS bugs prevent this from working. The problem is that
4426 // we are not guaranteed to capture an accurate CONTEXT (register state) for a suspended
4427 // thread. So instead, we "redirect" the thread, by overwriting its instruction pointer.
4428 // We then resume the thread, and it immediately starts executing our "redirect" routine,
4429 // which leaves cooperative mode and waits for the GC to complete.
4431 // See code:Thread#SuspendingTheRuntime for more
4432 HRESULT ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason)
4438 GC_TRIGGERS; // CLREvent::Wait is GC_TRIGGERS
4442 DISABLED(GC_TRIGGERS);
4448 Thread *pCurThread = GetThread();
4450 // The thread we're working on (suspending, etc.) right now.
4451 Thread *thread = NULL;
4453 // The number of threads we found in COOP mode.
4454 LONG countThreads = 0;
4458 // Caller is expected to be holding the ThreadStore lock. Also, caller must
4459 // have set GcInProgress before coming here, or things will break;
4460 _ASSERTE(ThreadStore::HoldingThreadStore() || IsAtProcessExit());
4461 _ASSERTE(GCHeapUtilities::IsGCInProgress() );
4463 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Thread::SuspendRuntime(reason=0x%x)\n", reason);
4466 #ifdef PROFILING_SUPPORTED
4467 // If the profiler desires information about GCs, then let it know that one
4470 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
4471 _ASSERTE(reason != ThreadSuspend::SUSPEND_FOR_DEBUGGER);
4472 _ASSERTE(reason != ThreadSuspend::SUSPEND_FOR_DEBUGGER_SWEEP);
4475 g_profControlBlock.pProfInterface->RuntimeSuspendStarted(
4476 GCSuspendReasonToProfSuspendReason(reason));
4480 // Notify the profiler that the thread that is actually doing the GC is 'suspended',
4481 // meaning that it is doing stuff other than run the managed code it was before the
4483 g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)pCurThread);
4487 #endif // PROFILING_SUPPORTED
4490 // If this thread is running at low priority, boost its priority. We remember the old
4491 // priority so that we can restore it in ResumeRuntime.
4493 if (pCurThread) // concurrent GC occurs on threads we don't know about
4495 _ASSERTE(pCurThread->m_Priority == INVALID_THREAD_PRIORITY);
4496 int priority = pCurThread->GetThreadPriority();
4497 if (priority < THREAD_PRIORITY_NORMAL)
4499 pCurThread->m_Priority = priority;
4500 pCurThread->SetThreadPriority(THREAD_PRIORITY_NORMAL);
4504 // From this point until the end of the function, consider all active thread
4505 // suspension to be in progress. This is mainly to give the profiler API a hint
4506 // that trying to suspend a thread (in order to walk its stack) could delay the
4507 // overall EE suspension. So the profiler API would early-abort the stackwalk
4509 SuspendRuntimeInProgressHolder hldSuspendRuntimeInProgress;
4512 // Flush the store buffers on all CPUs, to ensure two things:
4513 // - we get a reliable reading of the threads' m_fPreemptiveGCDisabled state
4514 // - other threads see that g_TrapReturningThreads is set
4515 // See VSW 475315 and 488918 for details.
4517 ::FlushProcessWriteBuffers();
4520 // Make a pass through all threads. We do a couple of things here:
4521 // 1) we count the number of threads that are observed to be in cooperative mode.
4522 // 2) for threads currently running managed code, we try to redirect/jihack them.
4524 // Later we will make more passes where we do roughly the same thing. We should combine the two loops.
4527 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
4529 if (thread->HasThreadState(Thread::TS_GCSuspendPending))
4531 thread->ResetThreadState(Thread::TS_GCSuspendPending);
4534 if (thread == pCurThread)
4537 STRESS_LOG3(LF_SYNC, LL_INFO10000, " Inspecting thread 0x%x ID 0x%x coop mode = %d\n",
4538 thread, thread->GetThreadId(), thread->m_fPreemptiveGCDisabled.Load());
4540 // Nothing confusing left over from last time.
4541 _ASSERTE((thread->m_State & Thread::TS_GCSuspendPending) == 0);
4543 // Threads can be in Preemptive or Cooperative GC mode. Threads cannot switch
4544 // to Cooperative mode without special treatment when a GC is happening.
4545 if (thread->m_fPreemptiveGCDisabled)
4547 // Check a little more carefully. Threads might sneak out without telling
4548 // us, because of inlined PInvoke which doesn't go through RareEnablePreemptiveGC.
4550 #ifdef DISABLE_THREADSUSPEND
4551 // On platforms that do not support safe thread suspension, we do one of two things:
4553 // - If we're on a Unix platform where hijacking is enabled, we attempt
4554 // to inject a GC suspension which will try to redirect or hijack the
4555 // thread to get it to a safe point.
4557 // - Otherwise, we rely on the GCPOLL mechanism enabled by
4558 // TrapReturningThreads.
4560 // When reading shared state we need to erect appropriate memory barriers.
4561 // The interlocked operation below ensures that any future reads on this
4562 // thread will happen after any earlier writes on a different thread.
4564 // <TODO> Need more careful review of this </TODO>
4566 FastInterlockOr(&thread->m_fPreemptiveGCDisabled, 0);
4568 if (thread->m_fPreemptiveGCDisabled)
4570 FastInterlockOr((ULONG *) &thread->m_State, Thread::TS_GCSuspendPending);
4573 #if defined(FEATURE_HIJACK) && defined(PLATFORM_UNIX)
4574 bool gcSuspensionSignalSuccess = thread->InjectGcSuspension();
4575 if (!gcSuspensionSignalSuccess)
4577 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Thread::SuspendRuntime() - Failed to raise GC suspension signal for thread %p.\n", thread);
4579 #endif // FEATURE_HIJACK && PLATFORM_UNIX
4582 #else // DISABLE_THREADSUSPEND
4584 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
4585 DWORD dwSwitchCount = 0;
4589 // We can not allocate memory after we suspend a thread.
4590 // Otherwise, we may deadlock the process, because the thread we just suspended
4591 // might hold locks we would need to acquire while allocating.
4592 ThreadStore::AllocateOSContext();
4595 DWORD startSuspend = g_SuspendStatistics.GetTime();
4599 // Suspend the native thread.
4601 Thread::SuspendThreadResult str = thread->SuspendThread();
4603 // We should just always build with this TIME_SUSPEND stuff, and report the results via ETW.
4605 g_SuspendStatistics.osSuspend.Accumulate(
4606 SuspendStatistics::GetElapsed(startSuspend,
4607 g_SuspendStatistics.GetTime()));
4609 if (str == Thread::STR_Success)
4610 g_SuspendStatistics.cntOSSuspendResume++;
4612 g_SuspendStatistics.cntFailedSuspends++;
4615 if (str == Thread::STR_NoStressLog)
4617 STRESS_LOG2(LF_SYNC, LL_ERROR, " ERROR: Could not suspend thread 0x%x, result = %d\n", thread, str);
4620 if (thread->m_fPreemptiveGCDisabled)
4622 // We now know for sure that the thread is still in cooperative mode. If it's in JIT'd code, here
4623 // is where we try to hijack/redirect the thread. If it's in VM code, we have to just let the VM
4624 // finish what it's doing.
4626 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
4627 // Only check for HandledJITCase if we actually suspended the thread.
4628 if (str == Thread::STR_Success)
4630 Thread::WorkingOnThreadContextHolder workingOnThreadContext(thread);
4633 // Note that thread->HandledJITCase is not a simple predicate - it actually will hijack the thread if that's possible.
4634 // So HandledJITCase can do one of these:
4636 // - Return TRUE, in which case it's our responsibility to redirect the thread
4637 // - Return FALSE after hijacking the thread - we shouldn't try to redirect
4638 // - Return FALSE but not hijack the thread - there's nothing we can do either
4640 // Here is another great opportunity for refactoring :)
4642 if (workingOnThreadContext.Acquired() && thread->HandledJITCase())
4644 // Redirect thread so we can capture a good thread context
4645 // (GetThreadContext is not sufficient, due to an OS bug).
4646 if (!thread->CheckForAndDoRedirectForGC())
4649 g_SuspendStatistics.cntFailedRedirections++;
4651 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Failed to CheckForAndDoRedirectForGC(). Retry suspension for thread %p\n", thread);
4652 thread->ResumeThread();
4653 __SwitchToThread(0, ++dwSwitchCount);
4654 goto RetrySuspension;
4658 g_SuspendStatistics.cntRedirections++;
4660 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Thread::SuspendRuntime() - Thread %p redirected().\n", thread);
4663 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
4665 FastInterlockOr((ULONG *) &thread->m_State, Thread::TS_GCSuspendPending);
4669 // Only resume if we actually suspended the thread above.
4670 if (str == Thread::STR_Success)
4671 thread->ResumeThread();
4673 STRESS_LOG1(LF_SYNC, LL_INFO1000, " Thread 0x%x is in cooperative needs to rendezvous\n", thread);
4676 if (str == Thread::STR_Success)
4678 STRESS_LOG1(LF_SYNC, LL_WARNING, " Inspecting thread 0x%x was in cooperative, but now is not\n", thread);
4680 thread->ResumeThread();
4683 if (str == Thread::STR_SwitchedOut) {
4684 STRESS_LOG1(LF_SYNC, LL_WARNING, " Inspecting thread 0x%x was in cooperative, but now is switched out\n", thread);
4687 _ASSERTE(str == Thread::STR_Failure || str == Thread::STR_UnstartedOrDead);
4688 STRESS_LOG3(LF_SYNC, LL_ERROR, " ERROR: Could not suspend thread 0x%x, result = %d, lastError = 0x%x\n", thread, str, GetLastError());
4691 #endif // DISABLE_THREADSUSPEND
4696 // To ensure 0 CPU utilization for FAS (see implementation of PauseAPC)
4697 // we queue the APC to all interruptable threads.
4698 if(g_IsPaused && (thread->m_State & Thread::TS_Interruptible))
4700 HANDLE handle = thread->GetThreadHandle();
4701 QueueUserAPC((PAPCFUNC)PauseAPC, handle, APC_Code);
4710 Thread *InnerThread = NULL;
4712 while ((InnerThread = ThreadStore::GetThreadList(InnerThread)) != NULL)
4714 if (InnerThread != pCurThread &&
4715 (InnerThread->m_State & Thread::TS_GCSuspendPending) != 0)
4720 _ASSERTE(countCheck == countThreads);
4726 // Now we keep retrying until we find that no threads are in cooperative mode. This should be merged into
4729 while (countThreads)
4731 _ASSERTE (thread == NULL);
4732 STRESS_LOG1(LF_SYNC, LL_INFO1000, " A total of %d threads need to rendezvous\n", countThreads);
4733 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
4735 if (thread == pCurThread)
4738 if (thread->HasThreadState(Thread::TS_BlockGCForSO))
4740 // The thread is trying to block for GC. But we don't have enough stack to do
4742 // We will let the thread switch back to cooperative mode, and continue running.
4743 if (thread->m_fPreemptiveGCDisabled.Load() == 0)
4745 if (!thread->HasThreadState(Thread::TS_GCSuspendPending))
4747 thread->SetThreadState(Thread::TS_GCSuspendPending);
4750 thread->ResetThreadState(Thread::TS_BlockGCForSO);
4751 FastInterlockOr (&thread->m_fPreemptiveGCDisabled, 1);
4755 if ((thread->m_State & Thread::TS_GCSuspendPending) == 0)
4758 if (!thread->m_fPreemptiveGCDisabled)
4760 // Inlined N/Direct can sneak out to preemptive without actually checking.
4761 // If we find one, we can consider it suspended (since it can't get back in).
4762 STRESS_LOG1(LF_SYNC, LL_INFO1000, " Thread %x went preemptive it is at a GC safe point\n", thread);
4764 thread->ResetThreadState(Thread::TS_GCSuspendPending);
4766 // To ensure 0 CPU utilization for FAS (see implementation of PauseAPC)
4767 // we queue the APC to all interruptable threads.
4768 if(g_IsPaused && (thread->m_State & Thread::TS_Interruptible))
4770 HANDLE handle = thread->GetThreadHandle();
4771 QueueUserAPC((PAPCFUNC)PauseAPC, handle, APC_Code);
4776 if (countThreads == 0)
4782 DWORD dbgStartTimeout = GetTickCount();
4785 // If another thread is trying to do a GC, there is a chance of deadlock
4786 // because this thread holds the threadstore lock and the GC thread is stuck
4787 // trying to get it, so this thread must bail and do a retry after the GC completes.
4789 // <REVISIT> Shouldn't we do this only if *this* thread isn't attempting a GC? We're mostly
4790 // done suspending the EE at this point - why give up just because another thread wants
4791 // to do exactly the same thing? Note that GetGCThreadAttemptingSuspend will never (AFAIK)
4792 // return the current thread here, because we NULL it out after obtaining the thread store lock. </REVISIT>
4794 if (m_pThreadAttemptingSuspendForGC != NULL && m_pThreadAttemptingSuspendForGC != pCurThread)
4796 #ifdef PROFILING_SUPPORTED
4797 // Must let the profiler know that this thread is aborting its attempt at suspending
4799 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
4800 g_profControlBlock.pProfInterface->RuntimeSuspendAborted();
4803 #endif // PROFILING_SUPPORTED
4805 STRESS_LOG0(LF_SYNC, LL_ALWAYS, "Thread::SuspendRuntime() - Timing out.\n");
4806 return (ERROR_TIMEOUT);
4810 DWORD startWait = g_SuspendStatistics.GetTime();
4814 // Wait for at least one thread to tell us it's left cooperative mode.
4815 // we do this by waiting on g_pGCSuspendEvent. We cannot simply wait forever, because we
4816 // might have done return-address hijacking on a thread, and that thread might not
4817 // return from the method we hijacked (maybe it calls into some other managed code that
4818 // executes a long loop, for example). We we wait with a timeout, and retry hijacking/redirection.
4820 // This is unfortunate, because it means that in some cases we wait for PING_JIT_TIMEOUT
4821 // milliseconds, causing long GC pause times.
4823 // We should fix this, by calling SwitchToThread/Sleep(0) a few times before waiting on the event.
4824 // This will not fix it 100% of the time (we may still have to wait on the event), but
4825 // the event is needed to work around limitations of SwitchToThread/Sleep(0).
4827 // For now, we simply wait.
4830 res = g_pGCSuspendEvent->Wait(PING_JIT_TIMEOUT, FALSE);
4834 g_SuspendStatistics.wait.Accumulate(
4835 SuspendStatistics::GetElapsed(startWait,
4836 g_SuspendStatistics.GetTime()));
4838 g_SuspendStatistics.cntWaits++;
4839 if (res == WAIT_TIMEOUT)
4840 g_SuspendStatistics.cntWaitTimeouts++;
4843 if (res == WAIT_TIMEOUT || res == WAIT_IO_COMPLETION)
4845 STRESS_LOG1(LF_SYNC, LL_INFO1000, " Timed out waiting for rendezvous event %d threads remaining\n", countThreads);
4847 DWORD dbgEndTimeout = GetTickCount();
4849 if ((dbgEndTimeout > dbgStartTimeout) &&
4850 (dbgEndTimeout - dbgStartTimeout > g_pConfig->SuspendDeadlockTimeout()))
4852 // Do not change this to _ASSERTE.
4853 // We want to catch the state of the machine at the
4854 // time when we can not suspend some threads.
4855 // It takes too long for _ASSERTE to stop the process.
4857 _ASSERTE(!"Timed out trying to suspend EE due to thread");
4859 _ASSERTE (thread == NULL);
4860 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
4862 if (thread == pCurThread)
4865 if ((thread->m_State & Thread::TS_GCSuspendPending) == 0)
4868 if (thread->m_fPreemptiveGCDisabled)
4870 DWORD id = thread->m_OSThreadId;
4871 if (id == 0xbaadf00d)
4873 sprintf_s (message, COUNTOF(message), "Thread CLR ID=%x cannot be suspended",
4874 thread->GetThreadId());
4878 sprintf_s (message, COUNTOF(message), "Thread OS ID=%x cannot be suspended",
4881 DbgAssertDialog(__FILE__, __LINE__, message);
4884 // if we continue from the assert we'll reset the time
4885 dbgStartTimeout = GetTickCount();
4889 #if defined(FEATURE_HIJACK) && defined(PLATFORM_UNIX)
4890 _ASSERTE (thread == NULL);
4891 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
4893 if (thread == pCurThread)
4896 if ((thread->m_State & Thread::TS_GCSuspendPending) == 0)
4899 if (!thread->m_fPreemptiveGCDisabled)
4902 // When we tried to inject the suspension before, we may have been in a place
4903 // where it wasn't possible. Try one more time.
4904 bool gcSuspensionSignalSuccess = thread->InjectGcSuspension();
4905 if (!gcSuspensionSignalSuccess)
4907 // If we failed to raise the signal for some reason, just log it and move on.
4908 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Thread::SuspendRuntime() - Failed to raise GC suspension signal for thread %p.\n", thread);
4913 #ifndef DISABLE_THREADSUSPEND
4914 // all these threads should be in cooperative mode unless they have
4915 // set their SafeEvent on the way out. But there's a race between
4916 // when we time out and when they toggle their mode, so sometimes
4917 // we will suspend a thread that has just left.
4918 _ASSERTE (thread == NULL);
4919 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
4921 if (thread == pCurThread)
4924 if ((thread->m_State & Thread::TS_GCSuspendPending) == 0)
4927 if (!thread->m_fPreemptiveGCDisabled)
4930 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
4933 // We can not allocate memory after we suspend a thread.
4934 // Otherwise, we may deadlock the process when CLR is hosted.
4935 ThreadStore::AllocateOSContext();
4938 DWORD startSuspend = g_SuspendStatistics.GetTime();
4941 Thread::SuspendThreadResult str = thread->SuspendThread();
4944 g_SuspendStatistics.osSuspend.Accumulate(
4945 SuspendStatistics::GetElapsed(startSuspend,
4946 g_SuspendStatistics.GetTime()));
4948 if (str == Thread::STR_Success)
4949 g_SuspendStatistics.cntOSSuspendResume++;
4951 g_SuspendStatistics.cntFailedSuspends++;
4954 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
4955 // Only check HandledJITCase if we actually suspended the thread, and
4956 // the thread is in cooperative mode.
4957 // See comment at the previous invocation of HandledJITCase - it does
4958 // more than you think!
4959 if (str == Thread::STR_Success && thread->m_fPreemptiveGCDisabled)
4961 Thread::WorkingOnThreadContextHolder workingOnThreadContext(thread);
4962 if (workingOnThreadContext.Acquired() && thread->HandledJITCase())
4964 // Redirect thread so we can capture a good thread context
4965 // (GetThreadContext is not sufficient, due to an OS bug).
4966 if (!thread->CheckForAndDoRedirectForGC())
4969 g_SuspendStatistics.cntFailedRedirections++;
4971 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Failed to CheckForAndDoRedirectForGC(). Retry suspension 2 for thread %p\n", thread);
4972 thread->ResumeThread();
4973 goto RetrySuspension2;
4977 g_SuspendStatistics.cntRedirections++;
4981 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
4983 if (str == Thread::STR_Success)
4984 thread->ResumeThread();
4986 #endif // DISABLE_THREADSUSPEND
4989 if (res == WAIT_OBJECT_0)
4991 g_pGCSuspendEvent->Reset();
4996 // No WAIT_FAILED, WAIT_ABANDONED, etc.
4997 _ASSERTE(!"unexpected wait termination during gc suspension");
5001 #ifdef PROFILING_SUPPORTED
5002 // If a profiler is keeping track of GC events, notify it
5004 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
5005 g_profControlBlock.pProfInterface->RuntimeSuspendFinished();
5008 #endif // PROFILING_SUPPORTED
5011 if (reason == ThreadSuspend::SUSPEND_FOR_GC) {
5013 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
5015 thread->DisableStressHeap();
5016 _ASSERTE (!thread->HasThreadState(Thread::TS_GCSuspendPending));
5021 // We know all threads are in preemptive mode, so go ahead and reset the event.
5022 g_pGCSuspendEvent->Reset();
5026 // Now that the EE has been suspended, let's see if any oustanding
5027 // gcstress instruction updates need to occur. Each thread can
5028 // have only one pending at a time.
5031 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
5033 thread->CommitGCStressInstructionUpdate();
5035 #endif // HAVE_GCCOVER
5037 STRESS_LOG0(LF_SYNC, LL_INFO1000, "Thread::SuspendRuntime() - Success\n");
5043 void Thread::CommitGCStressInstructionUpdate()
5053 if (HasPendingGCStressInstructionUpdate())
5055 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
5057 *m_pbDestCode = *m_pbSrcCode;
5059 #elif defined(_TARGET_ARM_)
5061 if (GetARMInstructionLength(m_pbDestCode) == 2)
5062 *(WORD*)m_pbDestCode = *(WORD*)m_pbSrcCode;
5064 *(DWORD*)m_pbDestCode = *(DWORD*)m_pbSrcCode;
5066 #elif defined(_TARGET_ARM64_)
5068 *(DWORD*)m_pbDestCode = *(DWORD*)m_pbSrcCode;
5072 *m_pbDestCode = *m_pbSrcCode;
5076 ClearGCStressInstructionUpdate();
5080 #endif // HAVE_GCCOVER
5084 void EnableStressHeapHelper()
5086 WRAPPER_NO_CONTRACT;
5091 // We're done with our GC. Let all the threads run again.
5092 // By this point we've already unblocked most threads. This just releases the ThreadStore lock.
5093 void ThreadSuspend::ResumeRuntime(BOOL bFinishedGC, BOOL SuspendSucceded)
5097 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
5101 Thread *pCurThread = GetThread();
5103 // Caller is expected to be holding the ThreadStore lock. But they must have
5104 // reset GcInProgress, or threads will continue to suspend themselves and won't
5105 // be resumed until the next GC.
5106 _ASSERTE(IsGCSpecialThread() || ThreadStore::HoldingThreadStore());
5107 _ASSERTE(!GCHeapUtilities::IsGCInProgress() );
5109 STRESS_LOG2(LF_SYNC, LL_INFO1000, "Thread::ResumeRuntime(finishedGC=%d, SuspendSucceeded=%d) - Start\n", bFinishedGC, SuspendSucceded);
5112 // Notify everyone who cares, that this suspension is over, and this thread is going to go do other things.
5116 #ifdef PROFILING_SUPPORTED
5117 // Need to give resume event for the GC thread
5119 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
5122 g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)pCurThread);
5126 #endif // PROFILING_SUPPORTED
5129 DWORD startRelease = g_SuspendStatistics.GetTime();
5133 // Unlock the thread store. At this point, all threads should be allowed to run.
5135 ThreadSuspend::UnlockThreadStore();
5138 g_SuspendStatistics.releaseTSL.Accumulate(SuspendStatistics::GetElapsed(startRelease,
5139 g_SuspendStatistics.GetTime()));
5142 #ifdef PROFILING_SUPPORTED
5144 // This thread is logically "resuming" from a GC now. Tell the profiler.
5147 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
5149 g_profControlBlock.pProfInterface->RuntimeResumeFinished();
5152 #endif // PROFILING_SUPPORTED
5155 // If we raised this thread's priority in SuspendRuntime, we restore it here.
5159 if (pCurThread->m_Priority != INVALID_THREAD_PRIORITY)
5161 pCurThread->SetThreadPriority(pCurThread->m_Priority);
5162 pCurThread->m_Priority = INVALID_THREAD_PRIORITY;
5166 STRESS_LOG0(LF_SYNC, LL_INFO1000, "Thread::ResumeRuntime() - End\n");
5171 //****************************************************************************************
5172 // This will resume the thread at the location of redirection.
5174 int RedirectedThrowControlExceptionFilter(
5175 PEXCEPTION_POINTERS pExcepPtrs // Exception data
5178 // !!! Do not use a non-static contract here.
5179 // !!! Contract may insert an exception handling record.
5180 // !!! This function assumes that GetCurrentSEHRecord() returns the exception record set up in
5181 // !!! ThrowControlForThread
5182 STATIC_CONTRACT_NOTHROW;
5183 STATIC_CONTRACT_GC_NOTRIGGER;
5184 STATIC_CONTRACT_MODE_ANY;
5186 if (pExcepPtrs->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
5188 return EXCEPTION_CONTINUE_SEARCH;
5191 // Get the thread handle
5192 Thread *pThread = GetThread();
5196 STRESS_LOG0(LF_SYNC, LL_INFO100, "In RedirectedThrowControlExceptionFilter\n");
5198 // If we get here via COM+ exception, gc-mode is unknown. We need it to
5199 // be cooperative for this function.
5200 _ASSERTE (pThread->PreemptiveGCDisabled());
5202 _ASSERTE(pExcepPtrs->ExceptionRecord->ExceptionCode == BOOTUP_EXCEPTION_COMPLUS);
5204 // Copy the saved context record into the EH context;
5205 CONTEXT *pCtx = pThread->m_OSContext;
5206 ReplaceExceptionContextRecord(pExcepPtrs->ContextRecord, pCtx);
5208 /////////////////////////////////////////////////////////////////////////////
5209 // NOTE: Ugly, ugly workaround.
5210 // We need to resume the thread into the managed code where it was redirected,
5211 // and the corresponding ESP is below the current one. But C++ expects that
5212 // on an EXCEPTION_CONTINUE_EXECUTION that the ESP will be above where it has
5213 // installed the SEH handler. To solve this, we need to remove all handlers
5214 // that reside above the resumed ESP, but we must leave the OS-installed
5215 // handler at the top, so we grab the top SEH handler, call
5216 // PopSEHRecords which will remove all SEH handlers above the target ESP and
5217 // then link the OS handler back in with SetCurrentSEHRecord.
5219 // Get the special OS handler and save it until PopSEHRecords is done
5220 EXCEPTION_REGISTRATION_RECORD *pCurSEH = GetCurrentSEHRecord();
5222 // Unlink all records above the target resume ESP
5223 PopSEHRecords((LPVOID)(size_t)pCtx->Esp);
5225 // Link the special OS handler back in to the top
5226 pCurSEH->Next = GetCurrentSEHRecord();
5228 // Register the special OS handler as the top handler with the OS
5229 SetCurrentSEHRecord(pCurSEH);
5231 // Resume execution at point where thread was originally redirected
5232 return (EXCEPTION_CONTINUE_EXECUTION);
5235 #endif // !FEATURE_PAL
5237 // Resume a thread at this location, to persuade it to throw a ThreadStop. The
5238 // exception handler needs a reasonable idea of how large this method is, so don't
5239 // add lots of arbitrary code here.
5241 ThrowControlForThread(
5242 #ifdef WIN64EXCEPTIONS
5243 FaultingExceptionFrame *pfef
5244 #endif // WIN64EXCEPTIONS
5247 STATIC_CONTRACT_THROWS;
5248 STATIC_CONTRACT_GC_NOTRIGGER;
5250 Thread *pThread = GetThread();
5252 _ASSERTE(pThread->m_OSContext);
5254 _ASSERTE(pThread->PreemptiveGCDisabled());
5256 #ifdef FEATURE_STACK_PROBE
5257 if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
5259 RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), pThread);
5263 // Check if we can start abort
5264 // We use InducedThreadRedirect as a marker to tell stackwalker that a thread is redirected from JIT code.
5265 // This is to distinguish a thread is in Preemptive mode and in JIT code.
5266 // After stackcrawl, we change to InducedThreadStop.
5267 if (pThread->ThrewControlForThread() == Thread::InducedThreadRedirect ||
5268 pThread->ThrewControlForThread() == Thread::InducedThreadRedirectAtEndOfCatch)
5270 _ASSERTE((pThread->m_OSContext->ContextFlags & CONTEXT_ALL) == CONTEXT_ALL);
5271 if (!pThread->ReadyForAbort())
5273 STRESS_LOG0(LF_SYNC, LL_INFO100, "ThrowControlForThread resume\n");
5274 pThread->ResetThrowControlForThread();
5275 // Thread abort is not allowed at this point
5276 #ifndef WIN64EXCEPTIONS
5278 RaiseException(BOOTUP_EXCEPTION_COMPLUS,0,0,NULL);
5280 __except(RedirectedThrowControlExceptionFilter(GetExceptionInformation()))
5282 _ASSERTE(!"Should not reach here");
5284 #else // WIN64EXCEPTIONS
5285 RtlRestoreContext(pThread->m_OSContext, NULL);
5286 #endif // !WIN64EXCEPTIONS
5287 _ASSERTE(!"Should not reach here");
5289 pThread->SetThrowControlForThread(Thread::InducedThreadStop);
5292 #if defined(WIN64EXCEPTIONS)
5293 *(TADDR*)pfef = FaultingExceptionFrame::GetMethodFrameVPtr();
5294 *pfef->GetGSCookiePtr() = GetProcessGSCookie();
5295 #else // WIN64EXCEPTIONS
5296 FrameWithCookie<FaultingExceptionFrame> fef;
5297 FaultingExceptionFrame *pfef = &fef;
5298 #endif // WIN64EXCEPTIONS
5299 pfef->InitAndLink(pThread->m_OSContext);
5301 // !!! Can not assert here. Sometimes our EHInfo for catch clause extends beyond
5302 // !!! Jit_EndCatch. Not sure if we have guarantee on catch clause.
5303 //_ASSERTE (pThread->ReadyForAbort());
5305 STRESS_LOG0(LF_SYNC, LL_INFO100, "ThrowControlForThread Aborting\n");
5307 // Here we raise an exception.
5308 RaiseComPlusException();
5311 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
5312 // This function is called by UserAbort and StopEEAndUnwindThreads.
5313 // It forces a thread to abort if allowed and the thread is running managed code.
5314 BOOL Thread::HandleJITCaseForAbort()
5322 _ASSERTE(ThreadStore::HoldingThreadStore());
5324 WorkingOnThreadContextHolder workingOnThreadContext(this);
5325 if (!workingOnThreadContext.Acquired())
5330 _ASSERTE (m_fPreemptiveGCDisabled);
5333 ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_EXCEPTION_REQUEST;
5334 BOOL success = EEGetThreadContext(this, &ctx);
5335 _ASSERTE(success && "Thread::HandleJITCaseForAbort : Failed to get thread context");
5339 success = IsContextSafeToRedirect(&ctx);
5344 PCODE curIP = GetIP(&ctx);
5346 // check if this is code managed by the code manager (ie. in the code heap)
5347 if (ExecutionManager::IsManagedCode(curIP))
5349 return ResumeUnderControl(&ctx);
5356 // Threads suspended by the Win32 ::SuspendThread() are resumed in two ways. If we
5357 // suspended them in error, they are resumed via the Win32 ::ResumeThread(). But if
5358 // this is the HandledJIT() case and the thread is in fully interruptible code, we
5359 // can resume them under special control. ResumeRuntime and UserResume are cases
5362 // The suspension has done its work (e.g. GC or user thread suspension). But during
5363 // the resumption we may have more that we want to do with this thread. For example,
5364 // there may be a pending ThreadAbort request. Instead of resuming the thread at its
5365 // current EIP, we tweak its resumption point via the thread context. Then it starts
5366 // executing at a new spot where we can have our way with it.
5368 BOOL Thread::ResumeUnderControl(CONTEXT *pCtx)
5376 BOOL fSuccess = FALSE;
5378 LOG((LF_APPDOMAIN, LL_INFO100, "ResumeUnderControl %x\n", GetThreadId()));
5382 m_OSContext->ContextFlags = CONTEXT_ALL | CONTEXT_EXCEPTION_REQUEST;
5383 fSucceeded = EEGetThreadContext(this, m_OSContext);
5387 if (GetIP(pCtx) != GetIP(m_OSContext))
5391 fSucceeded = IsContextSafeToRedirect(m_OSContext);
5396 PCODE resumePC = GetIP(m_OSContext);
5397 SetIP(m_OSContext, GetEEFuncEntryPoint(THROW_CONTROL_FOR_THREAD_FUNCTION));
5398 SetThrowControlForThread(InducedThreadRedirect);
5399 STRESS_LOG1(LF_SYNC, LL_INFO100, "ResumeUnderControl for Thread %p\n", this);
5401 #ifdef _TARGET_AMD64_
5402 // We need to establish the return value on the stack in the redirection stub, to
5403 // achieve crawlability. We use 'rcx' as the way to communicate the return value.
5404 // However, we are going to crawl in ReadyForAbort and we are going to resume in
5405 // ThrowControlForThread using m_OSContext. It's vital that the original correct
5406 // Rcx is present at those times, or we will have corrupted Rcx at the point of
5408 UINT_PTR keepRcx = m_OSContext->Rcx;
5410 m_OSContext->Rcx = (UINT_PTR)resumePC;
5411 #endif // _TARGET_AMD64_
5413 #if defined(_TARGET_ARM_)
5414 // We save the original ControlPC in LR on ARM.
5415 UINT_PTR originalLR = m_OSContext->Lr;
5416 m_OSContext->Lr = (UINT_PTR)resumePC;
5418 // Since we have set a new IP, we have to clear conditional execution flags too.
5419 UINT_PTR originalCpsr = m_OSContext->Cpsr;
5420 ClearITState(m_OSContext);
5421 #endif // _TARGET_ARM_
5423 EESetThreadContext(this, m_OSContext);
5426 // Restore the original LR now that the OS context has been updated to resume @ redirection function.
5427 m_OSContext->Lr = originalLR;
5428 m_OSContext->Cpsr = originalCpsr;
5429 #endif // _TARGET_ARM_
5431 #ifdef _TARGET_AMD64_
5433 m_OSContext->Rcx = keepRcx;
5434 #endif // _TARGET_AMD64_
5436 SetIP(m_OSContext, resumePC);
5442 _ASSERTE(!"Couldn't obtain thread context -- StopRequest delayed");
5447 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
5450 PCONTEXT Thread::GetAbortContext ()
5452 LIMITED_METHOD_CONTRACT;
5454 LOG((LF_EH, LL_INFO100, "Returning abort context: %p\n", m_OSContext));
5459 //****************************************************************************
5460 // Return true if we've Suspended the runtime,
5461 // False if we still need to sweep.
5462 //****************************************************************************
5463 bool Thread::SysStartSuspendForDebug(AppDomain *pAppDomain)
5471 Thread *pCurThread = GetThread();
5472 Thread *thread = NULL;
5474 if (IsAtProcessExit())
5476 LOG((LF_CORDB, LL_INFO1000,
5477 "SUSPEND: skipping suspend due to process detach.\n"));
5481 LOG((LF_CORDB, LL_INFO1000, "[0x%x] SUSPEND: starting suspend. Trap count: %d\n",
5482 pCurThread ? pCurThread->GetThreadId() : (DWORD) -1, g_TrapReturningThreads.Load()));
5484 // Caller is expected to be holding the ThreadStore lock
5485 _ASSERTE(ThreadStore::HoldingThreadStore() || IsAtProcessExit());
5488 // NOTE::NOTE::NOTE::NOTE::NOTE
5489 // This function has parallel logic in SuspendRuntime. Please make
5490 // sure to make appropriate changes there as well.
5492 _ASSERTE(m_DebugWillSyncCount == -1);
5493 m_DebugWillSyncCount++;
5495 // From this point until the end of the function, consider all active thread
5496 // suspension to be in progress. This is mainly to give the profiler API a hint
5497 // that trying to suspend a thread (in order to walk its stack) could delay the
5498 // overall EE suspension. So the profiler API would early-abort the stackwalk
5500 ThreadSuspend::SuspendRuntimeInProgressHolder hldSuspendRuntimeInProgress;
5502 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
5505 //<REVISIT_TODO> @todo APPD This needs to be finished, replaced, or yanked --MiPanitz</REVISIT_TODO>
5506 if (m_DebugAppDomainTarget != NULL &&
5507 thread->GetDomain() != m_DebugAppDomainTarget)
5513 // Don't try to suspend threads that you've left suspended.
5514 if (thread->m_StateNC & TSNC_DebuggerUserSuspend)
5517 if (thread == pCurThread)
5519 LOG((LF_CORDB, LL_INFO1000,
5520 "[0x%x] SUSPEND: marking current thread.\n",
5521 thread->GetThreadId()));
5523 _ASSERTE(!thread->m_fPreemptiveGCDisabled);
5525 // Mark this thread so it trips when it tries to re-enter
5526 // after completing this call.
5527 thread->SetupForSuspension(TS_DebugSuspendPending);
5528 thread->MarkForSuspension(TS_DebugSuspendPending);
5532 thread->SetupForSuspension(TS_DebugSuspendPending);
5534 // Threads can be in Preemptive or Cooperative GC mode.
5535 // Threads cannot switch to Cooperative mode without special
5536 // treatment when a GC is happening. But they can certainly
5537 // switch back and forth during a debug suspension -- until we
5538 // can get their Pending bit set.
5540 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
5541 DWORD dwSwitchCount = 0;
5543 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
5545 // We can not allocate memory after we suspend a thread.
5546 // Otherwise, we may deadlock the process when CLR is hosted.
5547 ThreadStore::AllocateOSContext();
5549 #ifdef DISABLE_THREADSUSPEND
5550 // On platforms that do not support safe thread suspension we have
5551 // to rely on the GCPOLL mechanism.
5553 // When we do not suspend the target thread we rely on the GCPOLL
5554 // mechanism enabled by TrapReturningThreads. However when reading
5555 // shared state we need to erect appropriate memory barriers. So
5556 // the interlocked operation below ensures that any future reads on
5557 // this thread will happen after any earlier writes on a different
5559 SuspendThreadResult str = STR_Success;
5560 FastInterlockOr(&thread->m_fPreemptiveGCDisabled, 0);
5562 SuspendThreadResult str = thread->SuspendThread();
5563 #endif // DISABLE_THREADSUSPEND
5565 if (thread->m_fPreemptiveGCDisabled && str == STR_Success)
5568 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
5569 WorkingOnThreadContextHolder workingOnThreadContext(thread);
5570 if (workingOnThreadContext.Acquired() && thread->HandledJITCase())
5572 // Redirect thread so we can capture a good thread context
5573 // (GetThreadContext is not sufficient, due to an OS bug).
5574 // If we don't succeed (should only happen on Win9X, due to
5575 // a different OS bug), we must resume the thread and try
5577 if (!thread->CheckForAndDoRedirectForDbg())
5579 thread->ResumeThread();
5580 __SwitchToThread(0, ++dwSwitchCount);
5581 goto RetrySuspension;
5584 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
5586 // Remember that this thread will be running to a safe point
5587 FastInterlockIncrement(&m_DebugWillSyncCount);
5589 // When the thread reaches a safe place, it will wait
5590 // on the DebugSuspendEvent which clients can set when they
5591 // want to release us.
5592 thread->MarkForSuspension(TS_DebugSuspendPending |
5596 #ifdef DISABLE_THREADSUSPEND
5597 // There'a a race above between the moment we first check m_fPreemptiveGCDisabled
5598 // and the moment we enable TrapReturningThreads in MarkForSuspension. However,
5599 // nothing bad happens if the thread has transitioned to preemptive before marking
5600 // the thread for suspension; the thread will later be identified as Synced in
5601 // SysSweepThreadsForDebug
5602 #else // DISABLE_THREADSUSPEND
5603 // Resume the thread and let it run to a safe point
5604 thread->ResumeThread();
5605 #endif // DISABLE_THREADSUSPEND
5607 LOG((LF_CORDB, LL_INFO1000,
5608 "[0x%x] SUSPEND: gc disabled - will sync.\n",
5609 thread->GetThreadId()));
5611 else if (!thread->m_fPreemptiveGCDisabled)
5613 // Mark threads that are outside the Runtime so that if
5614 // they attempt to re-enter they will trip.
5615 thread->MarkForSuspension(TS_DebugSuspendPending);
5617 #ifdef DISABLE_THREADSUSPEND
5618 // There'a a race above between the moment we first check m_fPreemptiveGCDisabled
5619 // and the moment we enable TrapReturningThreads in MarkForSuspension. To account
5620 // for that we check whether the thread moved into cooperative mode, and if it had
5621 // we mark it as a DebugWillSync thread, that will be handled later in
5622 // SysSweepThreadsForDebug
5623 if (thread->m_fPreemptiveGCDisabled)
5625 // Remember that this thread will be running to a safe point
5626 FastInterlockIncrement(&m_DebugWillSyncCount);
5627 thread->SetThreadState(TS_DebugWillSync);
5629 #else // DISABLE_THREADSUSPEND
5630 if (str == STR_Success) {
5631 thread->ResumeThread();
5633 #endif // DISABLE_THREADSUSPEND
5635 LOG((LF_CORDB, LL_INFO1000,
5636 "[0x%x] SUSPEND: gc enabled.\n", thread->GetThreadId()));
5641 // Return true if all threads are synchronized now, otherwise the
5642 // debugge must wait for the SuspendComplete, called from the last
5646 if (FastInterlockDecrement(&m_DebugWillSyncCount) < 0)
5648 LOG((LF_CORDB, LL_INFO1000,
5649 "SUSPEND: all threads sync before return.\n"));
5657 // This method is called by the debugger helper thread when it times out waiting for a set of threads to
5658 // synchronize. Its used to chase down threads that are not syncronizing quickly. It returns true if all the threads are
5659 // now synchronized. This also means that we own the thread store lock.
5661 // This can be safely called if we're already suspended.
5662 bool Thread::SysSweepThreadsForDebug(bool forceSync)
5666 DISABLED(GC_TRIGGERS); // WaitUntilConcurrentGCComplete toggle GC mode, disabled because called by unmanaged thread
5668 // We assume that only the "real" helper thread ever calls this (not somebody doing helper thread duty).
5669 PRECONDITION(IsDbgHelperSpecialThread());
5670 PRECONDITION(GetThread() == NULL);
5672 // Iff we return true, then we have the TSL (or the aux lock used in workarounds).
5673 POSTCONDITION(RETVAL == !!ThreadStore::HoldingThreadStore());
5677 _ASSERTE(!forceSync); // deprecated parameter
5679 Thread *thread = NULL;
5681 // NOTE::NOTE::NOTE::NOTE::NOTE
5682 // This function has parallel logic in SuspendRuntime. Please make
5683 // sure to make appropriate changes there as well.
5685 // We use ThreadSuspend::SUSPEND_FOR_DEBUGGER_SWEEP here to avoid a deadlock which
5686 // can occur due to the s_hAbortEvt event. This event causes any thread trying
5687 // to take the ThreadStore lock to wait for a GC to complete. If a thread is
5688 // in SuspendEE for a GC and suspends for the debugger, then this thread will
5689 // deadlock if we do not pass in SUSPEND_FOR_DEBUGGER_SWEEP here.
5690 ThreadSuspend::LockThreadStore(ThreadSuspend::SUSPEND_FOR_DEBUGGER_SWEEP);
5692 // From this point until the end of the function, consider all active thread
5693 // suspension to be in progress. This is mainly to give the profiler API a hint
5694 // that trying to suspend a thread (in order to walk its stack) could delay the
5695 // overall EE suspension. So the profiler API would early-abort the stackwalk
5697 ThreadSuspend::SuspendRuntimeInProgressHolder hldSuspendRuntimeInProgress;
5699 // Loop over the threads...
5700 while (((thread = ThreadStore::GetThreadList(thread)) != NULL) && (m_DebugWillSyncCount >= 0))
5702 // Skip threads that we aren't waiting for to sync.
5703 if ((thread->m_State & TS_DebugWillSync) == 0)
5706 #ifdef DISABLE_THREADSUSPEND
5708 // On platforms that do not support safe thread suspension we have
5709 // to rely on the GCPOLL mechanism.
5711 // When we do not suspend the target thread we rely on the GCPOLL
5712 // mechanism enabled by TrapReturningThreads. However when reading
5713 // shared state we need to erect appropriate memory barriers. So
5714 // the interlocked operation below ensures that any future reads on
5715 // this thread will happen after any earlier writes on a different
5717 FastInterlockOr(&thread->m_fPreemptiveGCDisabled, 0);
5718 if (!thread->m_fPreemptiveGCDisabled)
5720 // If the thread toggled to preemptive mode, then it's synced.
5721 goto Label_MarkThreadAsSynced;
5728 #else // DISABLE_THREADSUSPEND
5729 // Suspend the thread
5731 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
5732 DWORD dwSwitchCount = 0;
5736 // We can not allocate memory after we suspend a thread.
5737 // Otherwise, we may deadlock the process when CLR is hosted.
5738 ThreadStore::AllocateOSContext();
5740 SuspendThreadResult str = thread->SuspendThread();
5742 if (str == STR_Failure || str == STR_UnstartedOrDead)
5744 // The thread cannot actually be unstarted - if it was, we would not
5745 // have marked it with TS_DebugWillSync in the first phase.
5746 _ASSERTE(!(thread->m_State & TS_Unstarted));
5748 // If the thread has gone, we can't wait on it.
5749 goto Label_MarkThreadAsSynced;
5751 else if (str == STR_SwitchedOut)
5753 // The thread was switched b/c of fiber-mode stuff.
5754 if (!thread->m_fPreemptiveGCDisabled)
5756 goto Label_MarkThreadAsSynced;
5760 goto RetrySuspension;
5763 else if (str == STR_NoStressLog)
5765 goto RetrySuspension;
5767 else if (!thread->m_fPreemptiveGCDisabled)
5769 // If the thread toggled to preemptive mode, then it's synced.
5771 // We can safely resume the thread here b/c it's in PreemptiveMode and the
5772 // EE will trap anybody trying to re-enter cooperative. So letting it run free
5773 // won't hurt the runtime.
5774 _ASSERTE(str == STR_Success);
5775 thread->ResumeThread();
5777 goto Label_MarkThreadAsSynced;
5779 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
5780 // If the thread is in jitted code, HandledJitCase will try to hijack it; and the hijack
5781 // will toggle the GC.
5784 _ASSERTE(str == STR_Success);
5785 WorkingOnThreadContextHolder workingOnThreadContext(thread);
5786 if (workingOnThreadContext.Acquired() && thread->HandledJITCase())
5788 // Redirect thread so we can capture a good thread context
5789 // (GetThreadContext is not sufficient, due to an OS bug).
5790 // If we don't succeed (should only happen on Win9X, due to
5791 // a different OS bug), we must resume the thread and try
5793 if (!thread->CheckForAndDoRedirectForDbg())
5795 thread->ResumeThread();
5796 __SwitchToThread(0, ++dwSwitchCount);
5797 goto RetrySuspension;
5800 // The hijack will toggle our GC mode, and thus we could wait for the next sweep,
5801 // and the GC-mode check above would catch and sync us. But there's no reason to wait,
5802 // if the thread is hijacked, it's as good as synced, so mark it now.
5803 thread->ResumeThread();
5804 goto Label_MarkThreadAsSynced;
5807 #endif // FEATURE_HIJACK && !PLATFORM_UNIX
5809 // If we didn't take the thread out of the set, then resume it and give it another chance to reach a safe
5811 thread->ResumeThread();
5814 #endif // DISABLE_THREADSUSPEND
5816 // The thread is synced. Remove the sync bits and dec the sync count.
5817 Label_MarkThreadAsSynced:
5818 FastInterlockAnd((ULONG *) &thread->m_State, ~TS_DebugWillSync);
5819 if (FastInterlockDecrement(&m_DebugWillSyncCount) < 0)
5821 // If that was the last thread, then the CLR is synced.
5822 // We return while own the thread store lock. We return true now, which indicates this to the caller.
5827 } // end looping through Thread Store
5829 if (m_DebugWillSyncCount < 0)
5834 // The CLR is not yet synced. We release the threadstore lock and return false.
5835 hldSuspendRuntimeInProgress.Release();
5836 ThreadSuspend::UnlockThreadStore();
5841 void Thread::SysResumeFromDebug(AppDomain *pAppDomain)
5849 Thread *thread = NULL;
5851 if (IsAtProcessExit())
5853 LOG((LF_CORDB, LL_INFO1000,
5854 "RESUME: skipping resume due to process detach.\n"));
5858 LOG((LF_CORDB, LL_INFO1000, "RESUME: starting resume AD:0x%x.\n", pAppDomain));
5861 // Make sure we completed the previous sync
5862 _ASSERTE(m_DebugWillSyncCount == -1);
5864 // Caller is expected to be holding the ThreadStore lock
5865 _ASSERTE(ThreadStore::HoldingThreadStore() || IsAtProcessExit());
5867 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
5869 // Only consider resuming threads if they're in the correct appdomain
5870 if (pAppDomain != NULL && thread->GetDomain() != pAppDomain)
5872 LOG((LF_CORDB, LL_INFO1000, "RESUME: Not resuming thread 0x%x, since it's "
5873 "in appdomain 0x%x.\n", thread, pAppDomain));
5877 // If the user wants to keep the thread suspended, then
5878 // don't release the thread.
5879 if (!(thread->m_StateNC & TSNC_DebuggerUserSuspend))
5881 // If we are still trying to suspend this thread, forget about it.
5882 if (thread->m_State & TS_DebugSuspendPending)
5884 LOG((LF_CORDB, LL_INFO1000,
5885 "[0x%x] RESUME: TS_DebugSuspendPending was set, but will be removed\n",
5886 thread->GetThreadId()));
5889 if (thread->IsSingleStepEnabled())
5891 if (ISREDIRECTEDTHREAD(thread))
5892 thread->ApplySingleStep(GETREDIRECTEDCONTEXT(thread));
5895 // Note: we unmark for suspension _then_ set the suspend event.
5896 thread->ReleaseFromSuspension(TS_DebugSuspendPending);
5902 // Thread will remain suspended due to a request from the debugger.
5904 LOG((LF_CORDB,LL_INFO10000,"Didn't unsuspend thread 0x%x"
5905 "(ID:0x%x)\n", thread, thread->GetThreadId()));
5906 LOG((LF_CORDB,LL_INFO10000,"Suspending:0x%x\n",
5907 thread->m_State & TS_DebugSuspendPending));
5908 _ASSERTE((thread->m_State & TS_DebugWillSync) == 0);
5913 LOG((LF_CORDB, LL_INFO1000, "RESUME: resume complete. Trap count: %d\n", g_TrapReturningThreads.Load()));
5918 * WaitSuspendEventsHelper
5920 * This function is a simple helper function for WaitSuspendEvents. It is needed
5921 * because of the EX_TRY macro. This macro does an alloca(), which allocates space
5922 * off the stack, not free'ing it. Thus, doing a EX_TRY in a loop can easily result
5923 * in a stack overflow error. By factoring out the EX_TRY into a separate function,
5924 * we recover that stack space.
5930 * true if meant to continue, else false.
5933 BOOL Thread::WaitSuspendEventsHelper(void)
5935 STATIC_CONTRACT_NOTHROW;
5936 STATIC_CONTRACT_GC_NOTRIGGER;
5938 DWORD result = WAIT_FAILED;
5942 // CoreCLR does not support user-requested thread suspension
5943 _ASSERTE(!(m_State & TS_UserSuspendPending));
5945 if (m_State & TS_DebugSuspendPending) {
5947 ThreadState oldState = m_State;
5949 while (oldState & TS_DebugSuspendPending) {
5951 ThreadState newState = (ThreadState)(oldState | TS_SyncSuspended);
5952 if (FastInterlockCompareExchange((LONG *)&m_State, newState, oldState) == (LONG)oldState)
5954 result = m_DebugSuspendEvent.Wait(INFINITE,FALSE);
5957 _ASSERTE(!(newState & TS_SyncSuspended) || (newState & TS_UserSuspendPending));
5968 EX_END_CATCH(SwallowAllExceptions)
5970 return result != WAIT_OBJECT_0;
5974 // There's a bit of a workaround here
5975 void Thread::WaitSuspendEvents(BOOL fDoWait)
5977 STATIC_CONTRACT_NOTHROW;
5978 STATIC_CONTRACT_GC_NOTRIGGER;
5980 _ASSERTE(!PreemptiveGCDisabled());
5981 _ASSERTE((m_State & TS_SyncSuspended) == 0);
5983 // Let us do some useful work before suspending ourselves.
5985 // If we're required to perform a wait, do so. Typically, this is
5986 // skipped if this thread is a Debugger Special Thread.
5991 WaitSuspendEventsHelper();
5993 ThreadState oldState = m_State;
5995 // CoreCLR does not support user-requested thread suspension
5996 _ASSERTE(!(oldState & TS_UserSuspendPending));
5999 // If all reasons to suspend are off, we think we can exit
6000 // this loop, but we need to check atomically.
6002 if ((oldState & (TS_UserSuspendPending | TS_DebugSuspendPending)) == 0)
6005 // Construct the destination state we desire - all suspension bits turned off.
6007 ThreadState newState = (ThreadState)(oldState & ~(TS_UserSuspendPending |
6008 TS_DebugSuspendPending |
6011 if (FastInterlockCompareExchange((LONG *)&m_State, newState, oldState) == (LONG)oldState)
6023 #ifdef FEATURE_HIJACK
6024 // Hijacking JITted calls
6025 // ======================
6027 // State of execution when we suspend a thread
6028 struct ExecutionState
6031 BOOL m_IsJIT; // are we executing JITted code?
6032 MethodDesc *m_pFD; // current function/method we're executing
6033 VOID **m_ppvRetAddrPtr; // pointer to return address in frame
6034 DWORD m_RelOffset; // relative offset at which we're currently executing in this fcn
6035 IJitManager *m_pJitManager;
6036 METHODTOKEN m_MethodToken;
6037 BOOL m_IsInterruptible; // is this code interruptible?
6039 ExecutionState() : m_FirstPass(TRUE) {LIMITED_METHOD_CONTRACT; }
6042 // Client is responsible for suspending the thread before calling
6043 void Thread::HijackThread(VOID *pvHijackAddr, ExecutionState *esb)
6051 // Don't hijack if are in the first level of running a filter/finally/catch.
6052 // This is because they share ebp with their containing function further down the
6053 // stack and we will hijack their containing function incorrectly
6054 if (IsInFirstFrameOfHandler(this, esb->m_pJitManager, esb->m_MethodToken, esb->m_RelOffset))
6056 STRESS_LOG3(LF_SYNC, LL_INFO100, "Thread::HijackThread(%p to %p): Early out - IsInFirstFrameOfHandler. State=%x.\n", this, pvHijackAddr, (ThreadState)m_State);
6060 // Don't hijack if a profiler stackwalk is in progress
6061 HijackLockHolder hijackLockHolder(this);
6062 if (!hijackLockHolder.Acquired())
6064 STRESS_LOG3(LF_SYNC, LL_INFO100, "Thread::HijackThread(%p to %p): Early out - !hijackLockHolder.Acquired. State=%x.\n", this, pvHijackAddr, (ThreadState)m_State);
6068 IS_VALID_CODE_PTR((FARPROC) pvHijackAddr);
6070 if (m_State & TS_Hijacked)
6073 // Make sure that the location of the return address is on the stack
6074 _ASSERTE(IsAddressInStack(esb->m_ppvRetAddrPtr));
6076 // Obtain the location of the return address in the currently executing stack frame
6077 m_ppvHJRetAddrPtr = esb->m_ppvRetAddrPtr;
6079 // Remember the place that the return would have gone
6080 m_pvHJRetAddr = *esb->m_ppvRetAddrPtr;
6082 IS_VALID_CODE_PTR((FARPROC) (TADDR)m_pvHJRetAddr);
6083 // TODO [DAVBR]: For the full fix for VsWhidbey 450273, the below
6084 // may be uncommented once isLegalManagedCodeCaller works properly
6085 // with non-return address inputs, and with non-DEBUG builds
6086 //_ASSERTE(isLegalManagedCodeCaller((TADDR)m_pvHJRetAddr));
6087 STRESS_LOG2(LF_SYNC, LL_INFO100, "Hijacking return address 0x%p for thread %p\n", m_pvHJRetAddr, this);
6089 // Remember the method we're executing
6090 m_HijackedFunction = esb->m_pFD;
6092 // Bash the stack to return to one of our stubs
6093 *esb->m_ppvRetAddrPtr = pvHijackAddr;
6094 FastInterlockOr((ULONG *) &m_State, TS_Hijacked);
6097 // If we are unhijacking another thread (not the current thread), then the caller is responsible for
6098 // suspending that thread.
6099 // It's legal to unhijack the current thread without special treatment.
6100 void Thread::UnhijackThread()
6110 if (m_State & TS_Hijacked)
6112 IS_VALID_WRITE_PTR(m_ppvHJRetAddrPtr, sizeof(void*));
6113 IS_VALID_CODE_PTR((FARPROC) m_pvHJRetAddr);
6115 // Can't make the following assertion, because sometimes we unhijack after
6116 // the hijack has tripped (i.e. in the case we actually got some value from
6118 // _ASSERTE(*m_ppvHJRetAddrPtr == OnHijackTripThread);
6120 STRESS_LOG2(LF_SYNC, LL_INFO100, "Unhijacking return address 0x%p for thread %p\n", m_pvHJRetAddr, this);
6121 // restore the return address and clear the flag
6122 *m_ppvHJRetAddrPtr = m_pvHJRetAddr;
6123 FastInterlockAnd((ULONG *) &m_State, ~TS_Hijacked);
6125 // But don't touch m_pvHJRetAddr. We may need that to resume a thread that
6126 // is currently hijacked!
6130 // Get the ExecutionState for the specified *SUSPENDED* thread. Note that this is
6131 // a 'StackWalk' call back (PSTACKWALKFRAMESCALLBACK).
6132 StackWalkAction SWCB_GetExecutionState(CrawlFrame *pCF, VOID *pData)
6140 ExecutionState *pES = (ExecutionState *) pData;
6141 StackWalkAction action = SWA_ABORT;
6143 if (pES->m_FirstPass)
6145 // This will help factor out some repeated code.
6146 bool notJittedCase = false;
6148 // If we're jitted code at the top of the stack, grab everything
6149 if (pCF->IsFrameless() && pCF->IsActiveFunc())
6151 pES->m_IsJIT = TRUE;
6152 pES->m_pFD = pCF->GetFunction();
6153 pES->m_MethodToken = pCF->GetMethodToken();
6154 pES->m_ppvRetAddrPtr = 0;
6155 pES->m_IsInterruptible = pCF->IsGcSafe();
6156 pES->m_RelOffset = pCF->GetRelOffset();
6157 pES->m_pJitManager = pCF->GetJitManager();
6159 STRESS_LOG3(LF_SYNC, LL_INFO1000, "Stopped in Jitted code at pc = %p sp = %p fullyInt=%d\n",
6160 GetControlPC(pCF->GetRegisterSet()), GetRegdisplaySP(pCF->GetRegisterSet()), pES->m_IsInterruptible);
6162 #if defined(FEATURE_CONSERVATIVE_GC) && !defined(USE_GC_INFO_DECODER)
6163 if (g_pConfig->GetGCConservative())
6165 // Conservative GC enabled; behave as if HIJACK_NONINTERRUPTIBLE_THREADS had not been
6168 notJittedCase = true;
6171 #endif // FEATURE_CONSERVATIVE_GC
6173 #ifndef HIJACK_NONINTERRUPTIBLE_THREADS
6174 if (!pES->m_IsInterruptible)
6176 notJittedCase = true;
6178 #else // HIJACK_NONINTERRUPTIBLE_THREADS
6179 // if we're not interruptible right here, we need to determine the
6180 // return address for hijacking.
6181 if (!pES->m_IsInterruptible)
6183 #ifdef WIN64EXCEPTIONS
6184 PREGDISPLAY pRDT = pCF->GetRegisterSet();
6185 _ASSERTE(pRDT != NULL);
6187 // For simplicity, don't hijack in funclets
6188 bool fIsFunclet = pCF->IsFunclet();
6191 notJittedCase = true;
6195 // We already have the caller context available at this point
6196 _ASSERTE(pRDT->IsCallerContextValid);
6197 #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
6199 // Why do we use CallerContextPointers below?
6201 // Assume the following callstack, growing from left->right:
6205 // Assuming A is non-interruptible function and pushes LR on stack,
6206 // when we get the stackwalk callback for A, the CallerContext would
6207 // contain non-volatile register state for B and CallerContextPtrs would
6208 // contain the location where the caller's (B's) non-volatiles where restored
6209 // from. This would be the stack location in A where they were pushed. Thus,
6210 // CallerContextPtrs->Lr would contain the stack location in A where LR (representing an address in B)
6211 // was pushed and thus, contains the return address in B.
6213 // Note that the JIT always pushes LR even for leaf methods to make hijacking
6214 // work for them. See comment in code:Compiler::genPushCalleeSavedRegisters.
6216 if(pRDT->pCallerContextPointers->Lr == &pRDT->pContext->Lr)
6218 // This is the case when we are either:
6220 // 1) In a leaf method that does not push LR on stack, OR
6221 // 2) In the prolog/epilog of a non-leaf method that has not yet pushed LR on stack
6222 // or has LR already popped off.
6224 // The remaining case of non-leaf method is that of IP being in the body of the
6225 // function. In such a case, LR would be have been pushed on the stack and thus,
6226 // we wouldnt be here but in the "else" clause below.
6228 // For (1) we can use CallerContext->ControlPC to be used as the return address
6229 // since we know that leaf frames will return back to their caller.
6230 // For this, we may need JIT support to do so.
6231 notJittedCase = true;
6233 else if (pCF->HasTailCalls())
6235 // Do not hijack functions that have tail calls, since there are two problems:
6236 // 1. When a function that tail calls another one is hijacked, the LR may be
6237 // stored at a different location in the stack frame of the tail call target.
6238 // So just by performing tail call, the hijacked location becomes invalid and
6239 // unhijacking would corrupt stack by writing to that location.
6240 // 2. There is a small window after the caller pops LR from the stack in its
6241 // epilog and before the tail called function pushes LR in its prolog when
6242 // the hijacked return address would not be not on the stack and so we would
6243 // not be able to unhijack.
6244 notJittedCase = true;
6248 // This is the case of IP being inside the method body and LR is
6249 // pushed on the stack. We get it to determine the return address
6250 // in the caller of the current non-interruptible frame.
6251 pES->m_ppvRetAddrPtr = (void **) pRDT->pCallerContextPointers->Lr;
6253 #elif defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
6254 pES->m_ppvRetAddrPtr = (void **) (EECodeManager::GetCallerSp(pRDT) - sizeof(void*));
6255 #else // _TARGET_X86_ || _TARGET_AMD64_
6256 PORTABILITY_ASSERT("Platform NYI");
6257 #endif // _TARGET_???_
6259 #else // WIN64EXCEPTIONS
6260 // peel off the next frame to expose the return address on the stack
6261 pES->m_FirstPass = FALSE;
6262 action = SWA_CONTINUE;
6263 #endif // !WIN64EXCEPTIONS
6265 #endif // HIJACK_NONINTERRUPTIBLE_THREADS
6267 // else we are successfully out of here with SWA_ABORT
6272 STRESS_LOG2(LF_SYNC, LL_INFO1000, "Not in Jitted code at EIP = %p, &EIP = %p\n", GetControlPC(pCF->GetRegisterSet()), pCF->GetRegisterSet()->PCTAddr);
6274 STRESS_LOG1(LF_SYNC, LL_INFO1000, "Not in Jitted code at pc = %p\n", GetControlPC(pCF->GetRegisterSet()));
6276 notJittedCase = true;
6279 // Cases above may have set "notJITtedCase", which we handle as follows:
6282 pES->m_IsJIT = FALSE;
6284 pES->m_pFD = (MethodDesc *)POISONC;
6285 pES->m_ppvRetAddrPtr = (void **)POISONC;
6286 pES->m_IsInterruptible = FALSE;
6292 #if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
6293 // Second pass, looking for the address of the return address so we can
6296 PREGDISPLAY pRDT = pCF->GetRegisterSet();
6300 // pPC points to the return address sitting on the stack, as our
6301 // current EIP for the penultimate stack frame.
6302 pES->m_ppvRetAddrPtr = (void **) pRDT->PCTAddr;
6304 STRESS_LOG2(LF_SYNC, LL_INFO1000, "Partially Int case hijack address = 0x%x val = 0x%x\n", pES->m_ppvRetAddrPtr, *pES->m_ppvRetAddrPtr);
6307 PORTABILITY_ASSERT("Platform NYI");
6314 HijackFrame::HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args)
6315 : m_ReturnAddress((TADDR)returnAddress),
6325 _ASSERTE(m_Thread == GetThread());
6327 m_Next = m_Thread->GetFrame();
6328 m_Thread->SetFrame(this);
6331 void STDCALL OnHijackWorker(HijackArgs * pArgs)
6340 #ifdef HIJACK_NONINTERRUPTIBLE_THREADS
6341 Thread *thread = GetThread();
6343 #ifdef FEATURE_STACK_PROBE
6344 if (GetEEPolicy()->GetActionOnFailure(FAIL_StackOverflow) == eRudeUnloadAppDomain)
6346 // Make sure default domain does not see SO.
6347 // probe for our entry point amount and throw if not enough stack
6348 RetailStackProbe(ADJUST_PROBE(DEFAULT_ENTRY_PROBE_AMOUNT), thread);
6350 #endif // FEATURE_STACK_PROBE
6352 CONTRACT_VIOLATION(SOToleranceViolation);
6354 thread->ResetThreadState(Thread::TS_Hijacked);
6356 // Fix up our caller's stack, so it can resume from the hijack correctly
6357 pArgs->ReturnAddress = (size_t)thread->m_pvHJRetAddr;
6359 // Build a frame so that stack crawling can proceed from here back to where
6360 // we will resume execution.
6361 FrameWithCookie<HijackFrame> frame((void *)pArgs->ReturnAddress, thread, pArgs);
6364 BOOL GCOnTransition = FALSE;
6365 if (g_pConfig->FastGCStressLevel()) {
6366 GCOnTransition = GC_ON_TRANSITIONS(FALSE);
6371 g_SuspendStatistics.cntHijackTrap++;
6372 #endif // TIME_SUSPEND
6377 if (g_pConfig->FastGCStressLevel()) {
6378 GC_ON_TRANSITIONS(GCOnTransition);
6384 PORTABILITY_ASSERT("OnHijackWorker not implemented on this platform.");
6385 #endif // HIJACK_NONINTERRUPTIBLE_THREADS
6388 ReturnKind GetReturnKindFromMethodTable(Thread *pThread, EECodeInfo *codeInfo)
6391 // For simplicity, we don't hijack in funclets, but if you ever change that,
6392 // be sure to choose the OnHijack... callback type to match that of the FUNCLET
6393 // not the main method (it would probably be Scalar).
6396 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
6397 // Mark that we are performing a stackwalker like operation on the current thread.
6398 // This is necessary to allow the signature parsing functions to work without triggering any loads
6399 ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThread);
6401 MethodDesc *methodDesc = codeInfo->GetMethodDesc();
6402 _ASSERTE(methodDesc != nullptr);
6405 MetaSig msig(methodDesc);
6406 if (msig.HasFPReturn())
6408 // Figuring out whether the function returns FP or not is hard to do
6409 // on-the-fly, so we use a different callback helper on x86 where this
6410 // piece of information is needed in order to perform the right save &
6411 // restore of the return value around the call to OnHijackScalarWorker.
6414 #endif // _TARGET_X86_
6416 MethodTable* pMT = NULL;
6417 MetaSig::RETURNTYPE type = methodDesc->ReturnsObject(INDEBUG_COMMA(false) &pMT);
6418 if (type == MetaSig::RETOBJ)
6423 if (type == MetaSig::RETBYREF)
6428 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
6429 // The Multi-reg return case using the classhandle is only implemented for AMD64 SystemV ABI.
6430 // On other platforms, multi-reg return is not supported with GcInfo v1.
6431 // So, the relevant information must be obtained from the GcInfo tables (which requires version2).
6432 if (type == MetaSig::RETVALUETYPE)
6434 EEClass *eeClass = pMT->GetClass();
6435 ReturnKind regKinds[2] = { RT_Unset, RT_Unset };
6437 for (int i = 0; i < 2; i++)
6439 if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerReference)
6441 regKinds[i] = RT_Object;
6443 else if (eeClass->GetEightByteClassification(i) == SystemVClassificationTypeIntegerByRef)
6445 regKinds[i] = RT_ByRef;
6449 regKinds[i] = RT_Scalar;
6452 ReturnKind structReturnKind = GetStructReturnKind(regKinds[0], regKinds[1]);
6453 return structReturnKind;
6455 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
6460 ReturnKind GetReturnKind(Thread *pThread, EECodeInfo *codeInfo)
6462 GCInfoToken gcInfoToken = codeInfo->GetGCInfoToken();
6463 ReturnKind returnKind = codeInfo->GetCodeManager()->GetReturnKind(gcInfoToken);
6465 if (!IsValidReturnKind(returnKind))
6467 returnKind = GetReturnKindFromMethodTable(pThread, codeInfo);
6471 #if !defined(FEATURE_MULTIREG_RETURN) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6472 // For ARM64 struct-return, GetReturnKindFromMethodTable() is not supported
6473 _ASSERTE(returnKind == GetReturnKindFromMethodTable(pThread, codeInfo));
6474 #endif // !FEATURE_MULTIREG_RETURN || FEATURE_UNIX_AMD64_STRUCT_PASSING
6477 _ASSERTE(IsValidReturnKind(returnKind));
6481 VOID * GetHijackAddr(Thread *pThread, EECodeInfo *codeInfo)
6483 ReturnKind returnKind = GetReturnKind(pThread, codeInfo);
6484 pThread->SetHijackReturnKind(returnKind);
6487 if (returnKind == RT_Float)
6489 return reinterpret_cast<VOID *>(OnHijackFPTripThread);
6491 #endif // _TARGET_X86_
6493 return reinterpret_cast<VOID *>(OnHijackTripThread);
6496 #ifndef PLATFORM_UNIX
6498 // Get the ExecutionState for the specified SwitchIn thread. Note that this is
6499 // a 'StackWalk' call back (PSTACKWALKFRAMESCALLBACK).
6500 StackWalkAction SWCB_GetExecutionStateForSwitchIn(CrawlFrame *pCF, VOID *pData)
6508 ExecutionState *pES = (ExecutionState *) pData;
6509 StackWalkAction action = SWA_CONTINUE;
6511 if (pES->m_FirstPass) {
6512 if (pCF->IsFrameless()) {
6514 pES->m_FirstPass = FALSE;
6516 _ASSERTE(!"Platform NYI");
6519 pES->m_IsJIT = TRUE;
6520 pES->m_pFD = pCF->GetFunction();
6521 pES->m_MethodToken = pCF->GetMethodToken();
6522 // We do not care if the code is interruptible
6523 pES->m_IsInterruptible = FALSE;
6524 pES->m_RelOffset = pCF->GetRelOffset();
6525 pES->m_pJitManager = pCF->GetJitManager();
6530 if (pCF->IsFrameless()) {
6531 PREGDISPLAY pRDT = pCF->GetRegisterSet();
6533 // pPC points to the return address sitting on the stack, as our
6534 // current EIP for the penultimate stack frame.
6535 pES->m_ppvRetAddrPtr = (void **) pRDT->PCTAddr;
6540 _ASSERTE(!"Platform NYI");
6547 // The function below, ThreadCaughtInKernelModeExceptionHandling, exists to detect and work around a very subtle
6548 // race that we have when we suspend a thread while that thread is in the kernel handling an exception.
6550 // When a user-mode thread takes an exception, the OS must get involved to handle that exception before user-mode
6551 // exception handling takes place. The exception causes the thread to enter kernel-mode. To handle the exception,
6552 // the kernel does the following: 1) pushes a CONTEXT, then an EXCEPTION_RECORD, and finally an EXCEPTION_POINTERS
6553 // struct onto the thread's user-mode stack. 2) the Esp value in the thread's user-mode context is updated to
6554 // reflect the fact that these structures have just been pushed. 3) some segment registers in the user-mode context
6555 // are modified. 4) the Eip value in the user-mode context is changed to point to the user-mode exception dispatch
6556 // routine. 5) the kernel resumes user-mode execution with the altered context.
6558 // Note that during this entire process: 1) the thread can be suspeded by another user-mode thread, and 2)
6559 // Get/SetThreadContext all operate on the user-mode context.
6561 // There are two important races to consider here: a race with attempting to hijack the thread in HandledJITCase,
6562 // and a race attempting to trace the thread's stack in HandledJITCase.
6565 // Race #1: failure to hijack a thread in HandledJITCase.
6567 // In HandledJITCase, if we see that a thread's Eip is in managed code at an interruptable point, we will attempt
6568 // to move the thread to a hijack in order to stop it's execution for a variety of reasons (GC, debugger, user-mode
6569 // supension, etc.) We do this by suspending the thread, inspecting Eip, changing Eip to the address of the hijack
6570 // routine, and resuming the thread.
6572 // The problem here is that in step #4 above, the kernel is going to change Eip in the thread's context to point to
6573 // the user-mode exception dispatch routine. If we suspend a thread when it has taken an exception in managed code,
6574 // we may see Eip pointing to managed code and attempt to hijack the thread. When we resume the thread, step #4
6575 // will eventually execute and the thread will go to the user-mode exception dispatch routine instead of to our
6578 // We tollerate this by recgonizing that this has happened when we arrive in our exception handler
6579 // (COMPlusFrameHandler), and we fix up the IP in the context passed to the handler.
6582 // Race #2: inability to trace a managed call stack
6584 // If we suspend a thread after step #2 above, but before step #4, then we will see an Eip pointing to managed
6585 // code, but an Esp that points to the newly pushed exception structures. If we are in a managed function that does
6586 // not have an Ebp frame, the return address will be relative to Esp and we will not be able to resolve the return
6587 // address properly. Since we will attempt to place a return address hijack (as part of our heroic efforts to trap
6588 // the thread quickly), we may end up writing over random memory with our hijack. This is obviously extremely
6589 // bad. Realistically, any attempt to trace a thread's stack in this case is suspect, even if the mangaed function
6592 // The solution is to attempt to detect this race and abandon the hijack attempt. We have developed the following
6593 // heuristic to detect this case. Basically, we look to see if Esp points to an EXCEPTION_POINTERS structure, and
6594 // that this structure points to valid EXCEPTION_RECORD and CONTEXT structures. They must be ordered on the stack,
6595 // and the faulting address in the EXCEPTION_RECORD should be the thread's current Eip, and the Eip in the CONTEXT
6596 // should be the thread's current Eip.
6598 // This is the heuristic codified. Given Eip and Esp from the thread's current context:
6600 // 1. if Eip points to a managed function, and...
6601 // 2. the pointer at Esp is equal to Esp + sizeof(EXCEPTION_POINTERS), and...
6602 // 3. the faulting address in the EXCEPTION_RECORD at that location is equal to the current Eip, and...
6603 // 4. the NumberParameters field in the EXCEPTION_RECORD is valid (between 0 and EXCEPTION_MAXIMUM_PARAMETERS), and...
6604 // 5. the pointer at Esp + 4 is equal to Esp + sizeof(EXCEPTION_POINTERS) + the dynamic size of the EXCEPTION_RECORD, and...
6605 // 6. the Eip value of the CONTEXT at that location is equal to the current Eip, then we have recgonized the race.
6607 // The validation of Eip in both places, combined with ensuring that the pointer values are on the thread's stack
6608 // make this a safe heuristic to evaluate. Even if one could end up in a function with the stack looking exactly
6609 // like this, and even if we are trying to suspend such a thread and we catch it at the Eip that matches the values
6610 // at the proper places on the stack, then the worst that will happen is we won't attempt to hijack the thread at
6611 // that point. We'll resume it and try again later. There will be at least one other instruction in the function
6612 // that is not at the Eip value on the stack, and we'll be able to trace the thread's stack from that instruction
6613 // and place the return address hijack.
6615 // As races go, race #1 above is very, very easy to hit. We hit it in the wild before we shipped V1, and a simple
6616 // test program with one thread constantly AV'ing and another thread attempting to suspend the first thread every
6617 // half second hit's the race almost instantly.
6619 // Race #2 is extremely rare in comparison. The same program properly instrumented only hits the race about 5 times
6620 // every 2000 attempts or so. We did not hit this even in very stressful exception tests and
6621 // it's never been seen in the wild.
6623 // Note: a new feature has been added in recent OS's that allows us to detect both of these races with a simple
6624 // call to GetThreadContext. This feature exists on all Win64 platforms, so this change is only for 32-bit
6625 // platforms. We've asked for this fix to be applied to future 32-bit OS's, so we can remove this on those
6626 // platforms when that happens. Furthermore, once we stop supporting the older 32-bit OS versions that don't have
6627 // the new feature, we can remove these alltogether.
6629 // WARNING: Interrupts (int 3) immediately increment the IP whereas traps (AVs) do not.
6630 // So this heuristic only works for trap, but not for interrupts. As a result, the race
6631 // is still a problem for interrupts. This means that the race can cause a process crash
6632 // if the managed debugger puts an "int 3" in order to do a stepping operation,
6633 // and GC or a sampling profiler tries to suspend the thread. This can be handled
6634 // by modifying the code below to additionally check if the instruction just before
6635 // the IP is an "int 3".
6641 #define WORKAROUND_RACES_WITH_KERNEL_MODE_EXCEPTION_HANDLING
6642 #endif // !FEATURE_PAL
6644 #ifdef WORKAROUND_RACES_WITH_KERNEL_MODE_EXCEPTION_HANDLING
6645 BOOL ThreadCaughtInKernelModeExceptionHandling(Thread *pThread, CONTEXT *ctx)
6652 PRECONDITION(pThread != NULL);
6653 PRECONDITION(ctx != NULL);
6657 // Validate that Esp plus all of our maximum structure sizes is on the thread's stack. We use the cached bounds
6658 // on the Thread object. If we're that close to the top of the thread's stack, then we can't possibly have hit
6659 // the race. If we pass this test, we can assume all memory accesses below are legal, since they're all on the
6661 if ((ctx->Esp + sizeof(EXCEPTION_POINTERS) + sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)) >=
6662 (UINT_PTR)pThread->GetCachedStackBase())
6667 // The calculations below assume that a DWORD is the same size as a pointer. Since this is only needed on
6668 // 32-bit platforms, this should be fine.
6669 _ASSERTE(sizeof(DWORD) == sizeof(void*));
6671 // There are cases where the ESP is just decremented but the page is not touched, thus the page is not commited or
6672 // still has page guard bit set. We can't hit the race in such case so we just leave. Besides, we can't access the
6673 // memory with page guard flag or not committed.
6674 MEMORY_BASIC_INFORMATION mbi;
6676 // This code can run below YieldTask, which means that it must not call back into the host.
6677 // The reason is that YieldTask is invoked by the host, and the host needs not be reentrant.
6678 if (VirtualQuery((LPCVOID)(UINT_PTR)ctx->Esp, &mbi, sizeof(mbi)) == sizeof(mbi))
6680 if (!(mbi.State & MEM_COMMIT) || (mbi.Protect & PAGE_GUARD))
6684 STRESS_LOG0 (LF_SYNC, ERROR, "VirtualQuery failed!");
6685 #define VirtualQuery(lpAddress, lpBuffer, dwLength) Dont_Use_VirtualQuery(lpAddress, lpBuffer, dwLength)
6687 // The first two values on the stack should be a pointer to the EXCEPTION_RECORD and a pointer to the CONTEXT.
6688 UINT_PTR Esp = (UINT_PTR)ctx->Esp;
6689 UINT_PTR ER = *((UINT_PTR*)Esp);
6690 UINT_PTR CTX = *((UINT_PTR*)(Esp + sizeof(EXCEPTION_RECORD*)));
6692 // The EXCEPTION_RECORD should be at Esp + sizeof(EXCEPTION_POINTERS)... if it's not, then we haven't hit the race.
6693 if (ER != (Esp + sizeof(EXCEPTION_POINTERS)))
6698 // Assume we have an EXCEPTION_RECORD at Esp + sizeof(EXCEPTION_POINTERS) and look at values within that.
6699 EXCEPTION_RECORD *pER = (EXCEPTION_RECORD*)ER;
6701 // Make sure the faulting address in the EXCEPTION_RECORD matches the thread's current Eip.
6702 if ((UINT_PTR)pER->ExceptionAddress != ctx->Eip)
6707 // Validate the number of exception parameters.
6708 if ((pER->NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS))
6713 // We have a plausable number of exception parameters, so compute the exact size of this exception
6714 // record. Remember, an EXCEPTION_RECORD has a variable sized array of optional information at the end called
6715 // the ExceptionInformation. It's an array of pointers up to EXCEPTION_MAXIMUM_PARAMETERS in length.
6716 DWORD exceptionRecordSize = sizeof(EXCEPTION_RECORD) -
6717 ((EXCEPTION_MAXIMUM_PARAMETERS - pER->NumberParameters) * sizeof(pER->ExceptionInformation[0]));
6719 // On Vista WOW on X64, the OS pushes the maximum number of parameters onto the stack.
6720 DWORD exceptionRecordMaxSize = sizeof(EXCEPTION_RECORD);
6722 // The CONTEXT pointer should be pointing right after the EXCEPTION_RECORD.
6723 if ((CTX != (ER + exceptionRecordSize)) &&
6724 (CTX != (ER + exceptionRecordMaxSize)))
6729 // Assume we have a CONTEXT at Esp + 8 + exceptionRecordSize and look at values within that.
6730 CONTEXT *pCTX = (CONTEXT*)CTX;
6732 // Make sure the Eip in the CONTEXT on the stack matches the current Eip value.
6733 if (pCTX->Eip != ctx->Eip)
6738 // If all the tests above fail, then it means that we've hit race #2 described in the text before this function.
6739 STRESS_LOG3(LF_SYNC, LL_INFO100,
6740 "ThreadCaughtInKernelModeExceptionHandling returning TRUE. Eip=%p, Esp=%p, ExceptionCode=%p\n",
6741 ctx->Eip, ctx->Esp, pER->ExceptionCode);
6745 #endif //WORKAROUND_RACES_WITH_KERNEL_MODE_EXCEPTION_HANDLING
6746 #endif //_TARGET_X86_
6748 //---------------------------------------------------------------------------------------
6750 // Helper used by HandledJITCase and others (like the profiling API) who need an
6751 // absolutely reliable register context.
6754 // * dwOptions - [in] Combination of flags from enum
6755 // GetSafelyRedirectableThreadContextOptions to customize the checks performed by
6757 // * pCtx - [out] This Thread's current context. Callers may rely on this only if nonzero
6759 // * pRD - [out] Matching REGDISPLAY filled from the pCtx found by this function.
6760 // Callers may rely on this only if nonzero is returned
6763 // Nonzero iff all requested checks have succeeded, which would imply that it is
6764 // a reliable time to use this Thread's context.
6766 BOOL Thread::GetSafelyRedirectableThreadContext(DWORD dwOptions, CONTEXT * pCtx, REGDISPLAY * pRD)
6774 _ASSERTE(pCtx != NULL);
6775 _ASSERTE(pRD != NULL);
6777 // We are never in interruptible code if there if a filter context put in place by the debugger.
6778 if (GetFilterContext() != NULL)
6781 #ifdef DEBUGGING_SUPPORTED
6782 if ((dwOptions & kCheckDebuggerBreakpoints) != 0)
6784 // If we are running under the control of a managed debugger that may have placed breakpoints in the code stream,
6785 // then there is a special case that we need to check. See the comments in debugger.cpp for more information.
6786 if (CORDebuggerAttached() && (g_pDebugInterface->IsThreadContextInvalid(this)))
6789 #endif // DEBUGGING_SUPPORTED
6791 // Make sure we specify CONTEXT_EXCEPTION_REQUEST to detect "trap frame reporting".
6792 _ASSERTE(GetFilterContext() == NULL);
6794 ZeroMemory(pCtx, sizeof(*pCtx));
6795 pCtx->ContextFlags = CONTEXT_FULL | CONTEXT_EXCEPTION_REQUEST;
6796 if (!EEGetThreadContext(this, pCtx))
6802 // workaround around WOW64 problems. Only do this workaround if a) this is x86, and b) the OS does not support trap frame reporting,
6803 // If the OS *does* support trap frame reporting, then the call to IsContextSafeToRedirect below will return FALSE if we run
6807 if (!(pCtx->ContextFlags & CONTEXT_EXCEPTION_REPORTING) &&
6808 ((dwOptions & kPerfomLastRedirectIPCheck) != 0))
6810 // This code fixes a race between GetThreadContext and NtContinue. If we redirect managed code
6811 // at the same place twice in a row, we run the risk of reading a bogus CONTEXT when we redirect
6812 // the second time. This leads to access violations on x86 machines. To fix the problem, we
6813 // never redirect at the same instruction pointer that we redirected at on the previous GC.
6814 if (GetIP(pCtx) == m_LastRedirectIP)
6816 // We need to test for an infinite loop in assembly, as this will break the heuristic we
6818 const BYTE short_jmp = 0xeb; // Machine code for a short jump.
6819 const BYTE self = 0xfe; // -2. Short jumps are calculated as [ip]+2+[second_byte].
6821 // If we find that we are in an infinite loop, we'll set the last redirected IP to 0 so that we will
6822 // redirect the next time we attempt it. Delaying one interation allows us to narrow the window of
6823 // the race we are working around in this corner case.
6824 BYTE *ip = (BYTE *)m_LastRedirectIP;
6825 if (ip[0] == short_jmp && ip[1] == self)
6826 m_LastRedirectIP = 0;
6828 // We set a hard limit of 5 times we will spin on this to avoid any tricky race which we have not
6831 if (m_SpinCount >= 5)
6832 m_LastRedirectIP = 0;
6834 STRESS_LOG0(LF_GC, LL_INFO10000, "GetSafelyRedirectableThreadContext() - Cannot redirect at the same IP as the last redirection.\n");
6840 if (!IsContextSafeToRedirect(pCtx))
6842 STRESS_LOG0(LF_GC, LL_INFO10000, "GetSafelyRedirectableThreadContext() - trap frame reporting an invalid CONTEXT\n");
6846 ZeroMemory(pRD, sizeof(*pRD));
6847 if (!InitRegDisplay(pRD, pCtx, true))
6853 // Called while the thread is suspended. If we aren't in JITted code, this isn't
6854 // a JITCase and we return FALSE. If it is a JIT case and we are in interruptible
6855 // code, then we are handled. Our caller has found a good spot and can keep us
6856 // suspended. If we aren't in interruptible code, then we aren't handled. So we
6857 // pick a spot to hijack the return address and our caller will wait to get us
6859 BOOL Thread::HandledJITCase(BOOL ForTaskSwitchIn)
6869 StackWalkAction action;
6873 if (!GetSafelyRedirectableThreadContext(
6874 kPerfomLastRedirectIPCheck | kCheckDebuggerBreakpoints,
6878 STRESS_LOG0(LF_GC, LL_INFO10000, "HandledJITCase() - GetSafelyRedirectableThreadContext() returned FALSE\n");
6882 PCODE ip = GetIP(&ctx);
6883 if (!ExecutionManager::IsManagedCode(ip))
6888 #ifdef WORKAROUND_RACES_WITH_KERNEL_MODE_EXCEPTION_HANDLING
6889 if (ThreadCaughtInKernelModeExceptionHandling(this, &ctx))
6893 #endif //WORKAROUND_RACES_WITH_KERNEL_MODE_EXCEPTION_HANDLING
6896 // We know IP is in managed code, mark current thread as safe for calls into host
6897 Thread * pCurThread = GetThread();
6898 if (pCurThread != NULL)
6900 pCurThread->dbg_m_cSuspendedThreadsWithoutOSLock ++;
6901 _ASSERTE(pCurThread->dbg_m_cSuspendedThreadsWithoutOSLock <= pCurThread->dbg_m_cSuspendedThreads);
6905 // Walk one or two frames of the stack...
6906 if (ForTaskSwitchIn) {
6907 action = StackWalkFramesEx(&rd,SWCB_GetExecutionStateForSwitchIn, &esb, QUICKUNWIND | DISABLE_MISSING_FRAME_DETECTION | THREAD_IS_SUSPENDED | ALLOW_ASYNC_STACK_WALK, NULL);
6911 DWORD startCrawl = g_SuspendStatistics.GetTime();
6913 action = StackWalkFramesEx(&rd,SWCB_GetExecutionState, &esb,
6914 QUICKUNWIND | DISABLE_MISSING_FRAME_DETECTION |
6915 THREAD_IS_SUSPENDED | ALLOW_ASYNC_STACK_WALK, NULL);
6918 g_SuspendStatistics.crawl.Accumulate(
6919 SuspendStatistics::GetElapsed(startCrawl,
6920 g_SuspendStatistics.GetTime()));
6922 g_SuspendStatistics.cntHijackCrawl++;
6927 // action should either be SWA_ABORT, in which case we properly walked
6928 // the stack frame and found out whether this is a JIT case, or
6929 // SWA_FAILED, in which case the walk couldn't even be started because
6930 // there are no stack frames, which also isn't a JIT case.
6932 if (action == SWA_ABORT && esb.m_IsJIT)
6934 // If we are interruptible and we are in cooperative mode, our caller can
6935 // just leave us suspended.
6936 if (esb.m_IsInterruptible && m_fPreemptiveGCDisabled)
6938 _ASSERTE(!ThreadStore::HoldingThreadStore(this));
6942 if (esb.m_ppvRetAddrPtr)
6944 // we need to hijack the return address. Base this on whether or not
6945 // the method returns an object reference, so we know whether to protect
6947 EECodeInfo codeInfo(ip);
6948 VOID *pvHijackAddr = GetHijackAddr(this, &codeInfo);
6950 #ifdef FEATURE_ENABLE_GCPOLL
6951 // On platforms that support both hijacking and GC polling
6952 // decide whether to hijack based on a configuration value.
6953 // COMPlus_GCPollType = 1 is the setting that enables hijacking
6954 // in GCPOLL enabled builds.
6955 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
6956 if (EEConfig::GCPOLL_TYPE_HIJACK == pollType || EEConfig::GCPOLL_TYPE_DEFAULT == pollType)
6957 #endif // FEATURE_ENABLE_GCPOLL
6959 HijackThread(pvHijackAddr, &esb);
6963 // else it's not even a JIT case
6966 // Restore back the number of threads without OS lock
6967 if (pCurThread != NULL)
6969 pCurThread->dbg_m_cSuspendedThreadsWithoutOSLock--;
6973 STRESS_LOG1(LF_SYNC, LL_INFO10000, " HandledJitCase returning %d\n", ret);
6977 #endif // !PLATFORM_UNIX
6979 #endif // FEATURE_HIJACK
6981 // Some simple helpers to keep track of the threads we are waiting for
6982 void Thread::MarkForSuspension(ULONG bit)
6990 // CoreCLR does not support user-requested thread suspension
6991 _ASSERTE(bit == TS_DebugSuspendPending ||
6992 bit == (TS_DebugSuspendPending | TS_DebugWillSync));
6994 _ASSERTE(IsAtProcessExit() || ThreadStore::HoldingThreadStore());
6996 _ASSERTE((m_State & bit) == 0);
6998 FastInterlockOr((ULONG *) &m_State, bit);
6999 ThreadStore::TrapReturningThreads(TRUE);
7002 void Thread::UnmarkForSuspension(ULONG mask)
7010 // CoreCLR does not support user-requested thread suspension
7011 _ASSERTE(mask == ~TS_DebugSuspendPending);
7013 _ASSERTE(IsAtProcessExit() || ThreadStore::HoldingThreadStore());
7015 _ASSERTE((m_State & ~mask) != 0);
7017 // we decrement the global first to be able to satisfy the assert from DbgFindThread
7018 ThreadStore::TrapReturningThreads(FALSE);
7019 FastInterlockAnd((ULONG *) &m_State, mask);
7022 //----------------------------------------------------------------------------
7024 void ThreadSuspend::RestartEE(BOOL bFinishedGC, BOOL SuspendSucceded)
7027 g_SuspendStatistics.StartRestart();
7028 #endif //TIME_SUSPEND
7030 FireEtwGCRestartEEBegin_V1(GetClrInstanceId());
7033 // SyncClean holds a list of things to be cleaned up when it's possible.
7034 // SyncClean uses the GC mode to synchronize access to this list. Threads must be
7035 // in COOP mode to add things to the list, and the list can only be cleaned up
7036 // while no threads are adding things.
7037 // Since we know that no threads are in COOP mode at this point (because the EE is
7038 // suspended), we clean up the list here.
7040 SyncClean::CleanUp();
7042 #ifdef PROFILING_SUPPORTED
7043 // If a profiler is keeping track suspend events, notify it. This notification
7044 // must happen before we set TrapReturning threads to FALSE because as soon as
7045 // we remove the return trap threads can start "running" managed code again as
7046 // they return from unmanaged. (Whidbey Bug #7505)
7047 // Also must notify before setting GcInProgress = FALSE.
7049 // It's very odd that we do this here, in ThreadSuspend::RestartEE, while the
7050 // corresponding call to RuntimeSuspendStarted is done at a lower architectural layer,
7051 // in ThreadSuspend::SuspendRuntime.
7053 BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
7054 g_profControlBlock.pProfInterface->RuntimeResumeStarted();
7057 #endif // PROFILING_SUPPORTED
7060 // Unhijack all threads, and reset their "suspend pending" flags. Why isn't this in
7061 // Thread::ResumeRuntime?
7063 Thread *thread = NULL;
7064 while ((thread = ThreadStore::GetThreadList(thread)) != NULL)
7066 thread->PrepareForEERestart(SuspendSucceded);
7070 // Revert to being a normal thread
7072 ClrFlsClearThreadType (ThreadType_DynamicSuspendEE);
7073 GCHeapUtilities::GetGCHeap()->SetGCInProgress(false);
7076 // Allow threads to enter COOP mode (though we still need to wake the ones
7077 // that we hijacked).
7079 // Note: this is the last barrier that keeps managed threads
7080 // from entering cooperative mode. If the sequence changes,
7081 // you may have to change routine GCHeapUtilities::SafeToRestartManagedThreads
7084 ThreadStore::TrapReturningThreads(FALSE);
7085 g_pSuspensionThread = 0;
7088 // Any threads that are waiting in WaitUntilGCComplete will continue now.
7090 GCHeapUtilities::GetGCHeap()->SetWaitForGCEvent();
7091 _ASSERTE(IsGCSpecialThread() || ThreadStore::HoldingThreadStore());
7093 ResumeRuntime(bFinishedGC, SuspendSucceded);
7095 FireEtwGCRestartEEEnd_V1(GetClrInstanceId());
7098 g_SuspendStatistics.EndRestart();
7099 #endif //TIME_SUSPEND
7102 // The contract between GC and the EE, for starting and finishing a GC is as follows:
7109 // ... perform the GC ...
7114 // calls UnlockThreadStore
7116 // Note that this is intentionally *not* symmetrical. The EE will assert that the
7117 // GC does most of this stuff in the correct sequence.
7120 // This is the only way to call ThreadSuspend::SuspendRuntime, and that method is
7121 // so tightly coupled to this one, with intermingled responsibilities, that we don't
7122 // understand why we have a separation at all. At some point we should refactor all of
7123 // the suspension code into a separate abstraction, which we would like to call the
7124 // "managed execution lock." The current "layering" of this stuff has it mixed
7125 // randomly into the Thread and GC code, and split into almost completely arbitrary
7128 void ThreadSuspend::SuspendEE(SUSPEND_REASON reason)
7131 g_SuspendStatistics.StartSuspend();
7132 #endif //TIME_SUSPEND
7134 BOOL gcOnTransitions;
7136 ETW::GCLog::ETW_GC_INFO Info;
7137 Info.SuspendEE.Reason = reason;
7138 Info.SuspendEE.GcCount = (((reason == SUSPEND_FOR_GC) || (reason == SUSPEND_FOR_GC_PREP)) ?
7139 (ULONG)GCHeapUtilities::GetGCHeap()->GetGcCount() : (ULONG)-1);
7141 FireEtwGCSuspendEEBegin_V1(Info.SuspendEE.Reason, Info.SuspendEE.GcCount, GetClrInstanceId());
7143 LOG((LF_SYNC, INFO3, "Suspending the runtime for reason %d\n", reason));
7145 gcOnTransitions = GC_ON_TRANSITIONS(FALSE); // dont do GC for GCStress 3
7147 Thread* pCurThread = GetThread();
7149 DWORD dwSwitchCount = 0;
7151 // Note: we need to make sure to re-set m_pThreadAttemptingSuspendForGC when we retry
7152 // due to the debugger case below!
7156 // Set variable to indicate that this thread is preforming a true GC
7157 // This gives this thread priority over other threads that are trying to acquire the ThreadStore Lock
7158 // for other reasons.
7160 if (reason == ThreadSuspend::SUSPEND_FOR_GC || reason == ThreadSuspend::SUSPEND_FOR_GC_PREP)
7162 m_pThreadAttemptingSuspendForGC = pCurThread;
7165 // also unblock any thread waiting around for this thread to suspend. This prevents us from completely
7166 // starving other suspension clients, such as the debugger, which we otherwise would do because of
7167 // the priority we just established.
7169 g_pGCSuspendEvent->Set();
7173 DWORD startAcquire = g_SuspendStatistics.GetTime();
7177 // Acquire the TSL. We will hold this until the we restart the EE.
7179 ThreadSuspend::LockThreadStore(reason);
7182 g_SuspendStatistics.acquireTSL.Accumulate(SuspendStatistics::GetElapsed(startAcquire,
7183 g_SuspendStatistics.GetTime()));
7187 // If we've blocked other threads that are waiting for the ThreadStore lock, unblock them now
7188 // (since we already got it). This allows them to get the TSL after we release it.
7190 if ( s_hAbortEvtCache != NULL &&
7191 (reason == ThreadSuspend::SUSPEND_FOR_GC || reason == ThreadSuspend::SUSPEND_FOR_GC_PREP))
7193 LOG((LF_SYNC, INFO3, "GC thread is backing out the suspend abort event.\n"));
7196 LOG((LF_SYNC, INFO3, "GC thread is signalling the suspend abort event.\n"));
7197 s_hAbortEvtCache->Set();
7201 // Also null-out m_pThreadAttemptingSuspendForGC since it should only matter if s_hAbortEvt is
7204 if (reason == ThreadSuspend::SUSPEND_FOR_GC || reason == ThreadSuspend::SUSPEND_FOR_GC_PREP)
7206 m_pThreadAttemptingSuspendForGC = NULL;
7211 // Now we're going to acquire an exclusive lock on managed code execution (including
7212 // "maunally managed" code in GCX_COOP regions).
7214 // First, we reset the event that we're about to tell other threads to wait for.
7216 GCHeapUtilities::GetGCHeap()->ResetWaitForGCEvent();
7219 // Remember that we're the one doing the GC. Actually, maybe we're not doing a GC -
7220 // what this really indicates is that we are trying to acquire the "managed execution lock."
7223 g_pSuspensionThread = pCurThread;
7226 // Tell all threads, globally, to wait for WaitForGCEvent.
7228 ThreadStore::TrapReturningThreads(TRUE);
7231 // Remember why we're doing this.
7233 m_suspendReason = reason;
7236 // There's a GC in progress. (again, not necessarily - we suspend the EE for other reasons.
7237 // I wonder how much confusion this has caused....)
7238 // It seems like much of the above is redundant. We should investigate reducing the number
7239 // of mechanisms we use to indicate that a suspension is in progress.
7241 GCHeapUtilities::GetGCHeap()->SetGCInProgress(true);
7244 // Gratuitous memory barrier. (may be needed - but I'm not sure why.)
7248 ClrFlsSetThreadType (ThreadType_DynamicSuspendEE);
7253 _ASSERTE(ThreadStore::HoldingThreadStore() || g_fProcessDetach);
7256 // Now that we've instructed all threads to please stop,
7257 // go interrupt the ones that are running managed code and force them to stop.
7258 // This does not return successfully until all threads have acknowledged that they
7259 // will not run managed code.
7261 hr = SuspendRuntime(reason);
7262 ASSERT( hr == S_OK || hr == ERROR_TIMEOUT);
7265 if (hr == ERROR_TIMEOUT)
7266 g_SuspendStatistics.cntCollideRetry++;
7270 if (hr == ERROR_TIMEOUT)
7271 STRESS_LOG0(LF_SYNC, LL_INFO1000, "SysSuspension colission");
7273 // If the debugging services are attached, then its possible
7274 // that there is a thread which appears to be stopped at a gc
7275 // safe point, but which really is not. If that is the case,
7276 // back off and try again.
7278 // If this is not the GC thread and another thread has triggered
7279 // a GC, then we may have bailed out of SuspendRuntime, so we
7280 // must resume all of the threads and tell the GC that we are
7281 // at a safepoint - since this is the exact same behaviour
7282 // that the debugger needs, just use it's code.
7283 if ((hr == ERROR_TIMEOUT)
7284 || Thread::ThreadsAtUnsafePlaces()
7285 #ifdef DEBUGGING_SUPPORTED // seriously? When would we want to disable debugging support? :)
7286 || (CORDebuggerAttached() &&
7287 g_pDebugInterface->ThreadsAtUnsafePlaces())
7288 #endif // DEBUGGING_SUPPORTED
7291 // In this case, the debugger has stopped at least one
7292 // thread at an unsafe place. The debugger will usually
7293 // have already requested that we stop. If not, it will
7294 // usually either do so shortly, or resume the thread that is
7295 // at the unsafe place. Either way, we have to wait for the
7296 // debugger to decide what it wants to do.
7298 // In some rare cases, the end-user debugger may have frozen
7299 // a thread at a gc-unsafe place, and so we'll loop forever
7300 // here and never resolve the deadlock. Unfortunately we can't
7301 // easily abort a GC
7302 // and so for now we just wait for the debugger to timeout and
7303 // hopefully thaw that thread. Maybe instead we should try to
7304 // detect this situation sooner (when thread abort is possible)
7305 // and notify the debugger with NotifyOfCrossThreadDependency, giving
7306 // it the chance to thaw other threads or abort us before getting
7307 // wedged in the GC.
7309 // Note: we've still got the ThreadStore lock held.
7311 // <REVISIT>The below manipulation of two static variables (s_hAbortEvtCache and s_hAbortEvt)
7312 // is protected by the ThreadStore lock, which we are still holding. But we access these
7313 // in ThreadSuspend::LockThreadStore, prior to obtaining the lock. </REVISIT>
7315 LOG((LF_GCROOTS | LF_GC | LF_CORDB,
7317 "***** Giving up on current GC suspension due "
7318 "to debugger or timeout *****\n"));
7320 if (s_hAbortEvtCache == NULL)
7322 LOG((LF_SYNC, INFO3, "Creating suspend abort event.\n"));
7324 CLREvent * pEvent = NULL;
7328 pEvent = new CLREvent();
7329 pEvent->CreateManualEvent(FALSE);
7330 s_hAbortEvtCache = pEvent;
7334 // Bummer... couldn't init the abort event. Its a shame, but not fatal. We'll simply not use it
7335 // on this iteration and try again next time.
7337 _ASSERTE(!pEvent->IsValid());
7338 pEvent->CloseEvent();
7342 EX_END_CATCH(SwallowAllExceptions)
7345 if (s_hAbortEvtCache != NULL)
7347 LOG((LF_SYNC, INFO3, "Using suspend abort event.\n"));
7348 s_hAbortEvt = s_hAbortEvtCache;
7349 s_hAbortEvt->Reset();
7352 // Mark that we're done with the gc, so that the debugger can proceed.
7353 RestartEE(FALSE, FALSE);
7355 LOG((LF_GCROOTS | LF_GC | LF_CORDB,
7356 LL_INFO10, "The EE is free now...\n"));
7358 // If someone's trying to suspent *this* thread, this is a good opportunity.
7359 // <REVIST>This call to CatchAtSafePoint is redundant - PulseGCMode already checks this.</REVISIT>
7360 if (pCurThread && pCurThread->CatchAtSafePoint())
7362 // <REVISIT> This assert is fired on BGC thread 'cause we
7363 // got timeout.</REVISIT>
7364 //_ASSERTE((pCurThread->PreemptiveGCDisabled()) || IsGCSpecialThread());
7365 pCurThread->PulseGCMode(); // Go suspend myself.
7369 // otherwise, just yield so the debugger can finish what it's doing.
7370 __SwitchToThread (0, ++dwSwitchCount);
7373 goto retry_for_debugger;
7376 GC_ON_TRANSITIONS(gcOnTransitions);
7378 FireEtwGCSuspendEEEnd_V1(GetClrInstanceId());
7381 g_SuspendStatistics.EndSuspend(reason == SUSPEND_FOR_GC || reason == SUSPEND_FOR_GC_PREP);
7382 #endif //TIME_SUSPEND
7385 #if defined(FEATURE_HIJACK) && defined(PLATFORM_UNIX)
7387 // This function is called by PAL to check if the specified instruction pointer
7388 // is in a function where we can safely inject activation.
7389 BOOL CheckActivationSafePoint(SIZE_T ip, BOOL checkingCurrentThread)
7391 Thread *pThread = GetThread();
7392 // It is safe to call the ExecutionManager::IsManagedCode only if we are making the check for
7393 // a thread different from the current one or if the current thread is in the cooperative mode.
7394 // Otherwise ExecutionManager::IsManagedCode could deadlock if the activation happened when the
7395 // thread was holding the ExecutionManager's writer lock.
7396 // When the thread is in preemptive mode, we know for sure that it is not executing managed code.
7397 BOOL checkForManagedCode = !checkingCurrentThread || (pThread != NULL && pThread->PreemptiveGCDisabled());
7398 return checkForManagedCode && ExecutionManager::IsManagedCode(ip);
7401 // This function is called when a GC is pending. It tries to ensure that the current
7402 // thread is taken to a GC-safe place as quickly as possible. It does this by doing
7403 // one of the following:
7405 // - If the thread is in native code or preemptive GC is not disabled, there's
7406 // nothing to do, so we return.
7408 // - If the thread is in interruptible managed code, we will push a frame that
7409 // has information about the context that was interrupted and then switch to
7410 // preemptive GC mode so that the pending GC can proceed, and then switch back.
7412 // - If the thread is in uninterruptible managed code, we will patch the return
7413 // address to take the thread to the appropriate stub (based on the return
7414 // type of the method) which will then handle preparing the thread for GC.
7416 void HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
7418 Thread *pThread = GetThread();
7420 if (pThread->PreemptiveGCDisabled() != TRUE)
7423 #ifdef FEATURE_PERFTRACING
7424 // Mark that the thread is currently in managed code.
7425 pThread->SaveGCModeOnSuspension();
7426 #endif // FEATURE_PERFTRACING
7428 PCODE ip = GetIP(interruptedContext);
7430 // This function can only be called when the interrupted thread is in
7431 // an activation safe point.
7432 _ASSERTE(CheckActivationSafePoint(ip, /* checkingCurrentThread */ TRUE));
7434 Thread::WorkingOnThreadContextHolder workingOnThreadContext(pThread);
7435 if (!workingOnThreadContext.Acquired())
7438 EECodeInfo codeInfo(ip);
7439 if (!codeInfo.IsValid())
7442 DWORD addrOffset = codeInfo.GetRelOffset();
7444 ICodeManager *pEECM = codeInfo.GetCodeManager();
7445 _ASSERTE(pEECM != NULL);
7447 bool isAtSafePoint = pEECM->IsGcSafe(&codeInfo, addrOffset);
7450 // If the thread is at a GC safe point, push a RedirectedThreadFrame with
7451 // the interrupted context and pulse the GC mode so that GC can proceed.
7452 FrameWithCookie<RedirectedThreadFrame> frame(interruptedContext);
7453 pThread->SetSavedRedirectContext(NULL);
7455 frame.Push(pThread);
7457 pThread->PulseGCMode();
7463 // The thread is in non-interruptible code.
7464 ExecutionState executionState;
7465 StackWalkAction action;
7466 REGDISPLAY regDisplay;
7467 pThread->InitRegDisplay(®Display, interruptedContext, true /* validContext */);
7471 if (IsIPInEpilog(interruptedContext, &codeInfo, &unused))
7474 // Use StackWalkFramesEx to find the location of the return address. This will locate the
7475 // return address by checking relative to the caller frame's SP, which is preferable to
7476 // checking next to the current RBP because we may have interrupted the function prior to
7477 // the point where RBP is updated.
7478 action = pThread->StackWalkFramesEx(
7480 SWCB_GetExecutionState,
7482 QUICKUNWIND | DISABLE_MISSING_FRAME_DETECTION | ALLOW_ASYNC_STACK_WALK);
7484 if (action != SWA_ABORT || !executionState.m_IsJIT)
7487 if (executionState.m_ppvRetAddrPtr == NULL)
7491 // Calling this turns off the GC_TRIGGERS/THROWS/INJECT_FAULT contract in LoadTypeHandle.
7492 // We should not trigger any loads for unresolved types.
7493 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
7495 // Mark that we are performing a stackwalker like operation on the current thread.
7496 // This is necessary to allow the signature parsing functions to work without triggering any loads.
7497 ClrFlsValueSwitch threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThread);
7499 // Hijack the return address to point to the appropriate routine based on the method's return type.
7500 void *pvHijackAddr = GetHijackAddr(pThread, &codeInfo);
7501 pThread->HijackThread(pvHijackAddr, &executionState);
7505 bool Thread::InjectGcSuspension()
7507 static ConfigDWORD injectionEnabled;
7508 if (injectionEnabled.val(CLRConfig::INTERNAL_ThreadSuspendInjection) == 0)
7511 Volatile<HANDLE> hThread;
7512 hThread = GetThreadHandle();
7513 if (hThread != INVALID_HANDLE_VALUE && hThread != SWITCHOUT_HANDLE_VALUE)
7515 ::PAL_InjectActivation(hThread);
7522 #endif // FEATURE_HIJACK && PLATFORM_UNIX
7524 // Initialize thread suspension support
7525 void ThreadSuspend::Initialize()
7527 #if defined(FEATURE_HIJACK) && defined(PLATFORM_UNIX)
7528 ::PAL_SetActivationFunction(HandleGCSuspensionForInterruptedThread, CheckActivationSafePoint);
7533 BOOL Debug_IsLockedViaThreadSuspension()
7535 LIMITED_METHOD_CONTRACT;
7536 return GCHeapUtilities::IsGCInProgress() &&
7537 (dbgOnly_IsSpecialEEThread() ||
7538 IsGCSpecialThread() ||
7539 GetThread() == ThreadSuspend::GetSuspensionThread());
7543 #if defined(TIME_SUSPEND) || defined(GC_STATS)
7545 DWORD StatisticsBase::secondsToDisplay = 0;
7547 DWORD StatisticsBase::GetTime()
7549 LIMITED_METHOD_CONTRACT;
7550 LARGE_INTEGER large;
7554 if (QueryPerformanceFrequency(&large) && (large.QuadPart != 0))
7555 divisor = (DWORD)(large.QuadPart / (1000 * 1000)); // microseconds
7560 if (QueryPerformanceCounter(&large))
7561 return (DWORD) (large.QuadPart / divisor);
7566 DWORD StatisticsBase::GetElapsed(DWORD start, DWORD stop)
7568 LIMITED_METHOD_CONTRACT;
7570 return stop - start;
7572 INT64 bigStop = stop;
7573 bigStop += 0x100000000ULL;
7576 // The assert below was seen firing in stress, so comment it out for now
7577 //_ASSERTE(((INT64)(DWORD)bigStop) == bigStop);
7579 if (((INT64)(DWORD)bigStop) == bigStop)
7580 return (DWORD) bigStop;
7585 void StatisticsBase::RollOverIfNeeded()
7587 LIMITED_METHOD_CONTRACT;
7589 // Our counters are 32 bits and can count to 4 GB in microseconds or 4K in seconds.
7590 // Reset when we get close to overflowing
7591 const DWORD RolloverInterval = 3900;
7593 // every so often, print a summary of our statistics
7594 DWORD ticksNow = GetTickCount();
7596 if (secondsToDisplay == 0)
7598 secondsToDisplay = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StatsUpdatePeriod);
7599 if (secondsToDisplay == 0)
7600 secondsToDisplay = 1;
7601 else if (secondsToDisplay > RolloverInterval)
7602 secondsToDisplay = RolloverInterval;
7605 if (ticksNow - startTick > secondsToDisplay * 1000)
7609 startTick = GetTickCount();
7611 // Our counters are 32 bits and can count to 4 GB in microseconds or 4K in seconds.
7612 // Reset when we get close to overflowing
7613 if (++cntDisplay >= (int)(RolloverInterval / secondsToDisplay))
7618 #endif // defined(TIME_SUSPEND) || defined(GC_STATS)
7623 // There is a current and a prior copy of the statistics. This allows us to display deltas per reporting
7624 // interval, as well as running totals. The 'min' and 'max' values require special treatment. They are
7625 // Reset (zeroed) in the current statistics when we begin a new interval and they are updated via a
7626 // comparison with the global min/max.
7627 SuspendStatistics g_SuspendStatistics;
7628 SuspendStatistics g_LastSuspendStatistics;
7630 WCHAR* SuspendStatistics::logFileName = NULL;
7632 // Called whenever our timers start to overflow
7633 void SuspendStatistics::Initialize()
7635 LIMITED_METHOD_CONTRACT;
7636 // for efficiency sake we're taking a dependency on the layout of a C++ object
7637 // with a vtable. protect against violations of our premise:
7638 static_assert(offsetof(SuspendStatistics, cntDisplay) == sizeof(void*),
7639 "The first field of SuspendStatistics follows the pointer sized vtable");
7641 int podOffs = offsetof(SuspendStatistics, cntDisplay); // offset of the first POD field
7642 memset((BYTE*)(&g_SuspendStatistics)+podOffs, 0, sizeof(g_SuspendStatistics)-podOffs);
7643 memset((BYTE*)(&g_LastSuspendStatistics)+podOffs, 0, sizeof(g_LastSuspendStatistics)-podOffs);
7647 void SuspendStatistics::StartSuspend()
7649 LIMITED_METHOD_CONTRACT;
7650 startSuspend = GetTime();
7653 // Bottom of SuspendEE
7654 void SuspendStatistics::EndSuspend(BOOL bForGC)
7656 LIMITED_METHOD_CONTRACT;
7657 DWORD time = GetElapsed(startSuspend, GetTime());
7659 suspend.Accumulate(time);
7661 // details on suspends...
7664 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
7668 cntNonGCSuspendsInBGC++;
7672 // Time spent in the current suspend (for pro-active debugging)
7673 DWORD SuspendStatistics::CurrentSuspend()
7675 LIMITED_METHOD_CONTRACT;
7676 return GetElapsed(startSuspend, GetTime());
7680 void SuspendStatistics::StartRestart()
7682 LIMITED_METHOD_CONTRACT;
7683 startRestart = GetTime();
7686 // Bottom of RestartEE
7687 void SuspendStatistics::EndRestart()
7689 LIMITED_METHOD_CONTRACT;
7690 DWORD timeNow = GetTime();
7692 restart.Accumulate(GetElapsed(startRestart, timeNow));
7695 paused.Accumulate(SuspendStatistics::GetElapsed(startSuspend, timeNow));
7700 // Time spent in the current restart
7701 DWORD SuspendStatistics::CurrentRestart()
7703 LIMITED_METHOD_CONTRACT;
7704 return GetElapsed(startRestart, GetTime());
7707 void SuspendStatistics::DisplayAndUpdate()
7709 LIMITED_METHOD_CONTRACT;
7711 // TODO: this fires at times...
7712 // _ASSERTE(cntSuspends == cntRestarts);
7714 if (logFileName == NULL)
7716 logFileName = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_SuspendTimeLog);
7721 if (logFileName != NULL && (logFile = _wfopen((LPCWSTR)logFileName, W("a"))) != NULL)
7723 if (cntDisplay == 0)
7724 fprintf(logFile, "\nSUSP **** Initialize *****\n\n");
7726 fprintf(logFile, "SUSP **** Summary ***** %d\n", cntDisplay);
7728 paused.DisplayAndUpdate (logFile, "Paused ", &g_LastSuspendStatistics.paused, cntSuspends, g_LastSuspendStatistics.cntSuspends);
7729 suspend.DisplayAndUpdate (logFile, "Suspend", &g_LastSuspendStatistics.suspend, cntSuspends, g_LastSuspendStatistics.cntSuspends);
7730 restart.DisplayAndUpdate (logFile, "Restart", &g_LastSuspendStatistics.restart, cntRestarts, g_LastSuspendStatistics.cntSuspends);
7731 acquireTSL.DisplayAndUpdate(logFile, "LockTSL", &g_LastSuspendStatistics.acquireTSL, cntSuspends, g_LastSuspendStatistics.cntSuspends);
7732 releaseTSL.DisplayAndUpdate(logFile, "Unlock ", &g_LastSuspendStatistics.releaseTSL, cntSuspends, g_LastSuspendStatistics.cntSuspends);
7733 osSuspend.DisplayAndUpdate (logFile, "OS Susp", &g_LastSuspendStatistics.osSuspend, cntOSSuspendResume, g_LastSuspendStatistics.cntOSSuspendResume);
7734 crawl.DisplayAndUpdate (logFile, "Crawl", &g_LastSuspendStatistics.crawl, cntHijackCrawl, g_LastSuspendStatistics.cntHijackCrawl);
7735 wait.DisplayAndUpdate (logFile, "Wait", &g_LastSuspendStatistics.wait, cntWaits, g_LastSuspendStatistics.cntWaits);
7737 fprintf(logFile, "OS Suspend Failures %d (%d), Wait Timeouts %d (%d), Hijack traps %d (%d)\n",
7738 cntFailedSuspends - g_LastSuspendStatistics.cntFailedSuspends, cntFailedSuspends,
7739 cntWaitTimeouts - g_LastSuspendStatistics.cntWaitTimeouts, cntWaitTimeouts,
7740 cntHijackTrap - g_LastSuspendStatistics.cntHijackTrap, cntHijackTrap);
7742 fprintf(logFile, "Redirected EIP Failures %d (%d), Collided GC/Debugger/ADUnload %d (%d)\n",
7743 cntFailedRedirections - g_LastSuspendStatistics.cntFailedRedirections, cntFailedRedirections,
7744 cntCollideRetry - g_LastSuspendStatistics.cntCollideRetry, cntCollideRetry);
7746 fprintf(logFile, "Suspend: All %d (%d). NonGC: %d (%d). InBGC: %d (%d). NonGCInBGC: %d (%d)\n\n",
7747 cntSuspends - g_LastSuspendStatistics.cntSuspends, cntSuspends,
7748 cntNonGCSuspends - g_LastSuspendStatistics.cntNonGCSuspends, cntNonGCSuspends,
7749 cntSuspendsInBGC - g_LastSuspendStatistics.cntSuspendsInBGC, cntSuspendsInBGC,
7750 cntNonGCSuspendsInBGC - g_LastSuspendStatistics.cntNonGCSuspendsInBGC, cntNonGCSuspendsInBGC);
7752 // close the log file...
7756 memcpy(&g_LastSuspendStatistics, this, sizeof(g_LastSuspendStatistics));
7768 #endif // TIME_SUSPEND
7770 #if defined(TIME_SUSPEND) || defined(GC_STATS)
7772 const char* const str_timeUnit[] = { "usec", "msec", "sec" };
7773 const int timeUnitFactor[] = { 1, 1000, 1000000 };
7775 void MinMaxTot::DisplayAndUpdate(FILE* logFile, __in_z const char *pName, MinMaxTot *pLastOne, int fullCount, int priorCount, timeUnit unit /* = usec */)
7777 LIMITED_METHOD_CONTRACT;
7779 int tuf = timeUnitFactor[unit];
7780 int delta = fullCount - priorCount;
7782 fprintf(logFile, "%s %u (%u) times for %u (%u) %s. Min %u (%u), Max %u (%u), Avg %u (%u)\n",
7785 (totVal - pLastOne->totVal) / tuf, totVal / tuf,
7786 str_timeUnit[(int)unit],
7787 minVal / tuf, pLastOne->minVal / tuf,
7788 maxVal / tuf, pLastOne->maxVal / tuf,
7789 (delta == 0 ? 0 : (totVal - pLastOne->totVal) / delta) / tuf,
7790 (fullCount == 0 ? 0 : totVal / fullCount) / tuf);
7792 if (minVal > pLastOne->minVal && pLastOne->minVal != 0)
7793 minVal = pLastOne->minVal;
7795 if (maxVal < pLastOne->maxVal)
7796 maxVal = pLastOne->maxVal;
7799 #endif // defined(TIME_SUSPEND) || defined(GC_STATS)