Skip to content

Commit 92783de

Browse files
jkotassirntar
authored andcommitted
Misc cleanup of VM threading code (dotnet#108171)
- Delete special-casing of thread finalizer - Factor out Get/SetApartment of unstarted threads - Delete some dead code - Fix comments
1 parent 9729425 commit 92783de

File tree

11 files changed

+83
-194
lines changed

11 files changed

+83
-194
lines changed

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,7 @@ public ThreadPriority Priority
240240
{
241241
Thread _this = this;
242242
SetPriority(ObjectHandleOnStack.Create(ref _this), (int)value);
243-
if (value != ThreadPriority.Normal)
244-
{
245-
_mayNeedResetForThreadPool = true;
246-
}
243+
_mayNeedResetForThreadPool = true;
247244
}
248245
}
249246

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs

+1-20
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ namespace System.Threading
1414
{
1515
public sealed partial class Thread
1616
{
17-
[ThreadStatic]
18-
private static int t_reentrantWaitSuppressionCount;
19-
2017
[ThreadStatic]
2118
private static ApartmentType t_apartmentType;
2219

@@ -404,24 +401,8 @@ internal static Thread EnsureThreadPoolThreadInitialized()
404401

405402
public void Interrupt() { throw new PlatformNotSupportedException(); }
406403

407-
//
408-
// Suppresses reentrant waits on the current thread, until a matching call to RestoreReentrantWaits.
409-
// This should be used by code that's expected to be called inside the STA message pump, so that it won't
410-
// reenter itself. In an ASTA, this should only be the CCW implementations of IUnknown and IInspectable.
411-
//
412-
internal static void SuppressReentrantWaits()
413-
{
414-
t_reentrantWaitSuppressionCount++;
415-
}
416-
417-
internal static void RestoreReentrantWaits()
418-
{
419-
Debug.Assert(t_reentrantWaitSuppressionCount > 0);
420-
t_reentrantWaitSuppressionCount--;
421-
}
422-
423404
internal static bool ReentrantWaitsEnabled =>
424-
GetCurrentApartmentType() == ApartmentType.STA && t_reentrantWaitSuppressionCount == 0;
405+
GetCurrentApartmentType() == ApartmentType.STA;
425406

426407
internal static ApartmentType GetCurrentApartmentType()
427408
{

src/coreclr/vm/assembly.hpp

-5
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,6 @@ class Assembly
372372
OBJECTHANDLE GetLoaderAllocatorObjectHandle() { WRAPPER_NO_CONTRACT; return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); }
373373
#endif // FEATURE_COLLECTIBLE_TYPES
374374

375-
#ifdef FEATURE_READYTORUN
376-
BOOL IsInstrumented();
377-
BOOL IsInstrumentedHelper();
378-
#endif // FEATURE_READYTORUN
379-
380375
#ifdef FEATURE_COMINTEROP
381376
static ITypeLib * const InvalidTypeLib;
382377

src/coreclr/vm/comsynchronizable.cpp

+34-20
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,7 @@
4040
static inline BOOL ThreadNotStarted(Thread *t)
4141
{
4242
WRAPPER_NO_CONTRACT;
43-
return (t && t->IsUnstarted() && !t->HasValidThreadHandle());
44-
}
45-
46-
static inline BOOL ThreadIsRunning(Thread *t)
47-
{
48-
WRAPPER_NO_CONTRACT;
49-
return (t &&
50-
(t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 &&
51-
(t->HasValidThreadHandle()));
43+
return (t && t->IsUnstarted());
5244
}
5345

5446
static inline BOOL ThreadIsDead(Thread *t)
@@ -255,10 +247,10 @@ void ThreadNative::Start(Thread* pNewThread, int threadStackSize, int priority,
255247

256248
#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
257249
// Attempt to eagerly set the apartment state during thread startup.
258-
Thread::ApartmentState as = pNewThread->GetExplicitApartment();
250+
Thread::ApartmentState as = pNewThread->GetApartmentOfUnstartedThread();
259251
if (as == Thread::AS_Unknown)
260252
{
261-
pNewThread->SetApartment(Thread::AS_InMTA);
253+
pNewThread->SetApartmentOfUnstartedThread(Thread::AS_InMTA);
262254
}
263255
#endif
264256

@@ -553,13 +545,23 @@ extern "C" INT32 QCALLTYPE ThreadNative_SetApartmentState(QCall::ObjectHandleOnS
553545
// We can only change the apartment if the thread is unstarted or
554546
// running, and if it's running we have to be in the thread's
555547
// context.
556-
if (!ThreadNotStarted(thread)
557-
&& (!ThreadIsRunning(thread) || (GetThread() != thread)))
548+
if (ThreadNotStarted(thread))
558549
{
559-
COMPlusThrow(kThreadStateException);
550+
// Compat: Disallow resetting the initial apartment state
551+
if (thread->GetApartmentOfUnstartedThread() == Thread::AS_Unknown)
552+
thread->SetApartmentOfUnstartedThread((Thread::ApartmentState)iState);
553+
554+
retVal = thread->GetApartmentOfUnstartedThread();
560555
}
556+
else
557+
{
558+
if (GetThread() != thread)
559+
{
560+
COMPlusThrow(kThreadStateException);
561+
}
561562

562-
retVal = thread->SetApartment((Thread::ApartmentState)iState);
563+
retVal = thread->SetApartment((Thread::ApartmentState)iState);
564+
}
563565

564566
END_QCALL;
565567
return retVal;
@@ -713,19 +715,31 @@ void ThreadBaseObject::InitExisting()
713715
m_Priority = ThreadNative::PRIORITY_NORMAL;
714716
break;
715717
}
716-
717718
}
718719

719720
FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE)
720721
{
721722
FCALL_CONTRACT;
722723

723-
// This function is intentionally blank.
724-
// See comment in code:MethodTable::CallFinalizer.
724+
THREADBASEREF refThis = (THREADBASEREF)pThisUNSAFE;
725+
Thread* thread = refThis->GetInternal();
726+
727+
// Prevent multiple calls to Finalize
728+
// Objects can be resurrected after being finalized. However, there is no
729+
// race condition here. We always check whether an exposed thread object is
730+
// still attached to the internal Thread object, before proceeding.
731+
if (thread)
732+
{
733+
refThis->ResetStartHelper();
725734

726-
_ASSERTE (!"Should not be called");
735+
if (GetThreadNULLOk() != thread)
736+
{
737+
refThis->ClearInternal();
738+
}
727739

728-
FCUnique(0x21);
740+
thread->SetThreadState(Thread::TS_Finalized);
741+
Thread::SetCleanupNeededForFinalizedThread();
742+
}
729743
}
730744
FCIMPLEND
731745

src/coreclr/vm/comutilnative.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,7 @@ void GCInterface::RemoveMemoryPressure(UINT64 bytesAllocated)
14011401
CONTRACTL
14021402
{
14031403
NOTHROW;
1404-
GC_TRIGGERS;
1404+
GC_NOTRIGGER;
14051405
MODE_ANY;
14061406
}
14071407
CONTRACTL_END;
@@ -1437,7 +1437,7 @@ NOINLINE void GCInterface::SendEtwRemoveMemoryPressureEvent(UINT64 bytesAllocate
14371437
CONTRACTL
14381438
{
14391439
NOTHROW;
1440-
GC_TRIGGERS;
1440+
GC_NOTRIGGER;
14411441
MODE_ANY;
14421442
}
14431443
CONTRACTL_END;

src/coreclr/vm/finalizerthread.cpp

-61
Original file line numberDiff line numberDiff line change
@@ -52,42 +52,6 @@ BOOL FinalizerThread::HaveExtraWorkForFinalizer()
5252
return GetFinalizerThread()->HaveExtraWorkForFinalizer();
5353
}
5454

55-
static void CallFinalizerOnThreadObject(OBJECTREF obj)
56-
{
57-
STATIC_CONTRACT_MODE_COOPERATIVE;
58-
59-
THREADBASEREF refThis = (THREADBASEREF)obj;
60-
Thread* thread = refThis->GetInternal();
61-
62-
// Prevent multiple calls to Finalize
63-
// Objects can be resurrected after being finalized. However, there is no
64-
// race condition here. We always check whether an exposed thread object is
65-
// still attached to the internal Thread object, before proceeding.
66-
if (thread)
67-
{
68-
refThis->ResetStartHelper();
69-
70-
// During process shutdown, we finalize even reachable objects. But if we break
71-
// the link between the System.Thread and the internal Thread object, the runtime
72-
// may not work correctly. In particular, we won't be able to transition between
73-
// contexts and domains to finalize other objects. Since the runtime doesn't
74-
// require that Threads finalize during shutdown, we need to disable this. If
75-
// we wait until phase 2 of shutdown finalization (when the EE is suspended and
76-
// will never resume) then we can simply skip the side effects of Thread
77-
// finalization.
78-
if ((g_fEEShutDown & ShutDown_Finalize2) == 0)
79-
{
80-
if (GetThreadNULLOk() != thread)
81-
{
82-
refThis->ClearInternal();
83-
}
84-
85-
thread->SetThreadState(Thread::TS_Finalized);
86-
Thread::SetCleanupNeededForFinalizedThread();
87-
}
88-
}
89-
}
90-
9155
OBJECTREF FinalizerThread::GetNextFinalizableObject()
9256
{
9357
STATIC_CONTRACT_THROWS;
@@ -138,20 +102,6 @@ OBJECTREF FinalizerThread::GetNextFinalizableObject()
138102
}
139103
while (pMTCur != NULL);
140104
}
141-
142-
if (pMT == g_pThreadClass)
143-
{
144-
// Finalizing Thread object requires ThreadStoreLock. It is expensive if
145-
// we keep taking ThreadStoreLock. This is very bad if we have high retiring
146-
// rate of Thread objects.
147-
// To avoid taking ThreadStoreLock multiple times, we mark Thread with TS_Finalized
148-
// and clean up a batch of them when we take ThreadStoreLock next time.
149-
150-
// To avoid possible hierarchy requirement between critical finalizers, we call cleanup
151-
// code directly.
152-
CallFinalizerOnThreadObject(obj);
153-
goto Again;
154-
}
155105

156106
return obj;
157107
}
@@ -426,19 +376,8 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args)
426376
ASSERT(args == 0);
427377
ASSERT(hEventFinalizer->IsValid());
428378

