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.
6 /*============================================================
8 ** Header: COMSynchronizable.cpp
10 ** Purpose: Native methods on System.SynchronizableObject
11 ** and its subclasses.
14 ===========================================================*/
24 #include "comsynchronizable.h"
25 #include "dbginterface.h"
26 #include "comdelegate.h"
27 #ifdef FEATURE_REMOTING
31 #ifdef FEATURE_REMOTING
32 #include "appdomainhelper.h"
33 #include "objectclone.h"
35 #include "callhelpers.h"
37 #include "appdomain.hpp"
38 #include "appdomain.inl"
39 #ifdef FEATURE_REMOTING
40 #include "crossdomaincalls.h"
45 // To include definition of CAPTURE_BUCKETS_AT_TRANSITION
48 // The two threads need to communicate some information. Any object references must
52 OBJECTHANDLE m_Threadable;
53 OBJECTHANDLE m_ThreadStartArg;
56 SharedState(OBJECTREF threadable, OBJECTREF threadStartArg, Thread *internal)
61 THROWS; // From CreateHandle()
65 AppDomainFromIDHolder ad(internal->GetKickOffDomainId(), TRUE);
67 COMPlusThrow(kAppDomainUnloadedException);
69 m_Threadable = ad->CreateHandle(threadable);
70 m_ThreadStartArg = ad->CreateHandle(threadStartArg);
72 m_Internal = internal;
85 // It's important to have no GC rendez-vous point between the checking and the clean-up below.
86 // The three handles below could be in an appdomain which is just starting to be unloaded, or an appdomain
87 // which has been unloaded already. Thus, we need to check whether the appdomain is still valid before
88 // we do the clean-up. Since we suspend all runtime threads when we try to do the unload, there will be no
89 // race condition between the checking and the clean-up as long as this thread cannot be suspended in between.
90 AppDomainFromIDHolder ad(m_Internal->GetKickOffDomainId(), TRUE);
93 DestroyHandle(m_Threadable);
94 DestroyHandle(m_ThreadStartArg);
100 // For the following helpers, we make no attempt to synchronize. The app developer
101 // is responsible for managing his own race conditions.
103 // Note: if the internal Thread is NULL, this implies that the exposed object has
104 // finalized and then been resurrected.
105 static inline BOOL ThreadNotStarted(Thread *t)
108 return (t && t->IsUnstarted() && !t->HasValidThreadHandle());
111 static inline BOOL ThreadIsRunning(Thread *t)
114 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
116 (t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 &&
117 (CLRTaskHosted()? t->GetHostTask()!=NULL:t->HasValidThreadHandle()));
118 #else // !FEATURE_INCLUDE_ALL_INTERFACES
120 (t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 &&
121 (t->HasValidThreadHandle()));
122 #endif // FEATURE_INCLUDE_ALL_INTERFACES
125 static inline BOOL ThreadIsDead(Thread *t)
128 return (t == 0 || t->IsDead());
132 // Map our exposed notion of thread priorities into the enumeration that NT uses.
133 static INT32 MapToNTPriority(INT32 ours)
143 INT32 NTPriority = 0;
147 case ThreadNative::PRIORITY_LOWEST:
148 NTPriority = THREAD_PRIORITY_LOWEST;
151 case ThreadNative::PRIORITY_BELOW_NORMAL:
152 NTPriority = THREAD_PRIORITY_BELOW_NORMAL;
155 case ThreadNative::PRIORITY_NORMAL:
156 NTPriority = THREAD_PRIORITY_NORMAL;
159 case ThreadNative::PRIORITY_ABOVE_NORMAL:
160 NTPriority = THREAD_PRIORITY_ABOVE_NORMAL;
163 case ThreadNative::PRIORITY_HIGHEST:
164 NTPriority = THREAD_PRIORITY_HIGHEST;
168 COMPlusThrow(kArgumentOutOfRangeException, W("Argument_InvalidFlag"));
174 // Map to our exposed notion of thread priorities from the enumeration that NT uses.
175 INT32 MapFromNTPriority(INT32 NTPriority)
177 LIMITED_METHOD_CONTRACT;
181 if (NTPriority <= THREAD_PRIORITY_LOWEST)
183 // managed code does not support IDLE. Map it to PRIORITY_LOWEST.
184 ours = ThreadNative::PRIORITY_LOWEST;
186 else if (NTPriority >= THREAD_PRIORITY_HIGHEST)
188 ours = ThreadNative::PRIORITY_HIGHEST;
190 else if (NTPriority == THREAD_PRIORITY_BELOW_NORMAL)
192 ours = ThreadNative::PRIORITY_BELOW_NORMAL;
194 else if (NTPriority == THREAD_PRIORITY_NORMAL)
196 ours = ThreadNative::PRIORITY_NORMAL;
198 else if (NTPriority == THREAD_PRIORITY_ABOVE_NORMAL)
200 ours = ThreadNative::PRIORITY_ABOVE_NORMAL;
204 _ASSERTE (!"not supported priority");
205 ours = ThreadNative::PRIORITY_NORMAL;
211 void ThreadNative::KickOffThread_Worker(LPVOID ptr)
222 KickOffThread_Args *args = (KickOffThread_Args *) ptr;
223 _ASSERTE(ObjectFromHandle(args->share->m_Threadable) != NULL);
226 // we are saving the delagate and result primarily for debugging
229 OBJECTREF orThreadStartArg;
230 OBJECTREF orDelegate;
234 ZeroMemory(&gc, sizeof(gc));
237 pThread = GetThread();
240 BEGIN_SO_INTOLERANT_CODE(pThread);
242 gc.orDelegate = ObjectFromHandle(args->share->m_Threadable);
243 gc.orThreadStartArg = ObjectFromHandle(args->share->m_ThreadStartArg);
245 // We cannot call the Delegate Invoke method directly from ECall. The
246 // stub has not been created for non multicast delegates. Instead, we
247 // will invoke the Method on the OR stored in the delegate directly.
248 // If there are changes to the signature of the ThreadStart delegate
249 // this code will need to change. I've noted this in the Thread start
255 MethodDesc *pMeth = ((DelegateEEClass*)( gc.orDelegate->GetMethodTable()->GetClass() ))->m_pInvokeMethod;
257 MethodDescCallSite invokeMethod(pMeth, &gc.orDelegate);
259 if (MscorlibBinder::IsClass(gc.orDelegate->GetMethodTable(), CLASS__PARAMETERIZEDTHREADSTART))
261 //Parameterized ThreadStart
264 arg[0] = ObjToArgSlot(gc.orDelegate);
265 arg[1]=ObjToArgSlot(gc.orThreadStartArg);
266 invokeMethod.Call(arg);
273 arg[0] = ObjToArgSlot(gc.orDelegate);
274 invokeMethod.Call(arg);
276 STRESS_LOG2(LF_SYNC, LL_INFO10, "Managed thread exiting normally for delegate %p Type %pT\n", OBJECTREFToObject(gc.orDelegate), (size_t) gc.orDelegate->GetMethodTable());
278 END_SO_INTOLERANT_CODE;
282 // Helper to avoid two EX_TRY/EX_CATCH blocks in one function
283 static void PulseAllHelper(Thread* pThread)
295 // GetExposedObject() will either throw, or we have a valid object. Note
296 // that we re-acquire it each time, since it may move during calls.
297 pThread->GetExposedObject()->EnterObjMonitor();
298 pThread->GetExposedObject()->PulseAll();
299 pThread->GetExposedObject()->LeaveObjMonitor();
303 // just keep going...
305 EX_END_CATCH(SwallowAllExceptions)
308 // When an exposed thread is started by Win32, this is where it starts.
309 ULONG __stdcall ThreadNative::KickOffThread(void* pass)
322 // Before we do anything else, get Setup so that we have a real thread.
324 // Our thread isn't setup yet, so we can't use the standard probe
325 BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return E_FAIL);
327 KickOffThread_Args args;
328 // don't have a separate var becuase this can be updated in the worker
329 args.share = (SharedState *) pass;
330 args.pThread = args.share->m_Internal;
332 Thread* pThread = args.pThread;
334 _ASSERTE(pThread != NULL);
341 CExecutionEngine::CheckThreadState(0);
345 // OOM might be thrown from CheckThreadState, so it's important
346 // that we don't rethrow it; if we do then the process will die
347 // because there are no installed handlers at this point, so
348 // swallow the exception. this will set the thread's state to
349 // FailStarted which will result in a ThreadStartException being
350 // thrown from the thread that attempted to start this one.
351 if (!GET_EXCEPTION()->IsTransient() && !SwallowUnhandledExceptions())
354 EX_END_CATCH(SwallowAllExceptions);
355 if (CExecutionEngine::CheckThreadStateNoCreate(0) == NULL)
358 pThread->SetThreadState(Thread::TS_FailStarted);
359 pThread->DetachThread(FALSE);
360 // !!! Do not touch any field of Thread object. The Thread object is subject to delete
361 // !!! after DetachThread call.
368 ok = pThread->HasStarted();
373 // Do not swallow the unhandled exception here
376 // Fire ETW event to correlate with the thread that created current thread
377 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadRunning))
378 FireEtwThreadRunning(pThread, GetClrInstanceId());
380 // We have a sticky problem here.
382 // Under some circumstances, the context of 'this' doesn't match the context
383 // of the thread. Today this can only happen if the thread is marked for an
384 // STA. If so, the delegate that is stored in the object may not be directly
385 // suitable for invocation. Instead, we need to call through a proxy so that
386 // the correct context transitions occur.
388 // All the changes occur inside HasStarted(), which will switch this thread
389 // over to a brand new STA as necessary. We have to notice this happening, so
390 // we can adjust the delegate we are going to invoke on.
392 _ASSERTE(GetThread() == pThread); // Now that it's started
393 ManagedThreadBase::KickOff(pThread->GetKickOffDomainId(), KickOffThread_Worker, &args);
395 // If TS_FailStarted is set then the args are deleted in ThreadNative::StartInner
396 if ((args.share) && !pThread->HasThreadState(Thread::TS_FailStarted))
401 PulseAllHelper(pThread);
403 GCX_PREEMP_NO_DTOR();
405 pThread->ClearThreadCPUGroupAffinity();
407 DestroyThread(pThread);
410 END_SO_INTOLERANT_CODE;
416 FCIMPL2(void, ThreadNative::Start, ThreadBaseObject* pThisUNSAFE, StackCrawlMark* pStackMark)
420 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
422 StartInner(pThisUNSAFE, pStackMark);
424 HELPER_METHOD_FRAME_END_POLL();
428 // Start up a thread, which by now should be in the ThreadStore's Unstarted list.
429 void ThreadNative::StartInner(ThreadBaseObject* pThisUNSAFE, StackCrawlMark* pStackMark)
444 gc.pThis = (THREADBASEREF) pThisUNSAFE;
448 if (gc.pThis == NULL)
449 COMPlusThrow(kNullReferenceException, W("NullReference_This"));
451 Thread *pNewThread = gc.pThis->GetInternal();
452 if (pNewThread == NULL)
453 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
455 _ASSERTE(GetThread() != NULL); // Current thread wandered in!
457 gc.pThis->EnterObjMonitor();
461 // Is the thread already started? You can't restart a thread.
462 if (!ThreadNotStarted(pNewThread))
464 COMPlusThrow(kThreadStateException, IDS_EE_THREADSTART_STATE);
467 OBJECTREF threadable = gc.pThis->GetDelegate();
468 OBJECTREF threadStartArg = gc.pThis->GetThreadStartArg();
469 gc.pThis->SetDelegate(NULL);
470 gc.pThis->SetThreadStartArg(NULL);
472 // This can never happen, because we construct it with a valid one and then
473 // we never let you change it (because SetStart is private).
474 _ASSERTE(threadable != NULL);
476 // Allocate this away from our stack, so we can unwind without affecting
477 // KickOffThread. It is inside a GCFrame, so we can enable GC now.
478 NewHolder<SharedState> share(new SharedState(threadable, threadStartArg, pNewThread));
480 pNewThread->IncExternalCount();
482 // Fire an ETW event to mark the current thread as the launcher of the new thread
483 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadCreating))
484 FireEtwThreadCreating(pNewThread, GetClrInstanceId());
486 // As soon as we create the new thread, it is eligible for suspension, etc.
487 // So it gets transitioned to cooperative mode before this call returns to
488 // us. It is our duty to start it running immediately, so that GC isn't blocked.
490 BOOL success = pNewThread->CreateNewThread(
491 pNewThread->RequestedThreadStackSize() /* 0 stackSize override*/,
492 KickOffThread, share);
496 pNewThread->DecExternalCount(FALSE);
500 // After we have established the thread handle, we can check m_Priority.
501 // This ordering is required to eliminate the race condition on setting the
502 // priority of a thread just as it starts up.
503 pNewThread->SetThreadPriority(MapToNTPriority(gc.pThis->m_Priority));
504 pNewThread->ChooseThreadCPUGroupAffinity();
506 FastInterlockOr((ULONG *) &pNewThread->m_State, Thread::TS_LegalToJoin);
509 ret = pNewThread->StartThread();
511 // When running under a user mode native debugger there is a race
512 // between the moment we've created the thread (in CreateNewThread) and
513 // the moment we resume it (in StartThread); the debugger may receive
514 // the "ct" (create thread) notification, and it will attempt to
515 // suspend/resume all threads in the process. Now imagine the debugger
516 // resumes this thread first, and only later does it try to resume the
517 // newly created thread. In these conditions our call to ResumeThread
518 // may come before the debugger's call to ResumeThread actually causing
520 // We cannot use IsDebuggerPresent() in the condition below because the
521 // debugger may have been detached between the time it got the notification
522 // and the moment we execute the test below.
523 _ASSERTE(ret == 1 || ret == 2);
528 // Synchronize with HasStarted.
529 YIELD_WHILE (!pNewThread->HasThreadState(Thread::TS_FailStarted) &&
530 pNewThread->HasThreadState(Thread::TS_Unstarted));
533 if (!pNewThread->HasThreadState(Thread::TS_FailStarted))
535 share.SuppressRelease(); // we have handed off ownership of the shared struct
540 PulseAllHelper(pNewThread);
541 pNewThread->HandleThreadStartupFailure();
546 gc.pThis->LeaveObjMonitor();
549 EX_END_CATCH_UNREACHABLE;
551 gc.pThis->LeaveObjMonitor();
556 FCIMPL1(void, ThreadNative::Abort, ThreadBaseObject* pThis)
561 FCThrowVoid(kNullReferenceException);
563 THREADBASEREF thisRef(pThis);
564 // We need to keep the managed Thread object alive so that we can call UserAbort on
565 // unmanaged thread object.
566 HELPER_METHOD_FRAME_BEGIN_1(thisRef);
568 Thread *thread = thisRef->GetInternal();
570 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
572 DWORD testAbort = g_pConfig->GetHostTestThreadAbort();
573 if (testAbort != 0) {
574 thread->UserAbort(Thread::TAR_Thread, testAbort == 1 ? EEPolicy::TA_Safe : EEPolicy::TA_Rude, INFINITE, Thread::UAC_Normal);
578 thread->UserAbort(Thread::TAR_Thread, EEPolicy::TA_V1Compatible, INFINITE, Thread::UAC_Normal);
580 if (thread->CatchAtSafePoint())
582 HELPER_METHOD_FRAME_END_POLL();
586 FCIMPL1(void, ThreadNative::ResetAbort, ThreadBaseObject* pThis)
591 VALIDATEOBJECT(pThis);
593 Thread *thread = pThis->GetInternal();
594 // We do not allow user to reset rude thread abort in MustRun code.
595 if (thread && thread->IsRudeAbort())
600 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
603 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
604 thread->UserResetAbort(Thread::TAR_Thread);
605 thread->ClearAborted();
606 HELPER_METHOD_FRAME_END_POLL();
611 // Note that you can manipulate the priority of a thread that hasn't started yet,
612 // or one that is running. But you get an exception if you manipulate the priority
613 // of a thread that has died.
614 FCIMPL1(INT32, ThreadNative::GetPriority, ThreadBaseObject* pThisUNSAFE)
618 if (pThisUNSAFE==NULL)
619 FCThrowRes(kNullReferenceException, W("NullReference_This"));
621 // validate the handle
622 if (ThreadIsDead(pThisUNSAFE->GetInternal()))
623 FCThrowEx(kThreadStateException, IDS_EE_THREAD_DEAD_PRIORITY, NULL, NULL, NULL);
625 return pThisUNSAFE->m_Priority;
629 FCIMPL2(void, ThreadNative::SetPriority, ThreadBaseObject* pThisUNSAFE, INT32 iPriority)
636 THREADBASEREF pThis = (THREADBASEREF) pThisUNSAFE;
637 HELPER_METHOD_FRAME_BEGIN_1(pThis);
641 COMPlusThrow(kNullReferenceException, W("NullReference_This"));
644 // translate the priority (validating as well)
645 priority = MapToNTPriority(iPriority); // can throw; needs a frame
647 // validate the thread
648 thread = pThis->GetInternal();
650 if (ThreadIsDead(thread))
652 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_DEAD_PRIORITY, NULL, NULL, NULL);
655 INT32 oldPriority = pThis->m_Priority;
657 // Eliminate the race condition by establishing m_Priority before we check for if
658 // the thread is running. See ThreadNative::Start() for the other half.
659 pThis->m_Priority = iPriority;
661 if (!thread->SetThreadPriority(priority))
663 pThis->m_Priority = oldPriority;
664 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_PRIORITY_FAIL, NULL, NULL, NULL);
667 HELPER_METHOD_FRAME_END();
671 // This service can be called on unstarted and dead threads. For unstarted ones, the
672 // next wait will be interrupted. For dead ones, this service quietly does nothing.
673 FCIMPL1(void, ThreadNative::Interrupt, ThreadBaseObject* pThisUNSAFE)
677 if (pThisUNSAFE==NULL)
678 FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
680 Thread *thread = pThisUNSAFE->GetInternal();
683 FCThrowExVoid(kThreadStateException, IDS_EE_THREAD_CANNOT_GET, NULL, NULL, NULL);
685 HELPER_METHOD_FRAME_BEGIN_0();
687 thread->UserInterrupt(Thread::TI_Interrupt);
689 HELPER_METHOD_FRAME_END();
693 FCIMPL1(FC_BOOL_RET, ThreadNative::IsAlive, ThreadBaseObject* pThisUNSAFE)
697 if (pThisUNSAFE==NULL)
698 FCThrowRes(kNullReferenceException, W("NullReference_This"));
700 THREADBASEREF thisRef(pThisUNSAFE);
703 // Keep managed Thread object alive, since the native object's
704 // lifetime is tied to the managed object's finalizer. And with
705 // resurrection, it may be possible to get a dangling pointer here -
706 // consider both protecting thisRef and setting the managed object's
707 // Thread* to NULL in the GC's ScanForFinalization method.
708 HELPER_METHOD_FRAME_BEGIN_RET_1(thisRef);
710 Thread *thread = thisRef->GetInternal();
713 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
715 ret = ThreadIsRunning(thread);
717 HELPER_METHOD_POLL();
718 HELPER_METHOD_FRAME_END();
724 FCIMPL2(FC_BOOL_RET, ThreadNative::Join, ThreadBaseObject* pThisUNSAFE, INT32 Timeout)
729 THREADBASEREF pThis = (THREADBASEREF) pThisUNSAFE;
731 HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
734 COMPlusThrow(kNullReferenceException, W("NullReference_This"));
736 // validate the timeout
737 if ((Timeout < 0) && (Timeout != INFINITE_TIMEOUT))
738 COMPlusThrowArgumentOutOfRange(W("millisecondsTimeout"), W("ArgumentOutOfRange_NeedNonNegOrNegative1"));
740 retVal = DoJoin(pThis, Timeout);
742 HELPER_METHOD_FRAME_END();
744 FC_RETURN_BOOL(retVal);
749 FCIMPL1(void, ThreadNative::Sleep, INT32 iTime)
753 HELPER_METHOD_FRAME_BEGIN_0();
755 // validate the sleep time
756 if ((iTime < 0) && (iTime != INFINITE_TIMEOUT))
757 COMPlusThrowArgumentOutOfRange(W("millisecondsTimeout"), W("ArgumentOutOfRange_NeedNonNegOrNegative1"));
761 INT64 sPauseTime = g_PauseTime;
762 INT64 sTime = CLRGetTickCount64();
763 GetThread()->UserSleep(iTime);
764 iTime = (INT32)AdditionalWait(sPauseTime, sTime, iTime);
769 HELPER_METHOD_FRAME_END();
773 #define Sleep(dwMilliseconds) Dont_Use_Sleep(dwMilliseconds)
775 FCIMPL1(INT32, ThreadNative::GetManagedThreadId, ThreadBaseObject* th) {
778 FC_GC_POLL_NOT_NEEDED();
780 FCThrow(kNullReferenceException);
782 return th->GetManagedThreadId();
786 NOINLINE static Object* GetCurrentThreadHelper()
789 FC_INNER_PROLOG(ThreadNative::GetCurrentThread);
790 OBJECTREF refRetVal = NULL;
792 HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, refRetVal);
793 refRetVal = GetThread()->GetExposedObject();
794 HELPER_METHOD_FRAME_END();
797 return OBJECTREFToObject(refRetVal);
800 FCIMPL0(Object*, ThreadNative::GetCurrentThread)
803 OBJECTHANDLE ExposedObject = GetThread()->m_ExposedObject;
804 _ASSERTE(ExposedObject != 0); //Thread's constructor always initializes its GCHandle
805 Object* result = *((Object**) ExposedObject);
809 FC_INNER_RETURN(Object*, GetCurrentThreadHelper());
814 FCIMPL3(void, ThreadNative::SetStart, ThreadBaseObject* pThisUNSAFE, Object* pDelegateUNSAFE, INT32 iRequestedStackSize)
818 if (pThisUNSAFE==NULL)
819 FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
821 THREADBASEREF pThis = (THREADBASEREF) pThisUNSAFE;
822 OBJECTREF pDelegate = (OBJECTREF ) pDelegateUNSAFE;
824 HELPER_METHOD_FRAME_BEGIN_2(pThis, pDelegate);
826 _ASSERTE(pThis != NULL);
827 _ASSERTE(pDelegate != NULL); // Thread's constructor validates this
829 if (pThis->m_InternalThread == NULL)
831 // if we don't have an internal Thread object associated with this exposed object,
832 // now is our first opportunity to create one.
833 Thread *unstarted = SetupUnstartedThread();
835 PREFIX_ASSUME(unstarted != NULL);
837 if (GetThread()->GetDomain()->IgnoreUnhandledExceptions())
839 unstarted->SetThreadStateNC(Thread::TSNC_IgnoreUnhandledExceptions);
842 pThis->SetInternal(unstarted);
843 pThis->SetManagedThreadId(unstarted->GetThreadId());
844 unstarted->SetExposedObject(pThis);
845 unstarted->RequestedThreadStackSize(iRequestedStackSize);
848 // save off the delegate
849 pThis->SetDelegate(pDelegate);
851 HELPER_METHOD_FRAME_END();
856 // Set whether or not this is a background thread.
857 FCIMPL2(void, ThreadNative::SetBackground, ThreadBaseObject* pThisUNSAFE, CLR_BOOL isBackground)
861 if (pThisUNSAFE==NULL)
862 FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
864 // validate the thread
865 Thread *thread = pThisUNSAFE->GetInternal();
867 if (ThreadIsDead(thread))
868 FCThrowExVoid(kThreadStateException, IDS_EE_THREAD_DEAD_STATE, NULL, NULL, NULL);
870 HELPER_METHOD_FRAME_BEGIN_0();
872 thread->SetBackground(isBackground);
874 HELPER_METHOD_FRAME_END();
878 // Return whether or not this is a background thread.
879 FCIMPL1(FC_BOOL_RET, ThreadNative::IsBackground, ThreadBaseObject* pThisUNSAFE)
883 if (pThisUNSAFE==NULL)
884 FCThrowRes(kNullReferenceException, W("NullReference_This"));
886 // validate the thread
887 Thread *thread = pThisUNSAFE->GetInternal();
889 if (ThreadIsDead(thread))
890 FCThrowEx(kThreadStateException, IDS_EE_THREAD_DEAD_STATE, NULL, NULL, NULL);
892 FC_RETURN_BOOL(thread->IsBackground());
897 // Deliver the state of the thread as a consistent set of bits.
898 // This copied in VM\EEDbgInterfaceImpl.h's
899 // CorDebugUserState GetUserState( Thread *pThread )
900 // , so propogate changes to both functions
901 FCIMPL1(INT32, ThreadNative::GetThreadState, ThreadBaseObject* pThisUNSAFE)
906 Thread::ThreadState state;
908 if (pThisUNSAFE==NULL)
909 FCThrowRes(kNullReferenceException, W("NullReference_This"));
911 // validate the thread. Failure here implies that the thread was finalized
912 // and then resurrected.
913 Thread *thread = pThisUNSAFE->GetInternal();
916 FCThrowEx(kThreadStateException, IDS_EE_THREAD_CANNOT_GET, NULL, NULL, NULL);
918 HELPER_METHOD_FRAME_BEGIN_RET_0();
921 state = thread->GetSnapshotState();
923 if (state & Thread::TS_Background)
924 res |= ThreadBackground;
926 if (state & Thread::TS_Unstarted)
927 res |= ThreadUnstarted;
929 // Don't report a StopRequested if the thread has actually stopped.
930 if (state & Thread::TS_Dead)
932 if (state & Thread::TS_Aborted)
933 res |= ThreadAborted;
935 res |= ThreadStopped;
939 if (state & Thread::TS_AbortRequested)
940 res |= ThreadAbortRequested;
943 if (state & Thread::TS_Interruptible)
944 res |= ThreadWaitSleepJoin;
946 // Don't report a SuspendRequested if the thread has actually Suspended.
947 if ((state & Thread::TS_UserSuspendPending) &&
948 (state & Thread::TS_SyncSuspended)
951 res |= ThreadSuspended;
954 if (state & Thread::TS_UserSuspendPending)
956 res |= ThreadSuspendRequested;
959 HELPER_METHOD_POLL();
960 HELPER_METHOD_FRAME_END();
966 #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
968 // Indicate whether the thread will host an STA (this may fail if the thread has
969 // already been made part of the MTA, use GetApartmentState or the return state
970 // from this routine to check for this).
971 FCIMPL3(INT32, ThreadNative::SetApartmentState, ThreadBaseObject* pThisUNSAFE, INT32 iState, CLR_BOOL fireMDAOnMismatch)
975 if (pThisUNSAFE==NULL)
976 FCThrowRes(kNullReferenceException, W("NullReference_This"));
978 INT32 retVal = ApartmentUnknown;
980 THREADBASEREF pThis = (THREADBASEREF) pThisUNSAFE;
982 HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
984 // Translate state input. ApartmentUnknown is not an acceptable input state.
985 // Throw an exception here rather than pass it through to the internal
986 // routine, which asserts.
987 Thread::ApartmentState state = Thread::AS_Unknown;
988 if (iState == ApartmentSTA)
989 state = Thread::AS_InSTA;
990 else if (iState == ApartmentMTA)
991 state = Thread::AS_InMTA;
992 else if (iState == ApartmentUnknown)
993 state = Thread::AS_Unknown;
995 COMPlusThrow(kArgumentOutOfRangeException, W("ArgumentOutOfRange_Enum"));
997 Thread *thread = pThis->GetInternal();
999 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1002 pThis->EnterObjMonitor();
1004 // We can only change the apartment if the thread is unstarted or
1005 // running, and if it's running we have to be in the thread's
1007 if ((!ThreadNotStarted(thread) && !ThreadIsRunning(thread)) ||
1008 (!ThreadNotStarted(thread) && (GetThread() != thread)))
1014 state = thread->SetApartment(state, fireMDAOnMismatch == TRUE);
1018 pThis->LeaveObjMonitor();
1021 EX_END_CATCH_UNREACHABLE;
1024 pThis->LeaveObjMonitor();
1028 // Now it's safe to throw exceptions again.
1030 COMPlusThrow(kThreadStateException);
1032 // Translate state back into external form
1033 if (state == Thread::AS_InSTA)
1034 retVal = ApartmentSTA;
1035 else if (state == Thread::AS_InMTA)
1036 retVal = ApartmentMTA;
1037 else if (state == Thread::AS_Unknown)
1038 retVal = ApartmentUnknown;
1040 _ASSERTE(!"Invalid state returned from SetApartment");
1042 HELPER_METHOD_FRAME_END();
1048 // Return whether the thread hosts an STA, is a member of the MTA or is not
1049 // currently initialized for COM.
1050 FCIMPL1(INT32, ThreadNative::GetApartmentState, ThreadBaseObject* pThisUNSAFE)
1056 THREADBASEREF refThis = (THREADBASEREF) ObjectToOBJECTREF(pThisUNSAFE);
1058 HELPER_METHOD_FRAME_BEGIN_RET_1(refThis);
1060 if (refThis == NULL)
1062 COMPlusThrow(kNullReferenceException, W("NullReference_This"));
1065 Thread* thread = refThis->GetInternal();
1067 if (ThreadIsDead(thread))
1069 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_DEAD_STATE);
1072 Thread::ApartmentState state = thread->GetApartment();
1074 #ifdef FEATURE_COMINTEROP
1075 if (state == Thread::AS_Unknown)
1077 // If the CLR hasn't started COM yet, start it up and attempt the call again.
1078 // We do this in order to minimize the number of situations under which we return
1079 // ApartmentState.Unknown to our callers.
1083 state = thread->GetApartment();
1086 #endif // FEATURE_COMINTEROP
1088 // Translate state into external form
1089 retVal = ApartmentUnknown;
1090 if (state == Thread::AS_InSTA)
1092 retVal = ApartmentSTA;
1094 else if (state == Thread::AS_InMTA)
1096 retVal = ApartmentMTA;
1098 else if (state == Thread::AS_Unknown)
1100 retVal = ApartmentUnknown;
1104 _ASSERTE(!"Invalid state returned from GetApartment");
1107 HELPER_METHOD_FRAME_END();
1114 // Attempt to eagerly set the apartment state during thread startup.
1115 FCIMPL1(void, ThreadNative::StartupSetApartmentState, ThreadBaseObject* pThisUNSAFE)
1119 THREADBASEREF refThis = (THREADBASEREF) ObjectToOBJECTREF(pThisUNSAFE);
1121 HELPER_METHOD_FRAME_BEGIN_1(refThis);
1123 if (refThis == NULL)
1125 COMPlusThrow(kNullReferenceException, W("NullReference_This"));
1128 Thread* thread = refThis->GetInternal();
1130 if (!ThreadNotStarted(thread))
1131 COMPlusThrow(kThreadStateException, IDS_EE_THREADSTART_STATE);
1133 // Assert that the thread hasn't been started yet.
1134 _ASSERTE(Thread::TS_Unstarted & thread->GetSnapshotState());
1136 if ((g_pConfig != NULL) && !g_pConfig->LegacyApartmentInitPolicy())
1138 Thread::ApartmentState as = thread->GetExplicitApartment();
1139 if (as == Thread::AS_Unknown)
1141 thread->SetApartment(Thread::AS_InMTA, TRUE);
1145 HELPER_METHOD_FRAME_END();
1149 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
1151 void ReleaseThreadExternalCount(Thread * pThread)
1153 WRAPPER_NO_CONTRACT;
1154 pThread->DecExternalCount(FALSE);
1157 typedef Holder<Thread *, DoNothing, ReleaseThreadExternalCount> ThreadExternalCountHolder;
1159 // Wait for the thread to die
1160 BOOL ThreadNative::DoJoin(THREADBASEREF DyingThread, INT32 timeout)
1167 PRECONDITION(DyingThread != NULL);
1168 PRECONDITION((timeout >= 0) || (timeout == INFINITE_TIMEOUT));
1172 Thread * DyingInternal = DyingThread->GetInternal();
1174 // Validate the handle. It's valid to Join a thread that's not running -- so
1175 // long as it was once started.
1176 if (DyingInternal == 0 ||
1177 !(DyingInternal->m_State & Thread::TS_LegalToJoin))
1179 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_NOTSTARTED);
1182 // Don't grab the handle until we know it has started, to eliminate the race
1184 if (ThreadIsDead(DyingInternal) || !DyingInternal->HasValidThreadHandle())
1187 DWORD dwTimeOut32 = (timeout == INFINITE_TIMEOUT
1191 // There is a race here. DyingThread is going to close its thread handle.
1192 // If we grab the handle and then DyingThread closes it, we will wait forever
1193 // in DoAppropriateWait.
1194 int RefCount = DyingInternal->IncExternalCount();
1197 // !!! We resurrect the Thread Object.
1198 // !!! We will keep the Thread ref count to be 1 so that we will not try
1199 // !!! to destroy the Thread Object again.
1200 // !!! Do not call DecExternalCount here!
1201 _ASSERTE (!DyingInternal->HasValidThreadHandle());
1205 ThreadExternalCountHolder dyingInternalHolder(DyingInternal);
1207 if (!DyingInternal->HasValidThreadHandle())
1213 DWORD rv = DyingInternal->JoinEx(dwTimeOut32, (WaitMode)(WaitMode_Alertable/*alertable*/|WaitMode_InDeadlock));
1224 if(!DyingInternal->HasValidThreadHandle())
1229 _ASSERTE(!"This return code is not understood \n");
1237 // We don't get a constructor for ThreadBaseObject, so we rely on the fact that this
1238 // method is only called once, out of SetStart. Since SetStart is private/native
1239 // and only called from the constructor, we'll only get called here once to set it
1240 // up and once (with NULL) to tear it down. The 'null' can only come from Finalize
1241 // because the constructor throws if it doesn't get a valid delegate.
1242 void ThreadBaseObject::SetDelegate(OBJECTREF delegate)
1252 #ifdef APPDOMAIN_STATE
1253 if (delegate != NULL)
1255 AppDomain *pDomain = delegate->GetAppDomain();
1256 Thread *pThread = GetInternal();
1257 AppDomain *kickoffDomain = pThread->GetKickOffDomain();
1258 _ASSERTE_ALL_BUILDS("clr/src/VM/COMSynchronizable.cpp", !pDomain || pDomain == kickoffDomain);
1259 _ASSERTE_ALL_BUILDS("clr/src/VM/COMSynchronizable.cpp", kickoffDomain == GetThread()->GetDomain());
1263 SetObjectReferenceUnchecked( (OBJECTREF *)&m_Delegate, delegate );
1265 // If the delegate is being set then initialize the other data members.
1266 if (m_Delegate != NULL)
1268 // Initialize the thread priority to normal.
1269 m_Priority = ThreadNative::PRIORITY_NORMAL;
1274 // If the exposed object is created after-the-fact, for an existing thread, we call
1275 // InitExisting on it. This is the other "construction", as opposed to SetDelegate.
1276 void ThreadBaseObject::InitExisting()
1286 Thread *pThread = GetInternal();
1288 switch (pThread->GetThreadPriority())
1290 case THREAD_PRIORITY_LOWEST:
1291 case THREAD_PRIORITY_IDLE:
1292 m_Priority = ThreadNative::PRIORITY_LOWEST;
1295 case THREAD_PRIORITY_BELOW_NORMAL:
1296 m_Priority = ThreadNative::PRIORITY_BELOW_NORMAL;
1299 case THREAD_PRIORITY_NORMAL:
1300 m_Priority = ThreadNative::PRIORITY_NORMAL;
1303 case THREAD_PRIORITY_ABOVE_NORMAL:
1304 m_Priority = ThreadNative::PRIORITY_ABOVE_NORMAL;
1307 case THREAD_PRIORITY_HIGHEST:
1308 case THREAD_PRIORITY_TIME_CRITICAL:
1309 m_Priority = ThreadNative::PRIORITY_HIGHEST;
1312 case THREAD_PRIORITY_ERROR_RETURN:
1314 m_Priority = ThreadNative::PRIORITY_NORMAL;
1318 m_Priority = ThreadNative::PRIORITY_NORMAL;
1324 #ifndef FEATURE_LEAK_CULTURE_INFO
1325 OBJECTREF ThreadBaseObject::GetManagedThreadCulture(BOOL bUICulture)
1334 // This is the case when we're building mscorlib and haven't yet created
1335 // the system assembly.
1336 if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
1340 OBJECTREF *pCurrentCulture = NULL;
1341 Thread *pThread = GetInternal();
1342 FieldDesc *pFD = NULL;
1346 pFD = pThread->managedThreadCurrentUICulture;
1350 pFD = pThread->managedThreadCurrentCulture;
1355 pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD, NULL);
1356 if (pCurrentCulture)
1358 return *pCurrentCulture;
1365 CULTUREINFOBASEREF ThreadBaseObject::GetCurrentUserCulture()
1367 WRAPPER_NO_CONTRACT;
1369 return (CULTUREINFOBASEREF)GetManagedThreadCulture(false);
1372 CULTUREINFOBASEREF ThreadBaseObject::GetCurrentUICulture()
1374 WRAPPER_NO_CONTRACT;
1376 return (CULTUREINFOBASEREF)GetManagedThreadCulture(true);
1379 // If the thread pool thread switched appdomains and the culture was set, the culture won't be
1380 // reset for the second appdomain. It's impossible to do general cleanup of thread pool threads
1381 // because we don't have the right extensible infrastructure for it. For example, if the second
1382 // appdomain was in a different CLR you won't be able to reset the culture without introducing
1383 // new cross-CLR communication mechanism. However, note that this isn't a user scenario in
1385 void ThreadBaseObject::ResetCurrentUserCulture()
1387 WRAPPER_NO_CONTRACT;
1388 ResetManagedThreadCulture(false);
1391 void ThreadBaseObject::ResetCurrentUICulture()
1393 WRAPPER_NO_CONTRACT;
1394 ResetManagedThreadCulture(true);
1397 void ThreadBaseObject::ResetManagedThreadCulture(BOOL bUICulture)
1408 // This is the case when we're building mscorlib and haven't yet created
1409 // the system assembly.
1410 if (SystemDomain::System()->SystemAssembly()==NULL || g_fForbidEnterEE) {
1414 Thread *pThread = GetInternal();
1415 FieldDesc *pFD = NULL;
1419 pFD = pThread->managedThreadCurrentUICulture;
1423 pFD = pThread->managedThreadCurrentCulture;
1428 OBJECTREF *pCulture = NULL;
1429 BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(COMPlusThrowSO());
1430 pCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD, NULL);
1433 SetObjectReferenceUnchecked(pCulture, NULL);
1435 END_SO_INTOLERANT_CODE;
1440 #endif // FEATURE_LEAK_CULTURE_INFO
1443 FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE)
1447 // This function is intentionally blank.
1448 // See comment in code:MethodTable::CallFinalizer.
1450 _ASSERTE (!"Should not be called");
1456 #ifdef FEATURE_COMINTEROP
1457 FCIMPL1(void, ThreadNative::DisableComObjectEagerCleanup, ThreadBaseObject* pThisUNSAFE)
1461 _ASSERTE(pThisUNSAFE != NULL);
1462 VALIDATEOBJECT(pThisUNSAFE);
1463 Thread *pThread = pThisUNSAFE->GetInternal();
1465 HELPER_METHOD_FRAME_BEGIN_0();
1467 if (pThread == NULL)
1468 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1470 pThread->SetDisableComObjectEagerCleanup();
1472 HELPER_METHOD_FRAME_END();
1475 #endif //FEATURE_COMINTEROP
1477 #ifdef FEATURE_LEAK_CULTURE_INFO
1478 FCIMPL1(FC_BOOL_RET, ThreadNative::SetThreadUILocale, StringObject* localeNameUNSAFE)
1484 STRINGREF name = (STRINGREF) localeNameUNSAFE;
1485 VALIDATEOBJECTREF(name);
1487 HELPER_METHOD_FRAME_BEGIN_RET_0();
1489 LCID lcid=NewApis::LocaleNameToLCID(name->GetBuffer(),0);
1492 ThrowHR(HRESULT_FROM_WIN32(GetLastError()));
1495 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
1496 IHostTaskManager *manager = CorHost2::GetHostTaskManager();
1498 BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread());
1499 result = (manager->SetUILocale(lcid) == S_OK);
1500 END_SO_TOLERANT_CODE_CALLING_HOST;
1502 #endif // FEATURE_INCLUDE_ALL_INTERFACES
1504 HELPER_METHOD_FRAME_END();
1506 FC_RETURN_BOOL(result);
1509 #endif // FEATURE_LEAK_CULTURE_INFO
1511 FCIMPL0(Object*, ThreadNative::GetDomain)
1515 APPDOMAINREF refRetVal = NULL;
1517 Thread* thread = GetThread();
1519 if ((thread) && (thread->GetDomain()))
1521 HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal);
1522 refRetVal = (APPDOMAINREF) thread->GetDomain()->GetExposedObject();
1523 HELPER_METHOD_FRAME_END();
1526 return OBJECTREFToObject(refRetVal);
1530 #if defined(_TARGET_X86_) && defined(_MSC_VER)
1531 __declspec(naked) LPVOID __fastcall ThreadNative::FastGetDomain()
1533 STATIC_CONTRACT_MODE_COOPERATIVE;
1534 STATIC_CONTRACT_GC_NOTRIGGER;
1535 STATIC_CONTRACT_NOTHROW;
1536 STATIC_CONTRACT_SO_TOLERANT;
1542 mov eax, dword ptr [eax]AppDomain.m_ExposedObject
1545 mov eax, dword ptr [eax]
1550 #else // _TARGET_X86_ && _MSC_VER
1551 LPVOID F_CALL_CONV ThreadNative::FastGetDomain()
1564 OBJECTHANDLE ExposedObject;
1566 pDomain = GetAppDomain();
1570 ExposedObject = pDomain->m_ExposedObject;
1571 if (ExposedObject) {
1572 return *(LPVOID *)ExposedObject;
1576 #endif // _TARGET_X86_ && _MSC_VER
1578 #ifdef FEATURE_REMOTING
1579 // This is just a helper method that lets BCL get to the managed context
1580 // from the contextID.
1581 FCIMPL1(Object*, ThreadNative::GetContextFromContextID, LPVOID ContextID)
1585 OBJECTREF rv = NULL;
1586 Context* pCtx = (Context *) ContextID;
1587 // Get the managed context backing this unmanaged context
1588 rv = pCtx->GetExposedObjectRaw();
1590 // This assert maintains the following invariant:
1591 // Only default unmanaged contexts can have a null managed context
1592 // (All non-deafult contexts are created as managed contexts first, and then
1593 // hooked to the unmanaged context)
1594 _ASSERTE((rv != NULL) || (pCtx->GetDomain()->GetDefaultContext() == pCtx));
1596 return OBJECTREFToObject(rv);
1601 FCIMPL6(Object*, ThreadNative::InternalCrossContextCallback, ThreadBaseObject* refThis, ContextBaseObject* refContext, LPVOID contextID, INT32 appDomainId, Object* oDelegateUNSAFE, PtrArray* oArgsUNSAFE)
1605 _ASSERTE(refThis != NULL);
1606 VALIDATEOBJECT(refThis);
1607 Thread *pThread = refThis->GetInternal();
1608 Context *pCtx = (Context *)contextID;
1611 _ASSERTE(pCtx && (refContext == NULL || pCtx->GetExposedObjectRaw() == NULL ||
1612 ObjectToOBJECTREF(refContext) == pCtx->GetExposedObjectRaw()));
1613 LOG((LF_APPDOMAIN, LL_INFO1000, "ThreadNative::InternalCrossContextCallback: %p, %p\n", refContext, pCtx));
1614 // install our frame. We have to put it here before we put the helper frame on
1616 // Set the VM conext
1620 OBJECTREF oDelegate;
1622 // We need to report the managed context object because it may become unreachable in the caller,
1623 // however we have to keep it alive, otherwise its finalizer could free the unmanaged internal context
1628 gc.oDelegate = ObjectToOBJECTREF(oDelegateUNSAFE);
1629 gc.oArgs = ObjectToOBJECTREF(oArgsUNSAFE);
1630 gc.oContext = ObjectToOBJECTREF(refContext);
1632 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1634 if (pThread == NULL)
1635 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1638 MethodDesc* pTargetMD = COMDelegate::GetMethodDesc(gc.oDelegate);
1639 _ASSERTE(pTargetMD->IsStatic());
1642 // If we have a non-zero appDomain index, this is a x-domain call
1643 // We must verify that the AppDomain is not unloaded
1644 PREPARE_NONVIRTUAL_CALLSITE(METHOD__THREAD__COMPLETE_CROSSCONTEXTCALLBACK);
1646 AppDomainFromIDHolder ad;
1647 if (appDomainId != 0)
1650 // NOTE: there is a potential race between the time we retrieve the app domain pointer,
1651 // and the time which this thread enters the domain.
1653 // To solve the race, we rely on the fact that there is a thread sync
1654 // between releasing an app domain's handle, and destroying the app domain. Thus
1655 // it is important that we not go into preemptive gc mode in that window.
1658 ad.Assign(ADID(appDomainId), TRUE);
1660 if (ad.IsUnloaded() || !ad->CanThreadEnter(pThread))
1661 COMPlusThrow(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded"));
1665 // Verify that the Context is valid.
1666 if ( !Context::ValidateContext(pCtx) )
1667 COMPlusThrow(kRemotingException, W("Remoting_InvalidContext"));
1669 DEBUG_ASSURE_NO_RETURN_BEGIN(COMSYNCH)
1671 FrameWithCookie<ContextTransitionFrame> frame;
1673 Context* pCurrContext = pThread->GetContext();
1674 bool fTransition = (pCurrContext != pCtx);
1675 BOOL fSameDomain = (appDomainId==0) || (pCurrContext->GetDomain()->GetId() == (ADID)appDomainId);
1676 _ASSERTE( fTransition || fSameDomain);
1679 ad->EnterContext(pThread,pCtx, &frame);
1681 pThread->EnterContextRestricted(pCtx,&frame);
1685 LOG((LF_EH, LL_INFO100, "MSCORLIB_ENTER_CONTEXT( %s::%s ): %s\n",
1686 pTargetMD->m_pszDebugClassName,
1687 pTargetMD->m_pszDebugMethodName,
1688 fTransition ? "ENTERED" : "NOP"));
1690 Exception* pOriginalException=NULL;
1694 DECLARE_ARGHOLDER_ARRAY(callArgs, 2);
1696 #if CHECK_APP_DOMAIN_LEAKS
1697 // We're passing the delegate object to another appdomain
1698 // without marshaling, that is OK - it's a static function delegate
1699 // but we should mark it as agile then.
1700 gc.oDelegate->SetSyncBlockAppDomainAgile();
1702 callArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.oDelegate);
1703 callArgs[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.oArgs);
1705 CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
1706 CALL_MANAGED_METHOD_RETREF(gc.oRetVal, OBJECTREF, callArgs);
1710 LOG((LF_EH, LL_INFO100, "MSCORLIB_CONTEXT_TRANSITION( %s::%s ): exception in flight\n", pTargetMD->m_pszDebugClassName, pTargetMD->m_pszDebugMethodName));
1712 if (!fTransition || fSameDomain)
1717 pThread->ReturnToContext(&frame);
1719 #ifdef FEATURE_TESTHOOKS
1722 TESTHOOKCALL(LeftAppDomain(appDomainId));
1728 pOriginalException=EXTRACT_EXCEPTION();
1729 CAPTURE_BUCKETS_AT_TRANSITION(pThread, CLRException::GetThrowableFromException(pOriginalException));
1730 goto lAfterCtxUnwind;
1732 EX_END_CATCH_UNREACHABLE;
1736 LOG((LF_EH, LL_INFO100, "MSCORLIB_RaiseCrossContextException( %s::%s )\n", pTargetMD->m_pszDebugClassName, pTargetMD->m_pszDebugMethodName));
1737 pThread->RaiseCrossContextException(pOriginalException,&frame);
1740 LOG((LF_EH, LL_INFO100, "MSCORLIB_LEAVE_CONTEXT_TRANSITION( %s::%s )\n", pTargetMD->m_pszDebugClassName, pTargetMD->m_pszDebugMethodName));
1745 pThread->ReturnToContext(&frame);
1747 #ifdef FEATURE_TESTHOOKS
1750 TESTHOOKCALL(LeftAppDomain(appDomainId));
1754 DEBUG_ASSURE_NO_RETURN_END(COMSYNCH)
1756 HELPER_METHOD_FRAME_END();
1757 return OBJECTREFToObject(gc.oRetVal);
1760 #endif //FEATURE_REMOTING
1763 // nativeGetSafeCulture is used when the culture get requested from the thread object.
1764 // we have to check the culture in the FCALL because in FCALL the thread cannot be
1765 // interrupted and unload other app domian.
1766 // the concern here is if the thread hold a subclassed culture object and somebody
1767 // requested it from other app domain then we shouldn't hold any reference to that
1768 // culture object any time because the app domain created this culture may get
1769 // unloaded and this culture will survive although the type metadata will be unloaded
1770 // and GC will crash first time accessing this object after the app domain unload.
1772 #ifdef FEATURE_LEAK_CULTURE_INFO
1773 FCIMPL4(FC_BOOL_RET, ThreadNative::nativeGetSafeCulture,
1774 ThreadBaseObject* threadUNSAFE,
1777 OBJECTREF* safeCulture)
1781 THREADBASEREF thread(threadUNSAFE);
1783 CULTUREINFOBASEREF pCulture = isUI ? thread->GetCurrentUICulture() : thread->GetCurrentUserCulture();
1784 if (pCulture != NULL) {
1785 if (pCulture->IsSafeCrossDomain() || pCulture->GetCreatedDomainID() == ADID(appDomainId)) {
1786 SetObjectReference(safeCulture, pCulture, pCulture->GetAppDomain());
1788 FC_RETURN_BOOL(FALSE);
1791 FC_RETURN_BOOL(TRUE);
1794 #endif // FEATURE_LEAK_CULTURE_INFO
1796 #ifndef FEATURE_LEAK_CULTURE_INFO
1797 void QCALLTYPE ThreadNative::nativeInitCultureAccessors()
1803 Thread* pThread = GetThread();
1804 pThread->InitCultureAccessors();
1808 #endif // FEATURE_LEAK_CULTURE_INFO
1811 void QCALLTYPE ThreadNative::InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len)
1817 Thread* pThread = &(*thread);
1819 #ifdef PROFILING_SUPPORTED
1821 BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
1824 g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, 0, NULL);
1828 g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, len, (WCHAR*)name);
1832 #endif // PROFILING_SUPPORTED
1835 #ifdef DEBUGGING_SUPPORTED
1836 if (CORDebuggerAttached())
1838 _ASSERTE(NULL != g_pDebugInterface);
1839 g_pDebugInterface->NameChangeEvent(NULL, pThread);
1841 #endif // DEBUGGING_SUPPORTED
1846 UINT64 QCALLTYPE ThreadNative::GetProcessDefaultStackSize()
1855 if (!Thread::GetProcessDefaultStackSize(&reserve, &commit))
1856 reserve = 1024 * 1024;
1860 return (UINT64)reserve;
1865 FCIMPL1(FC_BOOL_RET, ThreadNative::IsThreadpoolThread, ThreadBaseObject* thread)
1870 FCThrowRes(kNullReferenceException, W("NullReference_This"));
1872 Thread *pThread = thread->GetInternal();
1874 if (pThread == NULL)
1875 FCThrowEx(kThreadStateException, IDS_EE_THREAD_DEAD_STATE, NULL, NULL, NULL);
1877 BOOL ret = pThread->IsThreadPoolThread();
1881 FC_RETURN_BOOL(ret);
1886 FCIMPL1(void, ThreadNative::SpinWait, int iterations)
1891 // If we're not going to spin for long, it's ok to remain in cooperative mode.
1892 // The threshold is determined by the cost of entering preemptive mode; if we're
1893 // spinning for less than that number of cycles, then switching to preemptive
1894 // mode won't help a GC start any faster. That number is right around 1000000
1897 if (iterations <= 1000000)
1899 for(int i = 0; i < iterations; i++)
1905 // Too many iterations; better switch to preemptive mode to avoid stalling a GC.
1907 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
1910 for(int i = 0; i < iterations; i++)
1913 HELPER_METHOD_FRAME_END();
1917 BOOL QCALLTYPE ThreadNative::YieldThread()
1925 ret = __SwitchToThread(0, CALLER_LIMITS_SPINNING);
1932 #ifdef FEATURE_COMPRESSEDSTACK
1933 FCIMPL2(void*, ThreadNative::SetAppDomainStack, ThreadBaseObject* pThis, SafeHandle* hcsUNSAFE)
1938 SAFEHANDLE hcsSAFE = (SAFEHANDLE) hcsUNSAFE;
1939 HELPER_METHOD_FRAME_BEGIN_RET_1(hcsSAFE);
1942 void* unmanagedCompressedStack = NULL;
1943 if (hcsSAFE != NULL)
1945 unmanagedCompressedStack = (void *)hcsSAFE->GetHandle();
1949 VALIDATEOBJECT(pThis);
1950 Thread *pThread = pThis->GetInternal();
1951 if (pThread == NULL)
1952 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1954 pRet = StackCompressor::SetAppDomainStack(pThread, unmanagedCompressedStack);
1955 HELPER_METHOD_FRAME_END_POLL();
1961 FCIMPL2(void, ThreadNative::RestoreAppDomainStack, ThreadBaseObject* pThis, void* appDomainStack)
1965 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
1967 VALIDATEOBJECT(pThis);
1968 Thread *pThread = pThis->GetInternal();
1969 if (pThread == NULL)
1970 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1972 StackCompressor::RestoreAppDomainStack(pThread, appDomainStack);
1973 HELPER_METHOD_FRAME_END_POLL();
1976 #endif //#ifdef FEATURE_COMPRESSEDSTACK
1978 FCIMPL0(void, ThreadNative::FCMemoryBarrier)
1987 FCIMPL2(void, ThreadNative::SetAbortReason, ThreadBaseObject* pThisUNSAFE, Object* pObject)
1991 if (pThisUNSAFE==NULL)
1992 FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
1994 OBJECTREF refObject = static_cast<OBJECTREF>(pObject);
1996 Thread *pThread = pThisUNSAFE->GetInternal();
1998 // If the OBJECTHANDLE is not 0, already set so just return
1999 if (pThread != NULL && pThread->m_AbortReason != 0)
2002 // Set up a frame in case of GC or EH
2003 HELPER_METHOD_FRAME_BEGIN_1(refObject)
2005 if (pThread == NULL)
2006 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
2008 // Get the AppDomain ID for the AppDomain on the currently running thread.
2009 // NOTE: the currently running thread may be different from this thread object!
2010 AppDomain *pCurrentDomain = GetThread()->GetDomain();
2011 ADID adid = pCurrentDomain->GetId();
2013 // Create a OBJECTHANDLE for the object.
2014 OBJECTHANDLE oh = pCurrentDomain->CreateHandle(refObject);
2016 // Scope the lock to peeking at and updating the two fields on the Thread object.
2017 { // Atomically check whether the OBJECTHANDLE has been set, and if not,
2018 // store it and the ADID of the object.
2019 // NOTE: get the lock on this thread object, not on the executing thread.
2020 Thread::AbortRequestLockHolder lock(pThread);
2021 if (pThread->m_AbortReason == 0)
2023 pThread->m_AbortReason = oh;
2024 pThread->m_AbortReasonDomainID = adid;
2025 // Set the OBJECTHANDLE so we can know that we stored it on the Thread object.
2030 // If the OBJECTHANDLE created above was not stored onto the Thread object, then
2031 // another thread beat this one to the update. Destroy the OBJECTHANDLE that
2032 // was not used, created above.
2038 HELPER_METHOD_FRAME_END()
2044 FCIMPL1(void, ThreadNative::ClearAbortReason, ThreadBaseObject* pThisUNSAFE)
2048 if (pThisUNSAFE==NULL)
2049 FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
2051 Thread *pThread = pThisUNSAFE->GetInternal();
2053 // Clearing from managed code can only happen on the current thread.
2054 _ASSERTE(pThread == GetThread());
2056 HELPER_METHOD_FRAME_BEGIN_0();
2058 if (pThread == NULL)
2059 COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
2061 pThread->ClearAbortReason();
2063 HELPER_METHOD_FRAME_END();