Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / vm / comsynchronizable.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5
6 /*============================================================
7 **
8 ** Header: COMSynchronizable.cpp
9 **
10 ** Purpose: Native methods on System.SynchronizableObject
11 **          and its subclasses.
12 **
13 **
14 ===========================================================*/
15
16 #include "common.h"
17
18 #include <object.h>
19 #include "threads.h"
20 #include "excep.h"
21 #include "vars.hpp"
22 #include "field.h"
23 #include "security.h"
24 #include "comsynchronizable.h"
25 #include "dbginterface.h"
26 #include "comdelegate.h"
27 #ifdef FEATURE_REMOTING
28 #include "remoting.h"
29 #endif
30 #include "eeconfig.h"
31 #ifdef FEATURE_REMOTING
32 #include "appdomainhelper.h"
33 #include "objectclone.h"
34 #else
35 #include "callhelpers.h"
36 #endif
37 #include "appdomain.hpp"
38 #include "appdomain.inl"
39 #ifdef FEATURE_REMOTING
40 #include "crossdomaincalls.h"
41 #endif
42
43 #include "newapis.h"
44
45 // To include definition of CAPTURE_BUCKETS_AT_TRANSITION
46 #include "exstate.h"
47
48 // The two threads need to communicate some information.  Any object references must
49 // be declared to GC.
50 struct SharedState
51 {
52     OBJECTHANDLE    m_Threadable;
53     OBJECTHANDLE    m_ThreadStartArg;
54     Thread         *m_Internal;
55
56     SharedState(OBJECTREF threadable, OBJECTREF threadStartArg, Thread *internal)
57     {
58         CONTRACTL
59         {
60             GC_NOTRIGGER;
61             THROWS;  // From CreateHandle()
62             MODE_COOPERATIVE;
63         }
64         CONTRACTL_END;
65         AppDomainFromIDHolder ad(internal->GetKickOffDomainId(), TRUE);
66         if (ad.IsUnloaded())
67             COMPlusThrow(kAppDomainUnloadedException);
68
69         m_Threadable = ad->CreateHandle(threadable);
70         m_ThreadStartArg = ad->CreateHandle(threadStartArg);
71
72         m_Internal = internal;
73     }
74
75     ~SharedState()
76     {
77         CONTRACTL
78         {
79             GC_NOTRIGGER;
80             NOTHROW;
81             MODE_COOPERATIVE;
82         }
83         CONTRACTL_END;
84
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);
91         if (!ad.IsUnloaded())
92         {
93             DestroyHandle(m_Threadable);
94             DestroyHandle(m_ThreadStartArg);
95         }
96     }
97 };
98
99
100 // For the following helpers, we make no attempt to synchronize.  The app developer
101 // is responsible for managing his own race conditions.
102 //
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)
106 {
107     WRAPPER_NO_CONTRACT;
108     return (t && t->IsUnstarted() && !t->HasValidThreadHandle());
109 }
110
111 static inline BOOL ThreadIsRunning(Thread *t)
112 {
113     WRAPPER_NO_CONTRACT;
114 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
115     return (t &&
116             (t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 &&
117             (CLRTaskHosted()? t->GetHostTask()!=NULL:t->HasValidThreadHandle()));
118 #else // !FEATURE_INCLUDE_ALL_INTERFACES
119     return (t &&
120             (t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 &&
121             (t->HasValidThreadHandle()));
122 #endif // FEATURE_INCLUDE_ALL_INTERFACES
123 }
124
125 static inline BOOL ThreadIsDead(Thread *t)
126 {
127     WRAPPER_NO_CONTRACT;
128     return (t == 0 || t->IsDead());
129 }
130
131
132 // Map our exposed notion of thread priorities into the enumeration that NT uses.
133 static INT32 MapToNTPriority(INT32 ours)
134 {
135     CONTRACTL
136     {
137         GC_NOTRIGGER;
138         THROWS;
139         MODE_ANY;
140     }
141     CONTRACTL_END;
142
143     INT32   NTPriority = 0;
144
145     switch (ours)
146     {
147     case ThreadNative::PRIORITY_LOWEST:
148         NTPriority = THREAD_PRIORITY_LOWEST;
149         break;
150
151     case ThreadNative::PRIORITY_BELOW_NORMAL:
152         NTPriority = THREAD_PRIORITY_BELOW_NORMAL;
153         break;
154
155     case ThreadNative::PRIORITY_NORMAL:
156         NTPriority = THREAD_PRIORITY_NORMAL;
157         break;
158
159     case ThreadNative::PRIORITY_ABOVE_NORMAL:
160         NTPriority = THREAD_PRIORITY_ABOVE_NORMAL;
161         break;
162
163     case ThreadNative::PRIORITY_HIGHEST:
164         NTPriority = THREAD_PRIORITY_HIGHEST;
165         break;
166
167     default:
168         COMPlusThrow(kArgumentOutOfRangeException, W("Argument_InvalidFlag"));
169     }
170     return NTPriority;
171 }
172
173
174 // Map to our exposed notion of thread priorities from the enumeration that NT uses.
175 INT32 MapFromNTPriority(INT32 NTPriority)
176 {
177     LIMITED_METHOD_CONTRACT;
178
179     INT32   ours = 0;
180
181     if (NTPriority <= THREAD_PRIORITY_LOWEST)
182     {
183         // managed code does not support IDLE.  Map it to PRIORITY_LOWEST.
184         ours = ThreadNative::PRIORITY_LOWEST;
185     }
186     else if (NTPriority >= THREAD_PRIORITY_HIGHEST)
187     {
188         ours = ThreadNative::PRIORITY_HIGHEST;
189     }
190     else if (NTPriority == THREAD_PRIORITY_BELOW_NORMAL)
191     {
192         ours = ThreadNative::PRIORITY_BELOW_NORMAL;
193     }
194     else if (NTPriority == THREAD_PRIORITY_NORMAL)
195     {
196         ours = ThreadNative::PRIORITY_NORMAL;
197     }
198     else if (NTPriority == THREAD_PRIORITY_ABOVE_NORMAL)
199     {
200         ours = ThreadNative::PRIORITY_ABOVE_NORMAL;
201     }
202     else
203     {
204         _ASSERTE (!"not supported priority");
205         ours = ThreadNative::PRIORITY_NORMAL;
206     }
207     return ours;
208 }
209
210
211 void ThreadNative::KickOffThread_Worker(LPVOID ptr)
212 {
213     CONTRACTL
214     {
215         GC_TRIGGERS;
216         THROWS;
217         MODE_COOPERATIVE;
218         SO_TOLERANT;
219     }
220     CONTRACTL_END;
221
222     KickOffThread_Args *args = (KickOffThread_Args *) ptr;
223     _ASSERTE(ObjectFromHandle(args->share->m_Threadable) != NULL);
224     args->retVal = 0;
225
226     // we are saving the delagate and result primarily for debugging
227     struct _gc
228     {
229         OBJECTREF orThreadStartArg;
230         OBJECTREF orDelegate;
231         OBJECTREF orResult;
232         OBJECTREF orThread;
233     } gc;
234     ZeroMemory(&gc, sizeof(gc));
235
236     Thread *pThread;
237     pThread = GetThread();
238     _ASSERTE(pThread);
239     GCPROTECT_BEGIN(gc);
240     BEGIN_SO_INTOLERANT_CODE(pThread);
241
242     gc.orDelegate = ObjectFromHandle(args->share->m_Threadable);
243     gc.orThreadStartArg = ObjectFromHandle(args->share->m_ThreadStartArg);
244
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
250     //  class.
251
252     delete args->share;
253     args->share = 0;
254
255     MethodDesc *pMeth = ((DelegateEEClass*)( gc.orDelegate->GetMethodTable()->GetClass() ))->m_pInvokeMethod;
256     _ASSERTE(pMeth);
257     MethodDescCallSite invokeMethod(pMeth, &gc.orDelegate);
258
259     if (MscorlibBinder::IsClass(gc.orDelegate->GetMethodTable(), CLASS__PARAMETERIZEDTHREADSTART))
260     {
261         //Parameterized ThreadStart
262         ARG_SLOT arg[2];
263
264         arg[0] = ObjToArgSlot(gc.orDelegate);
265         arg[1]=ObjToArgSlot(gc.orThreadStartArg);
266         invokeMethod.Call(arg);
267     }
268     else
269     {
270         //Simple ThreadStart
271         ARG_SLOT arg[1];
272
273         arg[0] = ObjToArgSlot(gc.orDelegate);
274         invokeMethod.Call(arg);
275     }
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());
277
278     END_SO_INTOLERANT_CODE;
279     GCPROTECT_END();
280 }
281
282 // Helper to avoid two EX_TRY/EX_CATCH blocks in one function
283 static void PulseAllHelper(Thread* pThread)
284 {
285     CONTRACTL
286     {
287         GC_TRIGGERS;
288         DISABLED(NOTHROW);
289         MODE_COOPERATIVE;
290     }
291     CONTRACTL_END;
292
293     EX_TRY
294     {
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();
300     }
301     EX_CATCH
302     {
303         // just keep going...
304     }
305     EX_END_CATCH(SwallowAllExceptions)
306 }
307
308 // When an exposed thread is started by Win32, this is where it starts.
309 ULONG __stdcall ThreadNative::KickOffThread(void* pass)
310 {
311
312     CONTRACTL
313     {
314         GC_TRIGGERS;
315         THROWS;
316         MODE_ANY;
317         SO_TOLERANT;
318     }
319     CONTRACTL_END;
320
321     ULONG retVal = 0;
322     // Before we do anything else, get Setup so that we have a real thread.
323
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);
326
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;
331
332     Thread* pThread = args.pThread;
333
334     _ASSERTE(pThread != NULL);
335
336     BOOL ok = TRUE;
337
338     {
339         EX_TRY
340         {
341             CExecutionEngine::CheckThreadState(0);
342         }
343         EX_CATCH
344         {
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())
352                 EX_RETHROW;
353         }
354         EX_END_CATCH(SwallowAllExceptions);
355         if (CExecutionEngine::CheckThreadStateNoCreate(0) == NULL)
356         {
357             // We can not 
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.
362             ok = FALSE;
363         }
364     }
365
366     if (ok)
367     {
368         ok = pThread->HasStarted();
369     }
370
371     if (ok)
372     {
373         // Do not swallow the unhandled exception here
374         //
375
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());
379
380         // We have a sticky problem here.
381         //
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.
387         //
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.
391
392         _ASSERTE(GetThread() == pThread);        // Now that it's started
393         ManagedThreadBase::KickOff(pThread->GetKickOffDomainId(), KickOffThread_Worker, &args);
394
395         // If TS_FailStarted is set then the args are deleted in ThreadNative::StartInner
396         if ((args.share) && !pThread->HasThreadState(Thread::TS_FailStarted))
397         {
398             delete args.share;
399         }
400
401         PulseAllHelper(pThread);
402
403         GCX_PREEMP_NO_DTOR();
404
405         pThread->ClearThreadCPUGroupAffinity();
406
407         DestroyThread(pThread);
408     }
409
410     END_SO_INTOLERANT_CODE;
411
412     return retVal;
413 }
414
415
416 FCIMPL2(void, ThreadNative::Start, ThreadBaseObject* pThisUNSAFE, StackCrawlMark* pStackMark)
417 {
418     FCALL_CONTRACT;
419
420     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
421
422     StartInner(pThisUNSAFE, pStackMark);
423
424     HELPER_METHOD_FRAME_END_POLL();
425 }
426 FCIMPLEND
427
428 // Start up a thread, which by now should be in the ThreadStore's Unstarted list.
429 void ThreadNative::StartInner(ThreadBaseObject* pThisUNSAFE, StackCrawlMark* pStackMark)
430 {
431     CONTRACTL
432     {
433         GC_TRIGGERS;
434         THROWS;
435         MODE_COOPERATIVE;
436     }
437     CONTRACTL_END;
438
439     struct _gc
440     {
441         THREADBASEREF   pThis;
442     } gc;
443
444     gc.pThis       = (THREADBASEREF) pThisUNSAFE;
445
446     GCPROTECT_BEGIN(gc);
447
448     if (gc.pThis == NULL)
449         COMPlusThrow(kNullReferenceException, W("NullReference_This"));
450
451     Thread        *pNewThread = gc.pThis->GetInternal();
452     if (pNewThread == NULL)
453         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
454
455     _ASSERTE(GetThread() != NULL);          // Current thread wandered in!
456
457     gc.pThis->EnterObjMonitor();
458
459     EX_TRY
460     {
461         // Is the thread already started?  You can't restart a thread.
462         if (!ThreadNotStarted(pNewThread))
463         {
464             COMPlusThrow(kThreadStateException, IDS_EE_THREADSTART_STATE);
465         }
466
467         OBJECTREF   threadable = gc.pThis->GetDelegate();
468         OBJECTREF   threadStartArg = gc.pThis->GetThreadStartArg();
469         gc.pThis->SetDelegate(NULL);
470         gc.pThis->SetThreadStartArg(NULL);
471
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);
475
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));
479
480         pNewThread->IncExternalCount();
481
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());
485
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.
489
490         BOOL success = pNewThread->CreateNewThread(
491                                         pNewThread->RequestedThreadStackSize() /* 0 stackSize override*/,
492                                         KickOffThread, share);
493
494         if (!success)
495         {
496             pNewThread->DecExternalCount(FALSE);
497             COMPlusThrowOM();
498         }
499
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();
505
506         FastInterlockOr((ULONG *) &pNewThread->m_State, Thread::TS_LegalToJoin);
507
508         DWORD   ret;
509         ret = pNewThread->StartThread();
510
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 
519         // ret to equal 2.
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);
524
525         {
526             GCX_PREEMP();
527
528             // Synchronize with HasStarted.
529             YIELD_WHILE (!pNewThread->HasThreadState(Thread::TS_FailStarted) &&
530                    pNewThread->HasThreadState(Thread::TS_Unstarted));
531         }
532
533         if (!pNewThread->HasThreadState(Thread::TS_FailStarted))
534         {
535             share.SuppressRelease();       // we have handed off ownership of the shared struct
536         }
537         else
538         {
539             share.Release();
540             PulseAllHelper(pNewThread);
541             pNewThread->HandleThreadStartupFailure();
542         }
543     }
544     EX_CATCH
545     {
546         gc.pThis->LeaveObjMonitor();
547         EX_RETHROW;
548     }
549     EX_END_CATCH_UNREACHABLE;
550     
551     gc.pThis->LeaveObjMonitor();
552
553     GCPROTECT_END();
554 }
555
556 FCIMPL1(void, ThreadNative::Abort, ThreadBaseObject* pThis)
557 {
558     FCALL_CONTRACT;
559
560     if (pThis == NULL)
561         FCThrowVoid(kNullReferenceException);
562
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);
567
568     Thread *thread = thisRef->GetInternal();
569     if (thread == NULL)
570         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
571 #ifdef _DEBUG
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);
575     }
576     else
577 #endif
578         thread->UserAbort(Thread::TAR_Thread, EEPolicy::TA_V1Compatible, INFINITE, Thread::UAC_Normal);
579
580     if (thread->CatchAtSafePoint())
581         CommonTripThread();
582     HELPER_METHOD_FRAME_END_POLL();
583 }
584 FCIMPLEND
585
586 FCIMPL1(void, ThreadNative::ResetAbort, ThreadBaseObject* pThis)
587 {
588     FCALL_CONTRACT;
589
590     _ASSERTE(pThis);
591     VALIDATEOBJECT(pThis);
592
593     Thread *thread = pThis->GetInternal();
594     // We do not allow user to reset rude thread abort in MustRun code.
595     if (thread && thread->IsRudeAbort())
596     {
597         return;
598     }
599
600     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
601
602     if (thread == NULL)
603         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
604     thread->UserResetAbort(Thread::TAR_Thread);
605     thread->ClearAborted();
606     HELPER_METHOD_FRAME_END_POLL();
607 }
608 FCIMPLEND
609
610
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)
615 {
616     FCALL_CONTRACT;
617
618     if (pThisUNSAFE==NULL)
619         FCThrowRes(kNullReferenceException, W("NullReference_This"));
620
621     // validate the handle
622     if (ThreadIsDead(pThisUNSAFE->GetInternal()))
623         FCThrowEx(kThreadStateException, IDS_EE_THREAD_DEAD_PRIORITY, NULL, NULL, NULL);
624
625     return pThisUNSAFE->m_Priority;
626 }
627 FCIMPLEND
628
629 FCIMPL2(void, ThreadNative::SetPriority, ThreadBaseObject* pThisUNSAFE, INT32 iPriority)
630 {
631     FCALL_CONTRACT;
632
633     int     priority;
634     Thread *thread;
635
636     THREADBASEREF  pThis = (THREADBASEREF) pThisUNSAFE;
637     HELPER_METHOD_FRAME_BEGIN_1(pThis);
638
639     if (pThis==NULL)
640     {
641         COMPlusThrow(kNullReferenceException, W("NullReference_This"));
642     }
643
644     // translate the priority (validating as well)
645     priority = MapToNTPriority(iPriority);  // can throw; needs a frame
646
647     // validate the thread
648     thread = pThis->GetInternal();
649
650     if (ThreadIsDead(thread))
651     {
652         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_DEAD_PRIORITY, NULL, NULL, NULL);
653     }
654
655     INT32 oldPriority = pThis->m_Priority;
656
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;
660
661     if (!thread->SetThreadPriority(priority))
662     {
663         pThis->m_Priority = oldPriority;
664         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_PRIORITY_FAIL, NULL, NULL, NULL);
665     }
666
667     HELPER_METHOD_FRAME_END();
668 }
669 FCIMPLEND
670
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)
674 {
675     FCALL_CONTRACT;
676
677     if (pThisUNSAFE==NULL)
678         FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
679
680     Thread  *thread = pThisUNSAFE->GetInternal();
681
682     if (thread == 0)
683         FCThrowExVoid(kThreadStateException, IDS_EE_THREAD_CANNOT_GET, NULL, NULL, NULL);
684
685     HELPER_METHOD_FRAME_BEGIN_0();
686
687     thread->UserInterrupt(Thread::TI_Interrupt);
688
689     HELPER_METHOD_FRAME_END();
690 }
691 FCIMPLEND
692
693 FCIMPL1(FC_BOOL_RET, ThreadNative::IsAlive, ThreadBaseObject* pThisUNSAFE)
694 {
695     FCALL_CONTRACT;
696
697     if (pThisUNSAFE==NULL)
698         FCThrowRes(kNullReferenceException, W("NullReference_This"));
699
700     THREADBASEREF thisRef(pThisUNSAFE);
701     BOOL ret = false;
702
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);
709
710     Thread  *thread = thisRef->GetInternal();
711
712     if (thread == 0)
713         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
714
715     ret = ThreadIsRunning(thread);
716
717     HELPER_METHOD_POLL();
718     HELPER_METHOD_FRAME_END();
719
720     FC_RETURN_BOOL(ret);
721 }
722 FCIMPLEND
723
724 FCIMPL2(FC_BOOL_RET, ThreadNative::Join, ThreadBaseObject* pThisUNSAFE, INT32 Timeout)
725 {
726     FCALL_CONTRACT;
727
728     BOOL            retVal = FALSE;
729     THREADBASEREF   pThis   = (THREADBASEREF) pThisUNSAFE;
730
731     HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
732
733     if (pThis==NULL)
734         COMPlusThrow(kNullReferenceException, W("NullReference_This"));
735
736     // validate the timeout
737     if ((Timeout < 0) && (Timeout != INFINITE_TIMEOUT))
738         COMPlusThrowArgumentOutOfRange(W("millisecondsTimeout"), W("ArgumentOutOfRange_NeedNonNegOrNegative1"));
739
740     retVal = DoJoin(pThis, Timeout);
741
742     HELPER_METHOD_FRAME_END();
743
744     FC_RETURN_BOOL(retVal);
745 }
746 FCIMPLEND
747
748 #undef Sleep
749 FCIMPL1(void, ThreadNative::Sleep, INT32 iTime)
750 {
751     FCALL_CONTRACT;
752
753     HELPER_METHOD_FRAME_BEGIN_0();
754
755     // validate the sleep time
756     if ((iTime < 0) && (iTime != INFINITE_TIMEOUT))
757         COMPlusThrowArgumentOutOfRange(W("millisecondsTimeout"), W("ArgumentOutOfRange_NeedNonNegOrNegative1"));
758
759     while(true)
760     {
761         INT64 sPauseTime = g_PauseTime;
762         INT64 sTime = CLRGetTickCount64();
763         GetThread()->UserSleep(iTime);       
764         iTime = (INT32)AdditionalWait(sPauseTime, sTime, iTime);
765         if(iTime == 0)
766             break;
767     }
768
769     HELPER_METHOD_FRAME_END();
770 }
771 FCIMPLEND
772
773 #define Sleep(dwMilliseconds) Dont_Use_Sleep(dwMilliseconds)
774
775 FCIMPL1(INT32, ThreadNative::GetManagedThreadId, ThreadBaseObject* th) {
776     FCALL_CONTRACT;
777
778     FC_GC_POLL_NOT_NEEDED();
779     if (th == NULL)
780         FCThrow(kNullReferenceException);
781
782     return th->GetManagedThreadId();
783 }
784 FCIMPLEND
785
786 NOINLINE static Object* GetCurrentThreadHelper()
787 {
788     FCALL_CONTRACT;
789     FC_INNER_PROLOG(ThreadNative::GetCurrentThread);
790     OBJECTREF   refRetVal  = NULL;
791
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();
795
796     FC_INNER_EPILOG();
797     return OBJECTREFToObject(refRetVal);
798 }
799
800 FCIMPL0(Object*, ThreadNative::GetCurrentThread)
801 {
802     FCALL_CONTRACT;
803     OBJECTHANDLE ExposedObject = GetThread()->m_ExposedObject;
804     _ASSERTE(ExposedObject != 0); //Thread's constructor always initializes its GCHandle
805     Object* result = *((Object**) ExposedObject);
806     if (result != 0)
807         return result;
808
809     FC_INNER_RETURN(Object*, GetCurrentThreadHelper());
810 }
811 FCIMPLEND
812
813
814 FCIMPL3(void, ThreadNative::SetStart, ThreadBaseObject* pThisUNSAFE, Object* pDelegateUNSAFE, INT32 iRequestedStackSize)
815 {
816     FCALL_CONTRACT;
817
818     if (pThisUNSAFE==NULL)
819         FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
820
821     THREADBASEREF   pThis       = (THREADBASEREF) pThisUNSAFE;
822     OBJECTREF       pDelegate   = (OBJECTREF    ) pDelegateUNSAFE;
823
824     HELPER_METHOD_FRAME_BEGIN_2(pThis, pDelegate);
825
826     _ASSERTE(pThis != NULL);
827     _ASSERTE(pDelegate != NULL); // Thread's constructor validates this
828
829     if (pThis->m_InternalThread == NULL)
830     {
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();
834
835         PREFIX_ASSUME(unstarted != NULL);
836
837         if (GetThread()->GetDomain()->IgnoreUnhandledExceptions())
838         {
839             unstarted->SetThreadStateNC(Thread::TSNC_IgnoreUnhandledExceptions);
840         }
841
842         pThis->SetInternal(unstarted);
843         pThis->SetManagedThreadId(unstarted->GetThreadId());
844         unstarted->SetExposedObject(pThis);
845         unstarted->RequestedThreadStackSize(iRequestedStackSize);
846     }
847
848     // save off the delegate
849     pThis->SetDelegate(pDelegate);
850
851     HELPER_METHOD_FRAME_END();
852 }
853 FCIMPLEND
854
855
856 // Set whether or not this is a background thread.
857 FCIMPL2(void, ThreadNative::SetBackground, ThreadBaseObject* pThisUNSAFE, CLR_BOOL isBackground)
858 {
859     FCALL_CONTRACT;
860
861     if (pThisUNSAFE==NULL)
862         FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
863
864     // validate the thread
865     Thread  *thread = pThisUNSAFE->GetInternal();
866
867     if (ThreadIsDead(thread))
868         FCThrowExVoid(kThreadStateException, IDS_EE_THREAD_DEAD_STATE, NULL, NULL, NULL);
869
870     HELPER_METHOD_FRAME_BEGIN_0();
871
872     thread->SetBackground(isBackground);
873
874     HELPER_METHOD_FRAME_END();
875 }
876 FCIMPLEND
877
878 // Return whether or not this is a background thread.
879 FCIMPL1(FC_BOOL_RET, ThreadNative::IsBackground, ThreadBaseObject* pThisUNSAFE)
880 {
881     FCALL_CONTRACT;
882
883     if (pThisUNSAFE==NULL)
884         FCThrowRes(kNullReferenceException, W("NullReference_This"));
885
886     // validate the thread
887     Thread  *thread = pThisUNSAFE->GetInternal();
888
889     if (ThreadIsDead(thread))
890         FCThrowEx(kThreadStateException, IDS_EE_THREAD_DEAD_STATE, NULL, NULL, NULL);
891
892     FC_RETURN_BOOL(thread->IsBackground());
893 }
894 FCIMPLEND
895
896
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)
902 {
903     FCALL_CONTRACT;
904
905     INT32               res = 0;
906     Thread::ThreadState state;
907
908     if (pThisUNSAFE==NULL)
909         FCThrowRes(kNullReferenceException, W("NullReference_This"));
910
911     // validate the thread.  Failure here implies that the thread was finalized
912     // and then resurrected.
913     Thread  *thread = pThisUNSAFE->GetInternal();
914
915     if (!thread)
916         FCThrowEx(kThreadStateException, IDS_EE_THREAD_CANNOT_GET, NULL, NULL, NULL);
917
918     HELPER_METHOD_FRAME_BEGIN_RET_0();
919
920     // grab a snapshot
921     state = thread->GetSnapshotState();
922
923     if (state & Thread::TS_Background)
924         res |= ThreadBackground;
925
926     if (state & Thread::TS_Unstarted)
927         res |= ThreadUnstarted;
928
929     // Don't report a StopRequested if the thread has actually stopped.
930     if (state & Thread::TS_Dead)
931     {
932         if (state & Thread::TS_Aborted)
933             res |= ThreadAborted;
934         else
935             res |= ThreadStopped;
936     }
937     else
938     {
939         if (state & Thread::TS_AbortRequested)
940             res |= ThreadAbortRequested;
941     }
942
943     if (state & Thread::TS_Interruptible)
944         res |= ThreadWaitSleepJoin;
945
946     // Don't report a SuspendRequested if the thread has actually Suspended.
947     if ((state & Thread::TS_UserSuspendPending) &&
948         (state & Thread::TS_SyncSuspended)
949        )
950     {
951         res |= ThreadSuspended;
952     }
953     else
954     if (state & Thread::TS_UserSuspendPending)
955     {
956         res |= ThreadSuspendRequested;
957     }
958
959     HELPER_METHOD_POLL();
960     HELPER_METHOD_FRAME_END();
961
962     return res;
963 }
964 FCIMPLEND
965
966 #ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
967
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)
972 {
973     FCALL_CONTRACT;
974
975     if (pThisUNSAFE==NULL)
976         FCThrowRes(kNullReferenceException, W("NullReference_This"));
977
978     INT32           retVal  = ApartmentUnknown;
979     BOOL    ok = TRUE;
980     THREADBASEREF   pThis   = (THREADBASEREF) pThisUNSAFE;
981
982     HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
983
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;
994     else
995         COMPlusThrow(kArgumentOutOfRangeException, W("ArgumentOutOfRange_Enum"));
996
997     Thread  *thread = pThis->GetInternal();
998     if (!thread)
999         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1000
1001     {
1002         pThis->EnterObjMonitor();
1003
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
1006         // context.
1007         if ((!ThreadNotStarted(thread) && !ThreadIsRunning(thread)) ||
1008             (!ThreadNotStarted(thread) && (GetThread() != thread)))
1009             ok = FALSE;
1010         else
1011         {
1012             EX_TRY
1013             {
1014                 state = thread->SetApartment(state, fireMDAOnMismatch == TRUE);
1015             }
1016             EX_CATCH
1017             {
1018                 pThis->LeaveObjMonitor();
1019                 EX_RETHROW;
1020             }
1021             EX_END_CATCH_UNREACHABLE;
1022         }
1023
1024         pThis->LeaveObjMonitor();
1025     }
1026
1027
1028     // Now it's safe to throw exceptions again.
1029     if (!ok)
1030         COMPlusThrow(kThreadStateException);
1031
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;
1039     else
1040         _ASSERTE(!"Invalid state returned from SetApartment");
1041
1042     HELPER_METHOD_FRAME_END();
1043
1044     return retVal;
1045 }
1046 FCIMPLEND
1047
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)
1051 {
1052     FCALL_CONTRACT;
1053
1054     INT32 retVal = 0;
1055
1056     THREADBASEREF refThis = (THREADBASEREF) ObjectToOBJECTREF(pThisUNSAFE);
1057
1058     HELPER_METHOD_FRAME_BEGIN_RET_1(refThis);
1059
1060     if (refThis == NULL)
1061     {
1062         COMPlusThrow(kNullReferenceException, W("NullReference_This"));
1063     }
1064
1065     Thread* thread = refThis->GetInternal();
1066
1067     if (ThreadIsDead(thread))
1068     {
1069         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_DEAD_STATE);
1070     }
1071
1072     Thread::ApartmentState state = thread->GetApartment();
1073
1074 #ifdef FEATURE_COMINTEROP
1075     if (state == Thread::AS_Unknown)
1076     {
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.
1080         if (!g_fComStarted)
1081         {
1082             EnsureComStarted();
1083             state = thread->GetApartment();
1084         }
1085     }
1086 #endif // FEATURE_COMINTEROP
1087
1088     // Translate state into external form
1089     retVal = ApartmentUnknown;
1090     if (state == Thread::AS_InSTA)
1091     {
1092         retVal = ApartmentSTA;
1093     }
1094     else if (state == Thread::AS_InMTA)
1095     {
1096         retVal = ApartmentMTA;
1097     }
1098     else if (state == Thread::AS_Unknown)
1099     {
1100         retVal = ApartmentUnknown;
1101     }
1102     else
1103     {
1104         _ASSERTE(!"Invalid state returned from GetApartment");
1105     }
1106
1107     HELPER_METHOD_FRAME_END();
1108
1109     return retVal;
1110 }
1111 FCIMPLEND
1112
1113
1114 // Attempt to eagerly set the apartment state during thread startup.
1115 FCIMPL1(void, ThreadNative::StartupSetApartmentState, ThreadBaseObject* pThisUNSAFE)
1116 {
1117     FCALL_CONTRACT;
1118
1119     THREADBASEREF refThis = (THREADBASEREF) ObjectToOBJECTREF(pThisUNSAFE);
1120
1121     HELPER_METHOD_FRAME_BEGIN_1(refThis);
1122
1123     if (refThis == NULL)
1124     {
1125         COMPlusThrow(kNullReferenceException, W("NullReference_This"));
1126     }
1127
1128     Thread* thread = refThis->GetInternal();
1129
1130     if (!ThreadNotStarted(thread))
1131         COMPlusThrow(kThreadStateException, IDS_EE_THREADSTART_STATE);
1132
1133     // Assert that the thread hasn't been started yet.
1134     _ASSERTE(Thread::TS_Unstarted & thread->GetSnapshotState());
1135
1136     if ((g_pConfig != NULL) && !g_pConfig->LegacyApartmentInitPolicy())
1137     {
1138         Thread::ApartmentState as = thread->GetExplicitApartment();
1139         if (as == Thread::AS_Unknown)
1140         {
1141             thread->SetApartment(Thread::AS_InMTA, TRUE);
1142         }
1143     }
1144
1145     HELPER_METHOD_FRAME_END();
1146 }
1147 FCIMPLEND
1148
1149 #endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
1150
1151 void ReleaseThreadExternalCount(Thread * pThread)
1152 {
1153     WRAPPER_NO_CONTRACT;
1154     pThread->DecExternalCount(FALSE);
1155 }
1156
1157 typedef Holder<Thread *, DoNothing, ReleaseThreadExternalCount> ThreadExternalCountHolder;
1158
1159 // Wait for the thread to die
1160 BOOL ThreadNative::DoJoin(THREADBASEREF DyingThread, INT32 timeout)
1161 {
1162     CONTRACTL
1163     {
1164         THROWS;
1165         GC_TRIGGERS;
1166         MODE_COOPERATIVE;
1167         PRECONDITION(DyingThread != NULL);
1168         PRECONDITION((timeout >= 0) || (timeout == INFINITE_TIMEOUT));
1169     }
1170     CONTRACTL_END;
1171
1172     Thread * DyingInternal = DyingThread->GetInternal();
1173
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))
1178     {
1179         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_NOTSTARTED);
1180     }
1181
1182     // Don't grab the handle until we know it has started, to eliminate the race
1183     // condition.
1184     if (ThreadIsDead(DyingInternal) || !DyingInternal->HasValidThreadHandle())
1185         return TRUE;
1186
1187     DWORD dwTimeOut32 = (timeout == INFINITE_TIMEOUT
1188                    ? INFINITE
1189                    : (DWORD) timeout);
1190
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();
1195     if (RefCount == 1)
1196     {
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());
1202         return TRUE;
1203     }
1204
1205     ThreadExternalCountHolder dyingInternalHolder(DyingInternal);
1206
1207     if (!DyingInternal->HasValidThreadHandle())
1208     {
1209         return TRUE;
1210     }
1211
1212     GCX_PREEMP();
1213     DWORD rv = DyingInternal->JoinEx(dwTimeOut32, (WaitMode)(WaitMode_Alertable/*alertable*/|WaitMode_InDeadlock));
1214
1215     switch(rv)
1216     {
1217         case WAIT_OBJECT_0:
1218             return TRUE;
1219
1220         case WAIT_TIMEOUT:
1221             break;
1222
1223         case WAIT_FAILED:
1224             if(!DyingInternal->HasValidThreadHandle())
1225                 return TRUE;
1226             break;
1227             
1228         default:
1229             _ASSERTE(!"This return code is not understood \n");
1230             break;
1231     }    
1232
1233     return FALSE;
1234 }
1235
1236
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)
1243 {
1244     CONTRACTL
1245     {
1246         GC_TRIGGERS;
1247         THROWS;
1248         MODE_COOPERATIVE;
1249     }
1250     CONTRACTL_END;
1251
1252 #ifdef APPDOMAIN_STATE
1253     if (delegate != NULL)
1254     {
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());
1260     }
1261 #endif
1262
1263     SetObjectReferenceUnchecked( (OBJECTREF *)&m_Delegate, delegate );
1264
1265     // If the delegate is being set then initialize the other data members.
1266     if (m_Delegate != NULL)
1267     {
1268         // Initialize the thread priority to normal.
1269         m_Priority = ThreadNative::PRIORITY_NORMAL;
1270     }
1271 }
1272
1273
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()
1277 {
1278     CONTRACTL
1279     {
1280         GC_NOTRIGGER;
1281         NOTHROW;
1282         MODE_COOPERATIVE;
1283     }
1284     CONTRACTL_END;
1285
1286     Thread *pThread = GetInternal();
1287     _ASSERTE (pThread);
1288     switch (pThread->GetThreadPriority())
1289     {
1290     case THREAD_PRIORITY_LOWEST:
1291     case THREAD_PRIORITY_IDLE:
1292         m_Priority = ThreadNative::PRIORITY_LOWEST;
1293         break;
1294
1295     case THREAD_PRIORITY_BELOW_NORMAL:
1296         m_Priority = ThreadNative::PRIORITY_BELOW_NORMAL;
1297         break;
1298
1299     case THREAD_PRIORITY_NORMAL:
1300         m_Priority = ThreadNative::PRIORITY_NORMAL;
1301         break;
1302
1303     case THREAD_PRIORITY_ABOVE_NORMAL:
1304         m_Priority = ThreadNative::PRIORITY_ABOVE_NORMAL;
1305         break;
1306
1307     case THREAD_PRIORITY_HIGHEST:
1308     case THREAD_PRIORITY_TIME_CRITICAL:
1309         m_Priority = ThreadNative::PRIORITY_HIGHEST;
1310         break;
1311
1312     case THREAD_PRIORITY_ERROR_RETURN:
1313         _ASSERTE(FALSE);
1314         m_Priority = ThreadNative::PRIORITY_NORMAL;
1315         break;
1316
1317     default:
1318         m_Priority = ThreadNative::PRIORITY_NORMAL;
1319         break;
1320     }
1321
1322 }
1323
1324 #ifndef FEATURE_LEAK_CULTURE_INFO
1325 OBJECTREF ThreadBaseObject::GetManagedThreadCulture(BOOL bUICulture)
1326 {
1327     CONTRACTL {
1328         GC_NOTRIGGER;
1329         NOTHROW;
1330         MODE_COOPERATIVE;
1331     }
1332     CONTRACTL_END;
1333
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) {
1337         return NULL;
1338     }
1339
1340     OBJECTREF *pCurrentCulture = NULL;
1341     Thread    *pThread = GetInternal();
1342     FieldDesc *pFD = NULL;
1343
1344     if (bUICulture)
1345     {
1346         pFD = pThread->managedThreadCurrentUICulture;
1347     }
1348     else
1349     {
1350         pFD = pThread->managedThreadCurrentCulture;
1351     }
1352
1353     if (pFD != NULL)
1354     {
1355         pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD, NULL);
1356         if (pCurrentCulture)
1357         {
1358             return *pCurrentCulture;
1359         }
1360     }
1361
1362     return NULL;
1363 }
1364
1365 CULTUREINFOBASEREF ThreadBaseObject::GetCurrentUserCulture()
1366 {
1367     WRAPPER_NO_CONTRACT;
1368
1369     return (CULTUREINFOBASEREF)GetManagedThreadCulture(false);
1370 }
1371
1372 CULTUREINFOBASEREF ThreadBaseObject::GetCurrentUICulture()
1373 {
1374     WRAPPER_NO_CONTRACT;
1375
1376     return (CULTUREINFOBASEREF)GetManagedThreadCulture(true);
1377 }
1378
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 
1384 // CoreCLR anyway.
1385 void ThreadBaseObject::ResetCurrentUserCulture()
1386 {
1387     WRAPPER_NO_CONTRACT;
1388     ResetManagedThreadCulture(false);
1389 }
1390
1391 void ThreadBaseObject::ResetCurrentUICulture()
1392 {
1393     WRAPPER_NO_CONTRACT;
1394     ResetManagedThreadCulture(true);
1395 }
1396
1397 void ThreadBaseObject::ResetManagedThreadCulture(BOOL bUICulture)
1398 {
1399     CONTRACTL
1400     {
1401         GC_NOTRIGGER;
1402         NOTHROW;
1403         MODE_COOPERATIVE;
1404         SO_TOLERANT;
1405     }
1406     CONTRACTL_END;
1407
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) {
1411         return;
1412     }
1413     
1414     Thread    *pThread = GetInternal();
1415     FieldDesc *pFD = NULL;
1416
1417     if (bUICulture)
1418     {
1419         pFD = pThread->managedThreadCurrentUICulture;
1420     }
1421     else
1422     {
1423         pFD = pThread->managedThreadCurrentCulture;
1424     }
1425
1426     if (pFD != NULL)
1427     {
1428         OBJECTREF *pCulture = NULL;
1429         BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(COMPlusThrowSO());
1430         pCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD, NULL);
1431         if (pCulture) 
1432         {
1433             SetObjectReferenceUnchecked(pCulture, NULL);
1434         }
1435         END_SO_INTOLERANT_CODE;
1436
1437     }
1438 }
1439
1440 #endif // FEATURE_LEAK_CULTURE_INFO
1441
1442
1443 FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE)
1444 {
1445     FCALL_CONTRACT;
1446
1447     // This function is intentionally blank.
1448     // See comment in code:MethodTable::CallFinalizer.
1449
1450     _ASSERTE (!"Should not be called");
1451
1452     FCUnique(0x21);
1453 }
1454 FCIMPLEND
1455
1456 #ifdef FEATURE_COMINTEROP
1457 FCIMPL1(void, ThreadNative::DisableComObjectEagerCleanup, ThreadBaseObject* pThisUNSAFE)
1458 {
1459     FCALL_CONTRACT;
1460
1461     _ASSERTE(pThisUNSAFE != NULL);
1462     VALIDATEOBJECT(pThisUNSAFE);
1463     Thread *pThread = pThisUNSAFE->GetInternal();
1464
1465     HELPER_METHOD_FRAME_BEGIN_0();
1466
1467     if (pThread == NULL)
1468         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1469
1470     pThread->SetDisableComObjectEagerCleanup();
1471
1472     HELPER_METHOD_FRAME_END();
1473 }
1474 FCIMPLEND
1475 #endif //FEATURE_COMINTEROP
1476
1477 #ifdef FEATURE_LEAK_CULTURE_INFO
1478 FCIMPL1(FC_BOOL_RET, ThreadNative::SetThreadUILocale, StringObject* localeNameUNSAFE)
1479 {
1480     FCALL_CONTRACT;
1481
1482     BOOL result = TRUE;
1483
1484     STRINGREF name = (STRINGREF) localeNameUNSAFE;
1485     VALIDATEOBJECTREF(name);
1486
1487     HELPER_METHOD_FRAME_BEGIN_RET_0();
1488     
1489     LCID lcid=NewApis::LocaleNameToLCID(name->GetBuffer(),0);
1490     if (lcid == 0)
1491     {
1492         ThrowHR(HRESULT_FROM_WIN32(GetLastError()));
1493     }
1494
1495 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
1496     IHostTaskManager *manager = CorHost2::GetHostTaskManager();
1497     if (manager) {
1498         BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread());
1499         result = (manager->SetUILocale(lcid) == S_OK);
1500         END_SO_TOLERANT_CODE_CALLING_HOST;
1501     }
1502 #endif  // FEATURE_INCLUDE_ALL_INTERFACES
1503
1504     HELPER_METHOD_FRAME_END();
1505    
1506     FC_RETURN_BOOL(result);
1507 }
1508 FCIMPLEND
1509 #endif // FEATURE_LEAK_CULTURE_INFO
1510
1511 FCIMPL0(Object*, ThreadNative::GetDomain)
1512 {
1513     FCALL_CONTRACT;
1514
1515     APPDOMAINREF refRetVal = NULL;
1516
1517     Thread* thread = GetThread();
1518
1519     if ((thread) && (thread->GetDomain()))
1520     {
1521         HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal);
1522         refRetVal = (APPDOMAINREF) thread->GetDomain()->GetExposedObject();
1523         HELPER_METHOD_FRAME_END();
1524     }
1525
1526     return OBJECTREFToObject(refRetVal);
1527 }
1528 FCIMPLEND
1529
1530 #if defined(_TARGET_X86_) && defined(_MSC_VER)
1531 __declspec(naked) LPVOID __fastcall ThreadNative::FastGetDomain()
1532 {
1533     STATIC_CONTRACT_MODE_COOPERATIVE;
1534     STATIC_CONTRACT_GC_NOTRIGGER;
1535     STATIC_CONTRACT_NOTHROW;
1536     STATIC_CONTRACT_SO_TOLERANT;
1537
1538     __asm {
1539         call GetAppDomain
1540         test eax, eax
1541         je done
1542         mov eax, dword ptr [eax]AppDomain.m_ExposedObject
1543         test eax, eax
1544         je done
1545         mov eax, dword ptr [eax]
1546 done:
1547         ret
1548     }
1549 }
1550 #else // _TARGET_X86_ && _MSC_VER
1551 LPVOID F_CALL_CONV ThreadNative::FastGetDomain()
1552 {
1553     CONTRACTL
1554     {
1555         GC_NOTRIGGER;
1556         NOTHROW;
1557         MODE_COOPERATIVE;
1558         SO_TOLERANT;
1559     }
1560     CONTRACTL_END;
1561
1562     Thread *pThread;
1563     AppDomain *pDomain;
1564     OBJECTHANDLE ExposedObject;
1565
1566     pDomain = GetAppDomain();
1567     if (!pDomain) {
1568         return NULL;
1569     }
1570     ExposedObject = pDomain->m_ExposedObject;
1571     if (ExposedObject) {
1572         return *(LPVOID *)ExposedObject;
1573     }
1574     return NULL;
1575 }
1576 #endif // _TARGET_X86_ && _MSC_VER
1577
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)
1582 {
1583     FCALL_CONTRACT;
1584
1585     OBJECTREF   rv   = NULL;
1586     Context*    pCtx = (Context *) ContextID;
1587     // Get the managed context backing this unmanaged context
1588     rv = pCtx->GetExposedObjectRaw();
1589
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));
1595
1596     return OBJECTREFToObject(rv);
1597 }
1598 FCIMPLEND
1599
1600
1601 FCIMPL6(Object*, ThreadNative::InternalCrossContextCallback, ThreadBaseObject* refThis, ContextBaseObject* refContext, LPVOID contextID, INT32 appDomainId, Object* oDelegateUNSAFE, PtrArray* oArgsUNSAFE)
1602 {
1603     FCALL_CONTRACT;
1604
1605     _ASSERTE(refThis != NULL);
1606     VALIDATEOBJECT(refThis);
1607     Thread *pThread = refThis->GetInternal();
1608     Context *pCtx = (Context *)contextID;
1609
1610
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
1615
1616     // Set the VM conext
1617
1618     struct _gc {
1619         OBJECTREF oRetVal;
1620         OBJECTREF oDelegate;
1621         OBJECTREF oArgs;
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
1624         OBJECTREF oContext;
1625     } gc;
1626
1627     gc.oRetVal   = NULL;
1628     gc.oDelegate = ObjectToOBJECTREF(oDelegateUNSAFE);
1629     gc.oArgs     = ObjectToOBJECTREF(oArgsUNSAFE);
1630     gc.oContext  = ObjectToOBJECTREF(refContext);
1631
1632     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1633
1634     if (pThread == NULL)
1635         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1636
1637 #ifdef _DEBUG
1638     MethodDesc* pTargetMD = COMDelegate::GetMethodDesc(gc.oDelegate);
1639     _ASSERTE(pTargetMD->IsStatic());
1640 #endif
1641
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);
1645
1646     AppDomainFromIDHolder ad;
1647     if (appDomainId != 0)
1648     {
1649         //
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.
1652         //
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.
1656         //
1657         {
1658             ad.Assign(ADID(appDomainId), TRUE); 
1659             
1660             if (ad.IsUnloaded() || !ad->CanThreadEnter(pThread))
1661                 COMPlusThrow(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded"));
1662         }
1663     }
1664
1665     // Verify that the Context is valid.
1666     if ( !Context::ValidateContext(pCtx) )
1667         COMPlusThrow(kRemotingException, W("Remoting_InvalidContext"));
1668
1669     DEBUG_ASSURE_NO_RETURN_BEGIN(COMSYNCH)
1670
1671     FrameWithCookie<ContextTransitionFrame>  frame;
1672
1673     Context*    pCurrContext    = pThread->GetContext();
1674     bool        fTransition     = (pCurrContext != pCtx);
1675     BOOL        fSameDomain     = (appDomainId==0) || (pCurrContext->GetDomain()->GetId() == (ADID)appDomainId);
1676     _ASSERTE( fTransition || fSameDomain);
1677     if (fTransition) 
1678         if (appDomainId!=0)
1679             ad->EnterContext(pThread,pCtx, &frame);
1680         else
1681             pThread->EnterContextRestricted(pCtx,&frame);
1682     ad.Release();
1683
1684
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"));
1689
1690     Exception* pOriginalException=NULL;
1691         
1692     EX_TRY
1693     {
1694         DECLARE_ARGHOLDER_ARRAY(callArgs, 2);
1695
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();
1701 #endif
1702         callArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.oDelegate);
1703         callArgs[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.oArgs);
1704
1705         CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
1706         CALL_MANAGED_METHOD_RETREF(gc.oRetVal, OBJECTREF, callArgs);
1707     }
1708     EX_CATCH
1709     {
1710         LOG((LF_EH, LL_INFO100, "MSCORLIB_CONTEXT_TRANSITION(     %s::%s ): exception in flight\n", pTargetMD->m_pszDebugClassName, pTargetMD->m_pszDebugMethodName));
1711
1712         if (!fTransition || fSameDomain)
1713         {
1714             if (fTransition)
1715             {
1716                 GCX_FORBID();
1717                 pThread->ReturnToContext(&frame);
1718             }
1719 #ifdef FEATURE_TESTHOOKS
1720             if (appDomainId!=0)
1721             {
1722                 TESTHOOKCALL(LeftAppDomain(appDomainId));
1723             }
1724 #endif
1725             EX_RETHROW;
1726         }
1727
1728         pOriginalException=EXTRACT_EXCEPTION();
1729         CAPTURE_BUCKETS_AT_TRANSITION(pThread, CLRException::GetThrowableFromException(pOriginalException));
1730         goto lAfterCtxUnwind;
1731     }
1732     EX_END_CATCH_UNREACHABLE;
1733     if (0)
1734     {
1735 lAfterCtxUnwind:
1736         LOG((LF_EH, LL_INFO100, "MSCORLIB_RaiseCrossContextException( %s::%s )\n", pTargetMD->m_pszDebugClassName, pTargetMD->m_pszDebugMethodName));
1737         pThread->RaiseCrossContextException(pOriginalException,&frame);
1738     }
1739
1740     LOG((LF_EH, LL_INFO100, "MSCORLIB_LEAVE_CONTEXT_TRANSITION( %s::%s )\n", pTargetMD->m_pszDebugClassName, pTargetMD->m_pszDebugMethodName));
1741
1742     if (fTransition)
1743     {
1744         GCX_FORBID();
1745         pThread->ReturnToContext(&frame);
1746     }
1747 #ifdef FEATURE_TESTHOOKS
1748     if(appDomainId!=0)
1749     {
1750         TESTHOOKCALL(LeftAppDomain(appDomainId));
1751     }
1752 #endif
1753
1754     DEBUG_ASSURE_NO_RETURN_END(COMSYNCH)
1755
1756     HELPER_METHOD_FRAME_END();
1757     return OBJECTREFToObject(gc.oRetVal);
1758 }
1759 FCIMPLEND
1760 #endif //FEATURE_REMOTING
1761
1762 //
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.
1771 //
1772 #ifdef FEATURE_LEAK_CULTURE_INFO
1773 FCIMPL4(FC_BOOL_RET, ThreadNative::nativeGetSafeCulture, 
1774         ThreadBaseObject*   threadUNSAFE, 
1775         int                 appDomainId, 
1776         CLR_BOOL            isUI, 
1777         OBJECTREF*          safeCulture)
1778 {
1779     FCALL_CONTRACT;
1780
1781     THREADBASEREF thread(threadUNSAFE);
1782
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());
1787         } else {
1788             FC_RETURN_BOOL(FALSE);
1789         }
1790     }
1791     FC_RETURN_BOOL(TRUE);
1792 }
1793 FCIMPLEND
1794 #endif // FEATURE_LEAK_CULTURE_INFO
1795
1796 #ifndef FEATURE_LEAK_CULTURE_INFO
1797 void QCALLTYPE ThreadNative::nativeInitCultureAccessors()
1798 {
1799     QCALL_CONTRACT;
1800
1801     BEGIN_QCALL;
1802
1803     Thread* pThread = GetThread();
1804     pThread->InitCultureAccessors();
1805
1806     END_QCALL;
1807 }
1808 #endif // FEATURE_LEAK_CULTURE_INFO
1809
1810
1811 void QCALLTYPE ThreadNative::InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len)
1812 {
1813     QCALL_CONTRACT;
1814
1815     BEGIN_QCALL;
1816
1817     Thread* pThread = &(*thread);
1818
1819 #ifdef PROFILING_SUPPORTED
1820     {
1821         BEGIN_PIN_PROFILER(CORProfilerTrackThreads());
1822         if (name == NULL)
1823         {
1824             g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, 0, NULL);
1825         }
1826         else
1827         {
1828             g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, len, (WCHAR*)name);
1829         }
1830         END_PIN_PROFILER();
1831     }
1832 #endif // PROFILING_SUPPORTED
1833
1834
1835 #ifdef DEBUGGING_SUPPORTED
1836     if (CORDebuggerAttached())
1837     {
1838         _ASSERTE(NULL != g_pDebugInterface);
1839         g_pDebugInterface->NameChangeEvent(NULL, pThread);
1840     }
1841 #endif // DEBUGGING_SUPPORTED
1842
1843     END_QCALL;
1844 }
1845
1846 UINT64 QCALLTYPE ThreadNative::GetProcessDefaultStackSize()
1847 {
1848     QCALL_CONTRACT;
1849
1850     SIZE_T reserve = 0;
1851     SIZE_T commit = 0;
1852
1853     BEGIN_QCALL;
1854
1855     if (!Thread::GetProcessDefaultStackSize(&reserve, &commit))
1856         reserve = 1024 * 1024;
1857
1858     END_QCALL;
1859
1860     return (UINT64)reserve;
1861 }
1862
1863
1864
1865 FCIMPL1(FC_BOOL_RET, ThreadNative::IsThreadpoolThread, ThreadBaseObject* thread)
1866 {
1867     FCALL_CONTRACT;
1868
1869     if (thread==NULL)
1870         FCThrowRes(kNullReferenceException, W("NullReference_This"));
1871
1872     Thread *pThread = thread->GetInternal();
1873
1874     if (pThread == NULL)
1875         FCThrowEx(kThreadStateException, IDS_EE_THREAD_DEAD_STATE, NULL, NULL, NULL);
1876
1877     BOOL ret = pThread->IsThreadPoolThread();
1878
1879     FC_GC_POLL_RET();
1880
1881     FC_RETURN_BOOL(ret);
1882 }
1883 FCIMPLEND
1884
1885
1886 FCIMPL1(void, ThreadNative::SpinWait, int iterations)
1887 {
1888     FCALL_CONTRACT;
1889
1890     //
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 
1895     // on my machine.
1896     //
1897     if (iterations <= 1000000)
1898     {
1899         for(int i = 0; i < iterations; i++)
1900             YieldProcessor();
1901         return;
1902     }
1903
1904     //
1905     // Too many iterations; better switch to preemptive mode to avoid stalling a GC.
1906     //
1907     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
1908     GCX_PREEMP();
1909
1910     for(int i = 0; i < iterations; i++)
1911         YieldProcessor();
1912
1913     HELPER_METHOD_FRAME_END();
1914 }
1915 FCIMPLEND
1916
1917 BOOL QCALLTYPE ThreadNative::YieldThread()
1918 {
1919     QCALL_CONTRACT;
1920
1921     BOOL ret = FALSE;
1922
1923     BEGIN_QCALL
1924
1925     ret = __SwitchToThread(0, CALLER_LIMITS_SPINNING);
1926
1927     END_QCALL
1928
1929     return ret;
1930 }
1931
1932 #ifdef FEATURE_COMPRESSEDSTACK
1933 FCIMPL2(void*, ThreadNative::SetAppDomainStack, ThreadBaseObject* pThis, SafeHandle* hcsUNSAFE)
1934 {
1935     FCALL_CONTRACT;
1936
1937     void* pRet = NULL;
1938     SAFEHANDLE hcsSAFE = (SAFEHANDLE) hcsUNSAFE;
1939     HELPER_METHOD_FRAME_BEGIN_RET_1(hcsSAFE);
1940
1941
1942     void* unmanagedCompressedStack = NULL;
1943     if (hcsSAFE != NULL)
1944     {
1945         unmanagedCompressedStack = (void *)hcsSAFE->GetHandle();
1946     }
1947
1948
1949     VALIDATEOBJECT(pThis);
1950     Thread *pThread = pThis->GetInternal();
1951     if (pThread == NULL)
1952         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1953
1954     pRet = StackCompressor::SetAppDomainStack(pThread, unmanagedCompressedStack);
1955     HELPER_METHOD_FRAME_END_POLL();
1956     return pRet;
1957 }
1958 FCIMPLEND
1959
1960
1961 FCIMPL2(void, ThreadNative::RestoreAppDomainStack, ThreadBaseObject* pThis, void* appDomainStack)
1962 {
1963     FCALL_CONTRACT;
1964
1965     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
1966
1967     VALIDATEOBJECT(pThis);
1968     Thread *pThread = pThis->GetInternal();
1969     if (pThread == NULL)
1970         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
1971
1972     StackCompressor::RestoreAppDomainStack(pThread, appDomainStack);
1973     HELPER_METHOD_FRAME_END_POLL();
1974 }
1975 FCIMPLEND
1976 #endif //#ifdef FEATURE_COMPRESSEDSTACK
1977
1978 FCIMPL0(void, ThreadNative::FCMemoryBarrier)
1979 {
1980     FCALL_CONTRACT;
1981
1982     MemoryBarrier();
1983     FC_GC_POLL();
1984 }
1985 FCIMPLEND
1986
1987 FCIMPL2(void, ThreadNative::SetAbortReason, ThreadBaseObject* pThisUNSAFE, Object* pObject)
1988 {
1989     FCALL_CONTRACT;
1990
1991     if (pThisUNSAFE==NULL)
1992         FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
1993
1994     OBJECTREF refObject = static_cast<OBJECTREF>(pObject);
1995
1996     Thread *pThread = pThisUNSAFE->GetInternal();
1997
1998     // If the OBJECTHANDLE is not 0, already set so just return
1999     if (pThread != NULL && pThread->m_AbortReason != 0)
2000         return;
2001
2002     // Set up a frame in case of GC or EH
2003     HELPER_METHOD_FRAME_BEGIN_1(refObject)
2004
2005     if (pThread == NULL)
2006         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
2007
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();
2012
2013     // Create a OBJECTHANDLE for the object.
2014     OBJECTHANDLE oh = pCurrentDomain->CreateHandle(refObject);
2015
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)
2022         {
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.
2026             oh = 0;
2027         }
2028     }
2029
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.
2033     if (oh != 0)
2034     {
2035         DestroyHandle(oh);
2036     }
2037
2038     HELPER_METHOD_FRAME_END()
2039
2040 }
2041 FCIMPLEND
2042
2043
2044 FCIMPL1(void, ThreadNative::ClearAbortReason, ThreadBaseObject* pThisUNSAFE)
2045 {
2046     FCALL_CONTRACT;
2047
2048     if (pThisUNSAFE==NULL)
2049         FCThrowResVoid(kNullReferenceException, W("NullReference_This"));
2050
2051     Thread *pThread = pThisUNSAFE->GetInternal();
2052
2053     // Clearing from managed code can only happen on the current thread.
2054     _ASSERTE(pThread == GetThread());
2055
2056     HELPER_METHOD_FRAME_BEGIN_0();
2057
2058     if (pThread == NULL)
2059         COMPlusThrow(kThreadStateException, IDS_EE_THREAD_CANNOT_GET);
2060
2061     pThread->ClearAbortReason();
2062
2063     HELPER_METHOD_FRAME_END();
2064
2065 }
2066 FCIMPLEND
2067
2068