429-
// TODO: The following line should be removed after contract violation is fixed.
430-
// See bug 27409
431-
SCAN_IGNORE_THROW;
432-
SCAN_IGNORE_TRIGGER;
433-
434379
LOG((LF_GC, LL_INFO10, "Finalizer thread starting...\n"));
435380

436-
#if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(FEATURE_COMINTEROP)
437-
// Make sure the finalizer thread is set to MTA to avoid hitting
438-
// DevDiv Bugs 180773 - [Stress Failure] AV at CoreCLR!SafeQueryInterfaceHelper
439-
GetFinalizerThread()->SetApartment(Thread::AS_InMTA);
440-
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT && !FEATURE_COMINTEROP
441-
442381
s_FinalizerThreadOK = GetFinalizerThread()->HasStarted();
443382

444383
_ASSERTE(s_FinalizerThreadOK);

src/coreclr/vm/methodtable.h

-9
Original file line numberDiff line numberDiff line change
@@ -2691,15 +2691,6 @@ class MethodTable
26912691
void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
26922692
#endif //_DEBUG
26932693

2694-
inline BOOL IsAgileAndFinalizable()
2695-
{
2696-
LIMITED_METHOD_CONTRACT;
2697-
// Right now, System.Thread is the only cases of this.
2698-
// Things should stay this way - please don't change without talking to EE team.
2699-
return this == g_pThreadClass;
2700-
}
2701-
2702-
27032694
//-------------------------------------------------------------------
27042695
// ENUMS, DELEGATES, VALUE TYPES, ARRAYS
27052696
//

0 commit comments

Comments
 (0)