Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc cleanup of VM threading code #108171

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,7 @@ public ThreadPriority Priority
{
Thread _this = this;
SetPriority(ObjectHandleOnStack.Create(ref _this), (int)value);
if (value != ThreadPriority.Normal)
{
_mayNeedResetForThreadPool = true;
}
_mayNeedResetForThreadPool = true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not handling the case of finalizer threads.

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ namespace System.Threading
{
public sealed partial class Thread
{
[ThreadStatic]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code

private static int t_reentrantWaitSuppressionCount;

[ThreadStatic]
private static ApartmentType t_apartmentType;

Expand Down Expand Up @@ -404,24 +401,8 @@ internal static Thread EnsureThreadPoolThreadInitialized()

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

//
// Suppresses reentrant waits on the current thread, until a matching call to RestoreReentrantWaits.
// This should be used by code that's expected to be called inside the STA message pump, so that it won't
// reenter itself. In an ASTA, this should only be the CCW implementations of IUnknown and IInspectable.
//
internal static void SuppressReentrantWaits()
{
t_reentrantWaitSuppressionCount++;
}

internal static void RestoreReentrantWaits()
{
Debug.Assert(t_reentrantWaitSuppressionCount > 0);
t_reentrantWaitSuppressionCount--;
}

internal static bool ReentrantWaitsEnabled =>
GetCurrentApartmentType() == ApartmentType.STA && t_reentrantWaitSuppressionCount == 0;
GetCurrentApartmentType() == ApartmentType.STA;

internal static ApartmentType GetCurrentApartmentType()
{
Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/vm/assembly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,6 @@ class Assembly
OBJECTHANDLE GetLoaderAllocatorObjectHandle() { WRAPPER_NO_CONTRACT; return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); }
#endif // FEATURE_COLLECTIBLE_TYPES

#ifdef FEATURE_READYTORUN
BOOL IsInstrumented();
BOOL IsInstrumentedHelper();
#endif // FEATURE_READYTORUN

#ifdef FEATURE_COMINTEROP
static ITypeLib * const InvalidTypeLib;

Expand Down
54 changes: 34 additions & 20 deletions src/coreclr/vm/comsynchronizable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,7 @@
static inline BOOL ThreadNotStarted(Thread *t)
{
WRAPPER_NO_CONTRACT;
return (t && t->IsUnstarted() && !t->HasValidThreadHandle());
}

static inline BOOL ThreadIsRunning(Thread *t)
{
WRAPPER_NO_CONTRACT;
return (t &&
(t->m_State & (Thread::TS_ReportDead|Thread::TS_Dead)) == 0 &&
(t->HasValidThreadHandle()));
return (t && t->IsUnstarted());
}

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

#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
// Attempt to eagerly set the apartment state during thread startup.
Thread::ApartmentState as = pNewThread->GetExplicitApartment();
Thread::ApartmentState as = pNewThread->GetApartmentOfUnstartedThread();
if (as == Thread::AS_Unknown)
{
pNewThread->SetApartment(Thread::AS_InMTA);
pNewThread->SetApartmentOfUnstartedThread(Thread::AS_InMTA);
}
#endif

Expand Down Expand Up @@ -553,13 +545,23 @@ extern "C" INT32 QCALLTYPE ThreadNative_SetApartmentState(QCall::ObjectHandleOnS
// We can only change the apartment if the thread is unstarted or
// running, and if it's running we have to be in the thread's
// context.
if (!ThreadNotStarted(thread)
&& (!ThreadIsRunning(thread) || (GetThread() != thread)))
if (ThreadNotStarted(thread))
{
COMPlusThrow(kThreadStateException);
// Compat: Disallow resetting the initial apartment state
if (thread->GetApartmentOfUnstartedThread() == Thread::AS_Unknown)
thread->SetApartmentOfUnstartedThread((Thread::ApartmentState)iState);

retVal = thread->GetApartmentOfUnstartedThread();
}
else
{
if (GetThread() != thread)
{
COMPlusThrow(kThreadStateException);
}

retVal = thread->SetApartment((Thread::ApartmentState)iState);
retVal = thread->SetApartment((Thread::ApartmentState)iState);
}

END_QCALL;
return retVal;
Expand Down Expand Up @@ -713,19 +715,31 @@ void ThreadBaseObject::InitExisting()
m_Priority = ThreadNative::PRIORITY_NORMAL;
break;
}

}

FCIMPL1(void, ThreadNative::Finalize, ThreadBaseObject* pThisUNSAFE)
{
FCALL_CONTRACT;

// This function is intentionally blank.
// See comment in code:MethodTable::CallFinalizer.
THREADBASEREF refThis = (THREADBASEREF)pThisUNSAFE;
Thread* thread = refThis->GetInternal();

// Prevent multiple calls to Finalize
// Objects can be resurrected after being finalized. However, there is no
// race condition here. We always check whether an exposed thread object is
// still attached to the internal Thread object, before proceeding.
if (thread)
{
refThis->ResetStartHelper();

_ASSERTE (!"Should not be called");
if (GetThreadNULLOk() != thread)
{
refThis->ClearInternal();
}

FCUnique(0x21);
thread->SetThreadState(Thread::TS_Finalized);
Thread::SetCleanupNeededForFinalizedThread();
}
}
FCIMPLEND

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/comutilnative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ void GCInterface::RemoveMemoryPressure(UINT64 bytesAllocated)
CONTRACTL
{
NOTHROW;
GC_TRIGGERS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
Expand Down Expand Up @@ -1437,7 +1437,7 @@ NOINLINE void GCInterface::SendEtwRemoveMemoryPressureEvent(UINT64 bytesAllocate
CONTRACTL
{
NOTHROW;
GC_TRIGGERS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
Expand Down
61 changes: 0 additions & 61 deletions src/coreclr/vm/finalizerthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,42 +52,6 @@ BOOL FinalizerThread::HaveExtraWorkForFinalizer()
return GetFinalizerThread()->HaveExtraWorkForFinalizer();
}

static void CallFinalizerOnThreadObject(OBJECTREF obj)
{
STATIC_CONTRACT_MODE_COOPERATIVE;

THREADBASEREF refThis = (THREADBASEREF)obj;
Thread* thread = refThis->GetInternal();

// Prevent multiple calls to Finalize
// Objects can be resurrected after being finalized. However, there is no
// race condition here. We always check whether an exposed thread object is
// still attached to the internal Thread object, before proceeding.
if (thread)
{
refThis->ResetStartHelper();

// During process shutdown, we finalize even reachable objects. But if we break
// the link between the System.Thread and the internal Thread object, the runtime
// may not work correctly. In particular, we won't be able to transition between
// contexts and domains to finalize other objects. Since the runtime doesn't
// require that Threads finalize during shutdown, we need to disable this. If
// we wait until phase 2 of shutdown finalization (when the EE is suspended and
// will never resume) then we can simply skip the side effects of Thread
// finalization.
if ((g_fEEShutDown & ShutDown_Finalize2) == 0)
{
if (GetThreadNULLOk() != thread)
{
refThis->ClearInternal();
}

thread->SetThreadState(Thread::TS_Finalized);
Thread::SetCleanupNeededForFinalizedThread();
}
}
}

OBJECTREF FinalizerThread::GetNextFinalizableObject()
{
STATIC_CONTRACT_THROWS;
Expand Down Expand Up @@ -138,20 +102,6 @@ OBJECTREF FinalizerThread::GetNextFinalizableObject()
}
while (pMTCur != NULL);
}

if (pMT == g_pThreadClass)
{
// Finalizing Thread object requires ThreadStoreLock. It is expensive if
// we keep taking ThreadStoreLock. This is very bad if we have high retiring
// rate of Thread objects.
// To avoid taking ThreadStoreLock multiple times, we mark Thread with TS_Finalized
// and clean up a batch of them when we take ThreadStoreLock next time.

// To avoid possible hierarchy requirement between critical finalizers, we call cleanup
// code directly.
CallFinalizerOnThreadObject(obj);
goto Again;
}

return obj;
}
Expand Down Expand Up @@ -426,19 +376,8 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args)
ASSERT(args == 0);
ASSERT(hEventFinalizer->IsValid());

// TODO: The following line should be removed after contract violation is fixed.
// See bug 27409
SCAN_IGNORE_THROW;
SCAN_IGNORE_TRIGGER;

LOG((LF_GC, LL_INFO10, "Finalizer thread starting...\n"));

#if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(FEATURE_COMINTEROP)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition was always false.

// Make sure the finalizer thread is set to MTA to avoid hitting
// DevDiv Bugs 180773 - [Stress Failure] AV at CoreCLR!SafeQueryInterfaceHelper
GetFinalizerThread()->SetApartment(Thread::AS_InMTA);
#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT && !FEATURE_COMINTEROP

s_FinalizerThreadOK = GetFinalizerThread()->HasStarted();

_ASSERTE(s_FinalizerThreadOK);
Expand Down
9 changes: 0 additions & 9 deletions src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -2691,15 +2691,6 @@ class MethodTable
void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
#endif //_DEBUG

inline BOOL IsAgileAndFinalizable()
{
LIMITED_METHOD_CONTRACT;
// Right now, System.Thread is the only cases of this.
// Things should stay this way - please don't change without talking to EE team.
return this == g_pThreadClass;
}


//-------------------------------------------------------------------
// ENUMS, DELEGATES, VALUE TYPES, ARRAYS
//
Expand Down
Loading
Loading