summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs5
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs6
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs17
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/Timer.cs11
-rw-r--r--src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs7
-rw-r--r--src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs19
-rw-r--r--src/System.Private.CoreLib/src/System/Reflection/LoaderAllocator.cs17
-rw-r--r--src/System.Private.CoreLib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs7
-rw-r--r--src/classlibnative/bcltype/system.cpp12
-rw-r--r--src/classlibnative/bcltype/system.h3
-rw-r--r--src/inc/MSCOREE.IDL1
-rw-r--r--src/inc/clrconfigvalues.h7
-rw-r--r--src/pal/prebuilt/inc/mscoree.h3
-rw-r--r--src/utilcode/posterror.cpp10
-rw-r--r--src/vm/appdomain.cpp4
-rw-r--r--src/vm/ceemain.cpp157
-rw-r--r--src/vm/ecalllist.h1
-rw-r--r--src/vm/eepolicy.cpp70
-rw-r--r--src/vm/excep.cpp11
-rw-r--r--src/vm/finalizerthread.cpp405
-rw-r--r--src/vm/finalizerthread.h19
-rw-r--r--src/vm/frames.cpp8
-rw-r--r--src/vm/frames.h1
-rw-r--r--src/vm/threads.cpp6
-rw-r--r--src/vm/threadsuspend.cpp50
-rw-r--r--src/vm/vars.hpp4
-rw-r--r--src/vm/win32threadpool.cpp7
27 files changed, 43 insertions, 825 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs b/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs
index acc415b6d1..1f8de9628e 100644
--- a/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs
+++ b/src/System.Private.CoreLib/shared/System/Gen2GcCallback.cs
@@ -71,10 +71,7 @@ namespace System
}
// Resurrect ourselves by re-registering for finalization.
- if (!Environment.HasShutdownStarted)
- {
- GC.ReRegisterForFinalize(this);
- }
+ GC.ReRegisterForFinalize(this);
}
}
}
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs
index a7ea972b41..505134a5cc 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs
@@ -750,11 +750,9 @@ namespace System.Runtime.CompilerServices
~Container()
{
- // We're just freeing per-appdomain unmanaged handles here. If we're already shutting down the AD,
- // don't bother. (Despite its name, Environment.HasShutdownStart also returns true if the current
- // AD is finalizing.) We also skip doing anything if the container is invalid, including if someone
+ // Skip doing anything if the container is invalid, including if somehow
// the container object was allocated but its associated table never set.
- if (Environment.HasShutdownStarted || _invalid || _parent is null)
+ if (_invalid || _parent is null)
{
return;
}
diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
index 4e6ff27e30..0625a97f13 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
@@ -709,8 +709,9 @@ namespace System.Threading
currentThread = Thread.CurrentThread;
}
- private void CleanUp()
+ ~ThreadPoolWorkQueueThreadLocals()
{
+ // Transfer any pending workitems into the global queue so that they will be executed by another thread
if (null != workStealingQueue)
{
if (null != workQueue)
@@ -726,17 +727,6 @@ namespace System.Threading
ThreadPoolWorkQueue.WorkStealingQueueList.Remove(workStealingQueue);
}
}
-
- ~ThreadPoolWorkQueueThreadLocals()
- {
- // Since the purpose of calling CleanUp is to transfer any pending workitems into the global
- // queue so that they will be executed by another thread, there's no point in doing this cleanup
- // if we're in the process of shutting down or unloading the AD. In those cases, the work won't
- // execute anyway. And there are subtle race conditions involved there that would lead us to do the wrong
- // thing anyway. So we'll only clean up if this is a "normal" finalization.
- if (!Environment.HasShutdownStarted)
- CleanUp();
- }
}
public delegate void WaitCallback(object? state);
@@ -752,8 +742,7 @@ namespace System.Threading
~QueueUserWorkItemCallbackBase()
{
Debug.Assert(
- executed != 0 || Environment.HasShutdownStarted,
- "A QueueUserWorkItemCallback was never called!");
+ executed != 0, "A QueueUserWorkItemCallback was never called!");
}
#endif
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Timer.cs b/src/System.Private.CoreLib/shared/System/Threading/Timer.cs
index 66d01ac81a..19bdac6f7a 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/Timer.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/Timer.cs
@@ -678,17 +678,6 @@ namespace System.Threading
~TimerHolder()
{
- // If shutdown has started, another thread may be suspended while holding the timer lock.
- // So we can't safely close the timer.
- //
- // Similarly, we should not close the timer during AD-unload's live-object finalization phase.
- // A rude abort may have prevented us from releasing the lock.
- //
- // Note that in either case, the Timer still won't fire, because ThreadPool threads won't be
- // allowed to run anymore.
- if (Environment.HasShutdownStarted)
- return;
-
_timer.Close();
}
diff --git a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
index 4514043e70..b09fa91a1b 100644
--- a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
+++ b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
@@ -77,11 +77,8 @@ namespace System
GetCommandLineArgsNative();
}
- public static extern bool HasShutdownStarted
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- get;
- }
+ // Unconditionally return false since .NET Core does not support object finalization during shutdown.
+ public static bool HasShutdownStarted => false;
public static int ProcessorCount => GetProcessorCount();
diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
index b47b305057..aee47df59c 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
+++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
@@ -638,14 +638,8 @@ namespace System.Reflection.Emit
}
catch
{
- // We go over all DynamicMethodDesc during AppDomain shutdown and make sure
- // that everything associated with them is released. So it is ok to skip reregistration
- // for finalization during appdomain shutdown
- if (!Environment.HasShutdownStarted)
- {
- // Try again later.
- GC.ReRegisterForFinalize(this);
- }
+ // Try again later.
+ GC.ReRegisterForFinalize(this);
return;
}
@@ -666,12 +660,9 @@ namespace System.Reflection.Emit
// It is not safe to destroy the method if the managed resolver is alive.
if (RuntimeMethodHandle.GetResolver(m_methodHandle) != null)
{
- if (!Environment.HasShutdownStarted)
- {
- // Somebody might have been holding a reference on us via weak handle.
- // We will keep trying. It will be hopefully released eventually.
- GC.ReRegisterForFinalize(this);
- }
+ // Somebody might have been holding a reference on us via weak handle.
+ // We will keep trying. It will be hopefully released eventually.
+ GC.ReRegisterForFinalize(this);
return;
}
diff --git a/src/System.Private.CoreLib/src/System/Reflection/LoaderAllocator.cs b/src/System.Private.CoreLib/src/System/Reflection/LoaderAllocator.cs
index 1119f07fa4..7d7d16b052 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/LoaderAllocator.cs
+++ b/src/System.Private.CoreLib/src/System/Reflection/LoaderAllocator.cs
@@ -41,19 +41,12 @@ namespace System.Reflection
if (m_nativeLoaderAllocator == IntPtr.Zero)
return;
- // Assemblies and LoaderAllocators will be cleaned up during AppDomain shutdown in
- // unmanaged code
- // So it is ok to skip reregistration and cleanup for finalization during shutdown.
- // We also avoid early finalization of LoaderAllocatorScout due to AD unload when the object was inside DelayedFinalizationList.
- if (!Environment.HasShutdownStarted)
+ // Destroy returns false if the managed LoaderAllocator is still alive.
+ if (!Destroy(m_nativeLoaderAllocator))
{
- // Destroy returns false if the managed LoaderAllocator is still alive.
- if (!Destroy(m_nativeLoaderAllocator))
- {
- // Somebody might have been holding a reference on us via weak handle.
- // We will keep trying. It will be hopefully released eventually.
- GC.ReRegisterForFinalize(this);
- }
+ // Somebody might have been holding a reference on us via weak handle.
+ // We will keep trying. It will be hopefully released eventually.
+ GC.ReRegisterForFinalize(this);
}
}
}
diff --git a/src/System.Private.CoreLib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs
index 26e1bd6bee..fd7f1dd962 100644
--- a/src/System.Private.CoreLib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs
+++ b/src/System.Private.CoreLib/src/System/Threading/ClrThreadPoolPreAllocatedOverlapped.cs
@@ -78,12 +78,7 @@ namespace System.Threading
~PreAllocatedOverlapped()
{
- //
- // During shutdown, don't automatically clean up, because this instance may still be
- // reachable/usable by other code.
- //
- if (!Environment.HasShutdownStarted)
- Dispose();
+ Dispose();
}
unsafe void IDeferredDisposable.OnFinalRelease(bool disposed)
diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp
index 38e5bba9ad..ce47c14e1b 100644
--- a/src/classlibnative/bcltype/system.cpp
+++ b/src/classlibnative/bcltype/system.cpp
@@ -356,18 +356,6 @@ INT32 QCALLTYPE SystemNative::GetProcessorCount()
return processorCount;
}
-FCIMPL0(FC_BOOL_RET, SystemNative::HasShutdownStarted)
-{
- FCALL_CONTRACT;
-
- // Return true if the EE has started to shutdown and is now going to
- // aggressively finalize objects referred to by static variables OR
- // if someone is unloading the current AppDomain AND we have started
- // finalizing objects referred to by static variables.
- FC_RETURN_BOOL(g_fEEShutDown & ShutDown_Finalize2);
-}
-FCIMPLEND
-
// FailFast is supported in BCL.small as internal to support failing fast in places where EEE used to be thrown.
//
// Static message buffer used by SystemNative::FailFast to avoid reliance on a
diff --git a/src/classlibnative/bcltype/system.h b/src/classlibnative/bcltype/system.h
index 803f1dfca8..95670a382c 100644
--- a/src/classlibnative/bcltype/system.h
+++ b/src/classlibnative/bcltype/system.h
@@ -69,9 +69,8 @@ public:
static FCDECL3(VOID, FailFastWithExceptionAndSource, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE, StringObject* errorSourceUNSAFE);
// Returns the number of logical processors that can be used by managed code
- static INT32 QCALLTYPE GetProcessorCount();
+ static INT32 QCALLTYPE GetProcessorCount();
- static FCDECL0(FC_BOOL_RET, HasShutdownStarted);
static FCDECL0(FC_BOOL_RET, IsServerGC);
#ifdef FEATURE_COMINTEROP
diff --git a/src/inc/MSCOREE.IDL b/src/inc/MSCOREE.IDL
index 93e4042816..ce368f3f80 100644
--- a/src/inc/MSCOREE.IDL
+++ b/src/inc/MSCOREE.IDL
@@ -204,7 +204,6 @@ typedef enum
// Stop bypasses finalizer run.
eFastExitProcess,
eRudeExitProcess,
- eDisableRuntime,
MaxPolicyAction
} EPolicyAction;
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index 441ae8e44b..61258ae09c 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -110,11 +110,6 @@ CONFIG_DWORD_INFO(INTERNAL_ADTakeDHSnapShot, W("ADTakeDHSnapShot"), 0, "Supersed
CONFIG_DWORD_INFO(INTERNAL_ADTakeSnapShot, W("ADTakeSnapShot"), 0, "Superseded by test hooks")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_EnableFullDebug, W("EnableFullDebug"), "Heavy-weight checking for AD boundary violations (AD leaks)")
-// For the proposal and discussion on why finalizers are not run on shutdown by default anymore in CoreCLR, see the API review:
-// https://github.com/dotnet/corefx/issues/5205
-#define DEFAULT_FinalizeOnShutdown (0)
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_FinalizeOnShutdown, W("FinalizeOnShutdown"), DEFAULT_FinalizeOnShutdown, "When enabled, on shutdown, blocks all user threads and calls finalizers for all finalizable objects, including live objects")
-
///
/// ARM
///
@@ -150,7 +145,6 @@ CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDumpToken, W("BreakOnDumpToken"), 0xfffffff
RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnEELoad, W("BreakOnEELoad"), 0, "", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO(INTERNAL_BreakOnEEShutdown, W("BreakOnEEShutdown"), 0, "")
CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnExceptionInGetThrowable, W("BreakOnExceptionInGetThrowable"), 0, "", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BreakOnFinalizeTimeOut, W("BreakOnFinalizeTimeOut"), 0, "Triggers a debug break on the finalizer thread when it has exceeded the maximum wait time")
CONFIG_DWORD_INFO(INTERNAL_BreakOnFindMethod, W("BreakOnFindMethod"), 0, "Breaks in findMethodInternal when it searches for the specified token.")
CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnFirstPass, W("BreakOnFirstPass"), 0, "", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnHR, W("BreakOnHR"), 0, "Debug.cpp, IfFailxxx use this macro to stop if hr matches ", CLRConfig::REGUTIL_default)
@@ -158,7 +152,6 @@ CONFIG_STRING_INFO(INTERNAL_BreakOnInstantiation, W("BreakOnInstantiation"), "Ve
CONFIG_STRING_INFO(INTERNAL_BreakOnInteropStubSetup, W("BreakOnInteropStubSetup"), "Throws an assert when marshaling stub for the given method is about to be built.")
CONFIG_STRING_INFO_EX(INTERNAL_BreakOnInteropVTableBuild, W("BreakOnInteropVTableBuild"), "Specifies a type name for which an assert should be thrown when building interop v-table.", CLRConfig::REGUTIL_default)
CONFIG_STRING_INFO(INTERNAL_BreakOnMethodName, W("BreakOnMethodName"), "Very useful for debugging method override placement code.")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnNGenRegistryAccessCount, W("BreakOnNGenRegistryAccessCount"), 0, "Breaks on the Nth' root store write", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnNotify, W("BreakOnNotify"), 0, "", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnRetailAssert, W("BreakOnRetailAssert"), 0, "Used for debugging \"retail\" asserts (fatal errors)", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnSecondPass, W("BreakOnSecondPass"), 0, "", CLRConfig::REGUTIL_default)
diff --git a/src/pal/prebuilt/inc/mscoree.h b/src/pal/prebuilt/inc/mscoree.h
index 42a97c0096..ab7bbb0d0c 100644
--- a/src/pal/prebuilt/inc/mscoree.h
+++ b/src/pal/prebuilt/inc/mscoree.h
@@ -229,8 +229,7 @@ enum __MIDL___MIDL_itf_mscoree_0000_0000_0009
eExitProcess = ( eRudeUnloadAppDomain + 1 ) ,
eFastExitProcess = ( eExitProcess + 1 ) ,
eRudeExitProcess = ( eFastExitProcess + 1 ) ,
- eDisableRuntime = ( eRudeExitProcess + 1 ) ,
- MaxPolicyAction = ( eDisableRuntime + 1 )
+ MaxPolicyAction = (eRudeExitProcess + 1 )
} EPolicyAction;
diff --git a/src/utilcode/posterror.cpp b/src/utilcode/posterror.cpp
index 3c97db7ea2..a15128add9 100644
--- a/src/utilcode/posterror.cpp
+++ b/src/utilcode/posterror.cpp
@@ -28,16 +28,6 @@
// Local prototypes.
HRESULT FillErrorInfo(LPCWSTR szMsg, DWORD dwHelpContext);
-//*****************************************************************************
-// Function that we'll expose to the outside world to fire off the shutdown method
-//*****************************************************************************
-#ifdef SHOULD_WE_CLEANUP
-void ShutdownCompRC()
-{
- CCompRC::ShutdownDefaultResourceDll();
-}
-#endif /* SHOULD_WE_CLEANUP */
-
void GetResourceCultureCallbacks(
FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
FPGETTHREADUICULTUREID* fpGetThreadUICultureId)
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index abb9ac15d6..9ac4478a1d 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -3207,11 +3207,7 @@ void AppDomain::Stop()
#ifdef DEBUGGING_SUPPORTED
if (IsDebuggerAttached())
NotifyDebuggerUnload();
-#endif // DEBUGGING_SUPPORTED
-
- m_pRootAssembly = NULL; // This assembly is in the assembly list;
-#ifdef DEBUGGING_SUPPORTED
if (NULL != g_pDebugInterface)
{
// Call the publisher API to delete this appdomain entry from the list
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp
index 9ac0cc6a71..3ca3356717 100644
--- a/src/vm/ceemain.cpp
+++ b/src/vm/ceemain.cpp
@@ -257,12 +257,6 @@ HRESULT g_EEStartupStatus = S_OK;
// checking this flag.
Volatile<BOOL> g_fEEStarted = FALSE;
-// Flag indicating if the EE should be suspended on shutdown.
-BOOL g_fSuspendOnShutdown = FALSE;
-
-// Flag indicating if the finalizer thread should be suspended on shutdown.
-BOOL g_fSuspendFinalizerOnShutdown = FALSE;
-
// Flag indicating if the EE was started up by COM.
extern BOOL g_fEEComActivatedStartup;
@@ -1457,7 +1451,7 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
// Used later for a callback.
CEEInfo ceeInf;
- if(fIsDllUnloading)
+ if (fIsDllUnloading)
{
ETW::EnumerationLog::ProcessShutdown();
}
@@ -1513,8 +1507,6 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
g_pDebugInterface->EarlyHelperThreadDeath();
#endif // DEBUGGING_SUPPORTED
- BOOL fFinalizeOK = FALSE;
-
EX_TRY
{
ClrFlsSetThreadType(ThreadType_Shutdown);
@@ -1528,20 +1520,17 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
// Indicate the EE is the shut down phase.
g_fEEShutDown |= ShutDown_Start;
- fFinalizeOK = TRUE;
-
// Terminate the BBSweep thread
g_BBSweep.ShutdownBBSweepThread();
- // We perform the final GC only if the user has requested it through the GC class.
- // We should never do the final GC for a process detach
if (!g_fProcessDetach && !g_fFastExitProcess)
{
g_fEEShutDown |= ShutDown_Finalize1;
- FinalizerThread::EnableFinalization();
- fFinalizeOK = FinalizerThread::FinalizerThreadWatchDog();
- }
+ // Wait for the finalizer thread to deliver process exit event
+ GCX_PREEMP();
+ FinalizerThread::RaiseShutdownEvents();
+ }
// Ok. Let's stop the EE.
if (!g_fProcessDetach)
@@ -1566,21 +1555,6 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
// This call will convert the ThreadStoreLock into "shutdown" mode, just like the debugger lock above.
g_fEEShutDown |= ShutDown_Finalize2;
- if (fFinalizeOK)
- {
- fFinalizeOK = FinalizerThread::FinalizerThreadWatchDog();
- }
-
- if (!fFinalizeOK)
- {
- // One of the calls to FinalizerThreadWatchDog failed due to timeout, so we need to prevent
- // any thread from running managed code, including the finalizer.
- ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_SHUTDOWN);
- g_fSuspendOnShutdown = TRUE;
- g_fSuspendFinalizerOnShutdown = TRUE;
- ThreadStore::TrapReturningThreads(TRUE);
- ThreadSuspend::RestartEE(FALSE, TRUE);
- }
}
#ifdef FEATURE_EVENT_TRACE
@@ -1631,18 +1605,6 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
Interpreter::PrintPostMortemData();
#endif // FEATURE_INTERPRETER
- FastInterlockExchange((LONG*)&g_fForbidEnterEE, TRUE);
-
- if (g_fProcessDetach)
- {
- ThreadStore::TrapReturningThreads(TRUE);
- }
-
- if (!g_fProcessDetach && !fFinalizeOK)
- {
- goto lDone;
- }
-
#ifdef PROFILING_SUPPORTED
// If profiling is enabled, then notify of shutdown first so that the
// profiler can make any last calls it needs to. Do this only if we
@@ -1761,13 +1723,6 @@ part2:
Interpreter::Terminate();
#endif // FEATURE_INTERPRETER
-#ifdef SHOULD_WE_CLEANUP
- if (!g_fFastExitProcess)
- {
- GCHandleUtilities::GetGCHandleManager()->Shutdown();
- }
-#endif /* SHOULD_WE_CLEANUP */
-
//@TODO: find the right place for this
VirtualCallStubManager::UninitStatic();
@@ -1775,13 +1730,6 @@ part2:
PerfLog::PerfLogDone();
#endif //ENABLE_PERF_LOG
- Frame::Term();
-
- if (!g_fFastExitProcess)
- {
- SystemDomain::DetachEnd();
- }
-
// Unregister our vectored exception and continue handlers from the OS.
// This will ensure that if any other DLL unload (after ours) has an exception,
// we wont attempt to process that exception (which could lead to various
@@ -1822,9 +1770,6 @@ part2:
StressLog::Terminate(TRUE);
#endif
- if (g_pConfig != NULL)
- g_pConfig->Cleanup();
-
#ifdef LOGGING
ShutdownLogging();
#endif
@@ -1910,46 +1855,6 @@ BOOL IsThreadInSTA()
}
#endif
-static LONG s_ActiveShutdownThreadCount = 0;
-
-// ---------------------------------------------------------------------------
-// Function: EEShutDownProcForSTAThread(LPVOID lpParameter)
-//
-// Parameters:
-// LPVOID lpParameter: unused
-//
-// Description:
-// When EEShutDown decides that the shut down logic must occur on another thread,
-// EEShutDown creates a new thread, and this function acts as the thread proc. See
-// code:#STAShutDown for details.
-//
-DWORD WINAPI EEShutDownProcForSTAThread(LPVOID lpParameter)
-{
- ClrFlsSetThreadType(ThreadType_ShutdownHelper);
-
- EEShutDownHelper(FALSE);
- for (int i = 0; i < 10; i ++)
- {
- if (s_ActiveShutdownThreadCount)
- {
- return 0;
- }
- __SwitchToThread(20, CALLER_LIMITS_SPINNING);
- }
-
- EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL);
- if (action < eRudeExitProcess)
- {
- action = eRudeExitProcess;
- }
-
- UINT exitCode = GetLatchedExitCode();
- EEPolicy::HandleExitProcessFromEscalation(action, exitCode);
-
- return 0;
-}
-
-// ---------------------------------------------------------------------------
// #EEShutDown
//
// Function: EEShutDown(BOOL fIsDllUnloading)
@@ -2027,60 +1932,14 @@ void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading)
#endif
}
-#ifdef FEATURE_COMINTEROP
- if (!fIsDllUnloading && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_FinalizeOnShutdown) && IsThreadInSTA())
- {
- // #STAShutDown
- //
- // During shutdown, we may need to release STA interface on the shutdown thread.
- // It is possible that the shutdown thread may deadlock. During shutdown, all
- // threads are blocked, except the shutdown thread and finalizer thread. If a
- // lock is held by one of these suspended threads, it can deadlock the process if
- // the shutdown thread tries to enter the lock. To mitigate this risk, create
- // another thread (B) to do shutdown activities (i.e., EEShutDownHelper), while
- // this thread (A) waits. If B deadlocks, A will time out and immediately return
- // from EEShutDown. A will then eventually call the OS's ExitProcess, which will
- // kill the deadlocked thread (and all other threads).
- //
- // Many Windows Forms-based apps will also execute the code below to shift shut
- // down logic to a separate thread, even if they don't use COM objects. Reason
- // being that they will typically use a main UI thread to pump all Windows
- // messages (including messages that facilitate cross-thread COM calls to STA COM
- // objects), and will set that thread up as an STA thread just in case there are
- // such cross-thread COM calls to contend with. In fact, when you use VS's
- // File.New.Project to make a new Windows Forms project, VS will mark Main() with
- // [STAThread]
- DWORD thread_id = 0;
- if (CreateThread(NULL,0,EEShutDownProcForSTAThread,NULL,0,&thread_id))
- {
- GCX_PREEMP_NO_DTOR();
-
- ClrFlsSetThreadType(ThreadType_Shutdown);
- WaitForEndOfShutdown();
- FastInterlockIncrement(&s_ActiveShutdownThreadCount);
- ClrFlsClearThreadType(ThreadType_Shutdown);
- }
- }
- else
- // Otherwise, this thread calls EEShutDownHelper directly. First switch to
- // cooperative mode if this is a managed thread
-#endif
if (GetThread())
{
GCX_COOP();
EEShutDownHelper(fIsDllUnloading);
- if (!fIsDllUnloading)
- {
- FastInterlockIncrement(&s_ActiveShutdownThreadCount);
- }
}
else
{
EEShutDownHelper(fIsDllUnloading);
- if (!fIsDllUnloading)
- {
- FastInterlockIncrement(&s_ActiveShutdownThreadCount);
- }
}
}
@@ -2406,11 +2265,7 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
if (g_fEEStarted)
{
- // GetThread() may be set to NULL for Win9x during shutdown.
- Thread *pThread = GetThread();
- if (GCHeapUtilities::IsGCInProgress() &&
- ( (pThread && (pThread != ThreadSuspend::GetSuspensionThread() ))
- || !g_fSuspendOnShutdown))
+ if (GCHeapUtilities::IsGCInProgress())
{
g_fEEShutDown |= ShutDown_Phase2;
break;
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index ab2da6555d..50071ed410 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -164,7 +164,6 @@ FCFuncStart(gEnvironmentFuncs)
QCFuncElement("_Exit", SystemNative::Exit)
FCFuncElement("set_ExitCode", SystemNative::SetExitCode)
FCFuncElement("get_ExitCode", SystemNative::GetExitCode)
- FCFuncElement("get_HasShutdownStarted", SystemNative::HasShutdownStarted)
QCFuncElement("GetProcessorCount", SystemNative::GetProcessorCount)
FCFuncElement("GetCommandLineArgsNative", SystemNative::GetCommandLineArgs)
diff --git a/src/vm/eepolicy.cpp b/src/vm/eepolicy.cpp
index a6ecda0520..2da1c70f70 100644
--- a/src/vm/eepolicy.cpp
+++ b/src/vm/eepolicy.cpp
@@ -538,61 +538,6 @@ void EEPolicy::ExitProcessViaShim(UINT exitCode)
ExitProcess(exitCode);
}
-
-//---------------------------------------------------------------------------------------
-// DisableRuntime disables this runtime, suspending all managed execution and preventing
-// threads from entering the runtime. This will cause the caller to block forever as well
-// unless sca is SCA_ReturnWhenShutdownComplete.
-//---------------------------------------------------------------------------------------
-void DisableRuntime(ShutdownCompleteAction sca)
-{
- CONTRACTL
- {
- DISABLED(GC_TRIGGERS);
- NOTHROW;
- }
- CONTRACTL_END;
-
- FastInterlockExchange((LONG*)&g_fForbidEnterEE, TRUE);
-
- if (!g_fSuspendOnShutdown)
- {
- if (!IsGCThread())
- {
- if (ThreadStore::HoldingThreadStore(GetThread()))
- {
- ThreadSuspend::UnlockThreadStore();
- }
- ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_SHUTDOWN);
- }
-
- if (!g_fSuspendOnShutdown)
- {
- ThreadStore::TrapReturningThreads(TRUE);
- g_fSuspendOnShutdown = TRUE;
- ClrFlsSetThreadType(ThreadType_Shutdown);
- }
-
- // Don't restart runtime. CLR is disabled.
- }
-
- GCX_PREEMP_NO_DTOR();
-
- ClrFlsClearThreadType(ThreadType_Shutdown);
-
- if (g_pDebugInterface != NULL)
- {
- g_pDebugInterface->DisableDebugger();
- }
-
- if (sca == SCA_ExitProcessWhenShutdownComplete)
- {
- __SwitchToThread(INFINITE, CALLER_LIMITS_SPINNING);
- _ASSERTE (!"Should not reach here");
- SafeExitProcess(0);
- }
-}
-
//---------------------------------------------------------------------------------------
// HandleExitProcessHelper is used to shutdown the runtime as specified by the given
// action, then to exit the process. Note, however, that the process will not exit if
@@ -629,9 +574,6 @@ static void HandleExitProcessHelper(EPolicyAction action, UINT exitCode, Shutdow
g_fFastExitProcess = 2;
SafeExitProcess(exitCode, TRUE, sca);
break;
- case eDisableRuntime:
- DisableRuntime(sca);
- break;
default:
_ASSERTE (!"Invalid policy");
break;
@@ -686,7 +628,6 @@ void EEPolicy::PerformResourceConstraintAction(Thread *pThread, EPolicyAction ac
case eExitProcess:
case eFastExitProcess:
case eRudeExitProcess:
- case eDisableRuntime:
HandleExitProcessFromEscalation(action, exitCode);
break;
default:
@@ -1040,13 +981,6 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage
}
#endif // _DEBUG
- // We're here logging a fatal error. If the policy is to then do anything other than
- // disable the runtime (ie, if the policy is to terminate the runtime), we should give
- // Watson an opportunity to capture an error report.
- // Presumably, hosts that are sophisticated enough to disable the runtime are also cognizant
- // of how they want to handle fatal errors in the runtime, including whether they want
- // to capture Watson information (for which they are responsible).
- if (GetEEPolicy()->GetActionOnFailureNoHostNotification(FAIL_FatalRuntime) != eDisableRuntime)
{
#ifdef DEBUGGING_SUPPORTED
//Give a managed debugger a chance if this fatal error is on a managed thread.
@@ -1279,10 +1213,6 @@ int NOINLINE EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR
LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource, argExceptionString);
SafeExitProcess(exitCode, TRUE);
break;
- case eDisableRuntime:
- LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource, argExceptionString);
- DisableRuntime(SCA_ExitProcessWhenShutdownComplete);
- break;
default:
_ASSERTE(!"Invalid action for FAIL_FatalRuntime");
break;
diff --git a/src/vm/excep.cpp b/src/vm/excep.cpp
index 4d24b21d90..52cab11138 100644
--- a/src/vm/excep.cpp
+++ b/src/vm/excep.cpp
@@ -4738,17 +4738,6 @@ LONG InternalUnhandledExceptionFilter_Worker(
return EXCEPTION_CONTINUE_SEARCH;
}
-
- if (GetEEPolicy()->GetActionOnFailure(FAIL_FatalRuntime) == eDisableRuntime)
- {
- ETaskType type = ::GetCurrentTaskType();
- if (type != TT_UNKNOWN && type != TT_USER)
- {
- LOG((LF_EH, LL_INFO100, "InternalUnhandledExceptionFilter_Worker: calling EEPolicy::HandleFatalError\n"));
- EEPolicy::HandleFatalError(COR_E_EXECUTIONENGINE, (UINT_PTR)GetIP(pExceptionInfo->ContextRecord), NULL, pExceptionInfo);
- }
- }
-
// We don't do anything when this is called from an unmanaged thread.
Thread *pThread = GetThread();
diff --git a/src/vm/finalizerthread.cpp b/src/vm/finalizerthread.cpp
index 15e97878c0..ad3386e5a5 100644
--- a/src/vm/finalizerthread.cpp
+++ b/src/vm/finalizerthread.cpp
@@ -17,7 +17,6 @@
#include "profattach.h"
#endif // FEATURE_PROFAPI_ATTACH_DETACH
-BOOL FinalizerThread::fRunFinalizersOnUnload = FALSE;
BOOL FinalizerThread::fQuitFinalizer = FALSE;
#if defined(__linux__) && defined(FEATURE_EVENT_TRACE)
@@ -31,7 +30,6 @@ Volatile<BOOL> g_TriggerHeapDump = FALSE;
CLREvent * FinalizerThread::hEventFinalizer = NULL;
CLREvent * FinalizerThread::hEventFinalizerDone = NULL;
-CLREvent * FinalizerThread::hEventShutDownToFinalizer = NULL;
CLREvent * FinalizerThread::hEventFinalizerToShutDown = NULL;
HANDLE FinalizerThread::MHandles[kHandleCount];
@@ -408,8 +406,6 @@ static BOOL s_FinalizerThreadOK = FALSE;
VOID FinalizerThread::FinalizerThreadWorker(void *args)
{
- // TODO: The following line should be removed after contract violation is fixed.
- // See bug 27409
SCAN_IGNORE_THROW;
SCAN_IGNORE_TRIGGER;
@@ -523,16 +519,6 @@ VOID FinalizerThread::FinalizerThreadWorker(void *args)
}
}
-
-// During shutdown, finalize all objects that haven't been run yet... whether reachable or not.
-void FinalizerThread::FinalizeObjectsOnShutdown(LPVOID args)
-{
- WRAPPER_NO_CONTRACT;
-
- FinalizeAllObjects(BIT_SBLK_FINALIZER_RUN);
-}
-
-
DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args)
{
ClrFlsSetThreadType (ThreadType_Finalizer);
@@ -591,7 +577,7 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args)
MHandles[kProfilingAPIAttach] = ::ProfilingAPIAttachDetach::GetAttachEvent();
GetFinalizerThread()->DisablePreemptiveGC();
#endif // FEATURE_PROFAPI_ATTACH_DETACH
-
+
while (!fQuitFinalizer)
{
// This will apply any policy for swallowing exceptions during normal
@@ -605,67 +591,12 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args)
EnableFinalization();
}
- // Tell shutdown thread we are done with finalizing dead objects.
- hEventFinalizerToShutDown->Set();
-
- // Wait for shutdown thread to signal us.
- GetFinalizerThread()->EnablePreemptiveGC();
- hEventShutDownToFinalizer->Wait(INFINITE,FALSE);
- GetFinalizerThread()->DisablePreemptiveGC();
-
AppDomain::RaiseExitProcessEvent();
- hEventFinalizerToShutDown->Set();
-
- // Phase 1 ends.
- // Now wait for Phase 2 signal.
-
- // Wait for shutdown thread to signal us.
- GetFinalizerThread()->EnablePreemptiveGC();
- hEventShutDownToFinalizer->Wait(INFINITE,FALSE);
- GetFinalizerThread()->DisablePreemptiveGC();
-
// We have been asked to quit, so must be shutting down
_ASSERTE(g_fEEShutDown);
_ASSERTE(GetFinalizerThread()->PreemptiveGCDisabled());
- if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_FinalizeOnShutdown) != 0)
- {
- // Finalize all registered objects during shutdown, even they are still reachable.
- GCHeapUtilities::GetGCHeap()->SetFinalizeQueueForShutdown(FALSE);
-
- // This will apply any policy for swallowing exceptions during normal
- // processing, without allowing the finalizer thread to disappear on us.
- ManagedThreadBase::FinalizerBase(FinalizeObjectsOnShutdown);
- }
-
- _ASSERTE(GetFinalizerThread()->GetDomain()->IsDefaultDomain());
-
- // we might want to do some extra work on the finalizer thread
- // check and do it
- if (GetFinalizerThread()->HaveExtraWorkForFinalizer())
- {
- GetFinalizerThread()->DoExtraWorkForFinalizer();
- }
-
- hEventFinalizerToShutDown->Set();
-
- // Wait for shutdown thread to signal us.
- GetFinalizerThread()->EnablePreemptiveGC();
- hEventShutDownToFinalizer->Wait(INFINITE,FALSE);
- GetFinalizerThread()->DisablePreemptiveGC();
-
-#ifdef FEATURE_COMINTEROP
- // Do extra cleanup for part 1 of shutdown.
- // If we hang here (bug 87809) shutdown thread will
- // timeout on us and will proceed normally
- //
- // We cannot call CoEEShutDownCOM, since the BEGIN_EXTERNAL_ENTRYPOINT
- // will turn our call into a NOP. We can no longer execute managed
- // code for an external caller.
- InnerCoEEShutDownCOM();
-#endif // FEATURE_COMINTEROP
-
hEventFinalizerToShutDown->Set();
#ifdef _DEBUG // The only purpose of this try/finally is to trigger an assertion
@@ -729,8 +660,6 @@ void FinalizerThread::FinalizerThreadCreate()
hEventFinalizer->CreateAutoEvent(FALSE);
hEventFinalizerToShutDown = new CLREvent();
hEventFinalizerToShutDown->CreateAutoEvent(FALSE);
- hEventShutDownToFinalizer = new CLREvent();
- hEventShutDownToFinalizer->CreateAutoEvent(FALSE);
_ASSERTE(g_pFinalizerThread == 0);
g_pFinalizerThread = SetupUnstartedThread();
@@ -833,335 +762,3 @@ void FinalizerThread::FinalizerThreadWait(DWORD timeout)
}
}
}
-
-
-#ifdef _DEBUG
-#define FINALIZER_WAIT_TIMEOUT 250
-#else
-#define FINALIZER_WAIT_TIMEOUT 200
-#endif
-#define FINALIZER_TOTAL_WAIT 2000
-
-static BOOL s_fRaiseExitProcessEvent = FALSE;
-static DWORD dwBreakOnFinalizeTimeOut = (DWORD) -1;
-
-static ULONGLONG ShutdownEnd;
-
-
-BOOL FinalizerThread::FinalizerThreadWatchDog()
-{
- Thread *pThread = GetThread();
-
- if (dwBreakOnFinalizeTimeOut == (DWORD) -1) {
- dwBreakOnFinalizeTimeOut = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BreakOnFinalizeTimeOut);
- }
-
- // Do not wait for FinalizerThread if the current one is FinalizerThread.
- if (pThread == GetFinalizerThread())
- return TRUE;
-
- // If finalizer thread is gone, just return.
- if (GetFinalizerThread()->Join (0, FALSE) != WAIT_TIMEOUT)
- return TRUE;
-
- // *** This is the first call ShutDown -> Finalizer to Finilize dead objects ***
- if ((g_fEEShutDown & ShutDown_Finalize1) &&
- !(g_fEEShutDown & ShutDown_Finalize2)) {
- ShutdownEnd = CLRGetTickCount64() + GetEEPolicy()->GetTimeout(OPR_ProcessExit);
- // Wait for the finalizer...
- LOG((LF_GC, LL_INFO10, "Signalling finalizer to quit..."));
-
- fQuitFinalizer = TRUE;
- hEventFinalizerDone->Reset();
- EnableFinalization();
-
- LOG((LF_GC, LL_INFO10, "Waiting for finalizer to quit..."));
-
- if (pThread)
- {
- pThread->EnablePreemptiveGC();
- }
-
- BOOL fTimeOut = FinalizerThreadWatchDogHelper();
-
- if (!fTimeOut) {
- hEventShutDownToFinalizer->Set();
-
- // Wait for finalizer thread to finish raising ExitProcess Event.
- s_fRaiseExitProcessEvent = TRUE;
- fTimeOut = FinalizerThreadWatchDogHelper();
- s_fRaiseExitProcessEvent = FALSE;
- }
-
- if (pThread)
- {
- pThread->DisablePreemptiveGC();
- }
-
- // Can not call ExitProcess here if we are in a hosting environment.
- // The host does not expect that we terminate the process.
- //if (fTimeOut)
- //{
- //::ExitProcess (GetLatchedExitCode());
- //}
-
- return !fTimeOut;
- }
-
- // *** This is the second call ShutDown -> Finalizer to ***
- // suspend the Runtime and Finilize live objects
- if ( g_fEEShutDown & ShutDown_Finalize2 &&
- !(g_fEEShutDown & ShutDown_COM) ) {
-
-#ifdef BACKGROUND_GC
- gc_heap::gc_can_use_concurrent = FALSE;
-
- if (pGenGCHeap->settings.concurrent)
- pGenGCHeap->background_gc_wait();
-#endif //BACKGROUND_GC
-
- _ASSERTE((g_fEEShutDown & ShutDown_Finalize1) || g_fFastExitProcess);
-
- if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_FinalizeOnShutdown) != 0)
- {
- // When running finalizers on shutdown (including for reachable objects), suspend threads for shutdown before
- // running finalizers, so that the reachable objects will not be used after they are finalized.
-
- ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_SHUTDOWN);
-
- g_fSuspendOnShutdown = TRUE;
-
- // Do not balance the trap returning threads.
- // We are shutting down CLR. Only Finalizer/Shutdown threads can
- // return from DisablePreemptiveGC.
- ThreadStore::TrapReturningThreads(TRUE);
-
- ThreadSuspend::RestartEE(FALSE, TRUE);
- }
-
- if (g_fFastExitProcess)
- {
- return TRUE;
- }
-
- // !!! Before we wake up Finalizer thread, we need to enable preemptive gc on the
- // !!! shutdown thread. Otherwise we may see a deadlock during debug test.
- if (pThread)
- {
- pThread->EnablePreemptiveGC();
- }
-
- GCHeapUtilities::GetGCHeap()->SetFinalizeRunOnShutdown(true);
-
- // Wait for finalizer thread to finish finalizing all objects.
- hEventShutDownToFinalizer->Set();
- BOOL fTimeOut = FinalizerThreadWatchDogHelper();
-
- if (!fTimeOut) {
- GCHeapUtilities::GetGCHeap()->SetFinalizeRunOnShutdown(false);
- }
-
- // Can not call ExitProcess here if we are in a hosting environment.
- // The host does not expect that we terminate the process.
- //if (fTimeOut) {
- // ::ExitProcess (GetLatchedExitCode());
- //}
-
- if (pThread)
- {
- pThread->DisablePreemptiveGC();
- }
- return !fTimeOut;
- }
-
- // *** This is the third call ShutDown -> Finalizer ***
- // to do additional cleanup
- if (g_fEEShutDown & ShutDown_COM) {
- _ASSERTE (g_fEEShutDown & (ShutDown_Finalize2 | ShutDown_Finalize1));
-
- if (pThread)
- {
- pThread->EnablePreemptiveGC();
- }
-
- GCHeapUtilities::GetGCHeap()->SetFinalizeRunOnShutdown(true);
-
- hEventShutDownToFinalizer->Set();
- DWORD status = WAIT_OBJECT_0;
- while (CLREventWaitWithTry(hEventFinalizerToShutDown, FINALIZER_WAIT_TIMEOUT, TRUE, &status))
- {
- }
-
- BOOL fTimeOut = (status == WAIT_TIMEOUT) ? TRUE : FALSE;
-
- if (fTimeOut)
- {
- if (dwBreakOnFinalizeTimeOut) {
- LOG((LF_GC, LL_INFO10, "Finalizer took too long to clean up COM IP's.\n"));
- DebugBreak();
- }
- }
-
- if (pThread)
- {
- pThread->DisablePreemptiveGC();
- }
-
- return !fTimeOut;
- }
-
- _ASSERTE(!"Should never reach this point");
- return FALSE;
-}
-
-BOOL FinalizerThread::FinalizerThreadWatchDogHelper()
-{
- // Since our thread is blocking waiting for the finalizer thread, we must be in preemptive GC
- // so that we don't in turn block the finalizer on us in a GC.
- Thread *pCurrentThread;
- pCurrentThread = GetThread();
- _ASSERTE (pCurrentThread == NULL || !pCurrentThread->PreemptiveGCDisabled());
-
- // We're monitoring the finalizer thread.
- Thread *pThread = GetFinalizerThread();
- _ASSERTE(pThread != pCurrentThread);
-
- ULONGLONG dwBeginTickCount = CLRGetTickCount64();
-
- size_t prevCount;
- size_t curCount;
- BOOL fTimeOut = FALSE;
- DWORD nTry = 0;
- DWORD maxTotalWait = (DWORD)(ShutdownEnd - dwBeginTickCount);
- DWORD totalWaitTimeout;
- totalWaitTimeout = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
- if (totalWaitTimeout == (DWORD)-1)
- {
- totalWaitTimeout = FINALIZER_TOTAL_WAIT;
- }
-
- if (s_fRaiseExitProcessEvent)
- {
- DWORD tmp = maxTotalWait/20; // Normally we assume 2 seconds timeout if total timeout is 40 seconds.
- if (tmp > totalWaitTimeout)
- {
- totalWaitTimeout = tmp;
- }
- prevCount = MAXLONG;
- }
- else
- {
- prevCount = GCHeapUtilities::GetGCHeap()->GetNumberOfFinalizable();
- }
-
- DWORD maxTry = (DWORD)(totalWaitTimeout*1.0/FINALIZER_WAIT_TIMEOUT + 0.5);
- BOOL bAlertable = TRUE; //(g_fEEShutDown & ShutDown_Finalize2) ? FALSE:TRUE;
-
- if (dwBreakOnFinalizeTimeOut == (DWORD) -1) {
- dwBreakOnFinalizeTimeOut = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_BreakOnFinalizeTimeOut);
- }
-
- DWORD dwTimeout = FINALIZER_WAIT_TIMEOUT;
-
- // This used to set the dwTimeout to infinite, but this can cause a hang when shutting down
- // if a finalizer tries to take a lock that another suspended managed thread already has.
- // This results in the hang because the other managed thread is never going to be resumed
- // because we're in shutdown. So we make a compromise here - make the timeout for every
- // iteration 10 times longer and make the total wait infinite - so if things hang we will
- // eventually shutdown but we also give things a chance to finish if they're running slower
- // because of the profiler.
-#ifdef PROFILING_SUPPORTED
- if (CORProfilerPresent())
- {
- dwTimeout *= 10;
- maxTotalWait = INFINITE;
- }
-#endif // PROFILING_SUPPORTED
-
- // This change was added late in Windows Phone 8, so we want to keep it minimal.
- // We should consider refactoring this later, as we've got a lot of dead code here now on CoreCLR.
- dwTimeout = INFINITE;
- maxTotalWait = INFINITE;
-
- while (1) {
- struct Param
- {
- DWORD status;
- DWORD dwTimeout;
- BOOL bAlertable;
- } param;
- param.status = 0;
- param.dwTimeout = dwTimeout;
- param.bAlertable = bAlertable;
-
- PAL_TRY(Param *, pParam, &param)
- {
- pParam->status = hEventFinalizerToShutDown->Wait(pParam->dwTimeout, pParam->bAlertable);
- }
- PAL_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
- {
- param.status = WAIT_TIMEOUT;
- }
- PAL_ENDTRY
-
- if (param.status != WAIT_TIMEOUT) {
- break;
- }
- nTry ++;
- // ExitProcessEventCount is incremental
- // FinalizableObjects is decremental
- if (s_fRaiseExitProcessEvent)
- {
- curCount = MAXLONG - GetProcessedExitProcessEventCount();
- }
- else
- {
- curCount = GCHeapUtilities::GetGCHeap()->GetNumberOfFinalizable();
- }
-
- if ((prevCount <= curCount)
- && !GCHeapUtilities::GetGCHeap()->ShouldRestartFinalizerWatchDog()
- && (pThread == NULL || !(pThread->m_State & (Thread::TS_UserSuspendPending | Thread::TS_DebugSuspendPending)))){
- if (nTry == maxTry) {
- if (!s_fRaiseExitProcessEvent) {
- LOG((LF_GC, LL_INFO10, "Finalizer took too long on one object.\n"));
- }
- else
- LOG((LF_GC, LL_INFO10, "Finalizer took too long to process ExitProcess event.\n"));
-
- fTimeOut = TRUE;
- if (dwBreakOnFinalizeTimeOut != 2) {
- break;
- }
- }
- }
- else
- {
- nTry = 0;
- prevCount = curCount;
- }
- ULONGLONG dwCurTickCount = CLRGetTickCount64();
- if (pThread && pThread->m_State & (Thread::TS_UserSuspendPending | Thread::TS_DebugSuspendPending)) {
- // CoreCLR does not support user-requested thread suspension
- _ASSERTE(!(pThread->m_State & Thread::TS_UserSuspendPending));
- dwBeginTickCount = dwCurTickCount;
- }
- if (dwCurTickCount - dwBeginTickCount >= maxTotalWait)
- {
- LOG((LF_GC, LL_INFO10, "Finalizer took too long on shutdown.\n"));
- fTimeOut = TRUE;
- if (dwBreakOnFinalizeTimeOut != 2) {
- break;
- }
- }
- }
-
- if (fTimeOut)
- {
- if (dwBreakOnFinalizeTimeOut){
- DebugBreak();
- }
- }
-
- return fTimeOut;
-}
diff --git a/src/vm/finalizerthread.h b/src/vm/finalizerthread.h
index f11dd15209..d5063b2166 100644
--- a/src/vm/finalizerthread.h
+++ b/src/vm/finalizerthread.h
@@ -8,16 +8,14 @@
class FinalizerThread
{
- static BOOL fRunFinalizersOnUnload;
static BOOL fQuitFinalizer;
-
+
#if defined(__linux__) && defined(FEATURE_EVENT_TRACE)
static ULONGLONG LastHeapDumpTime;
#endif
static CLREvent *hEventFinalizer;
static CLREvent *hEventFinalizerDone;
- static CLREvent *hEventShutDownToFinalizer;
static CLREvent *hEventFinalizerToShutDown;
// Note: This enum makes it easier to read much of the code that deals with the
@@ -40,8 +38,6 @@ class FinalizerThread
static void WaitForFinalizerEvent (CLREvent *event);
- static BOOL FinalizerThreadWatchDogHelper();
-
#ifdef FEATURE_PROFAPI_ATTACH_DETACH
static void ProcessProfilerAttachIfNecessary(ULONGLONG * pui64TimestampLastCheckedEventMs);
#endif // FEATURE_PROFAPI_ATTACH_DETACH
@@ -64,6 +60,17 @@ public:
static BOOL HaveExtraWorkForFinalizer();
+ static void RaiseShutdownEvents()
+ {
+ WRAPPER_NO_CONTRACT;
+ fQuitFinalizer = TRUE;
+ EnableFinalization();
+
+ // Do not wait for FinalizerThread if the current one is FinalizerThread.
+ if (GetThread() != GetFinalizerThread())
+ hEventFinalizerToShutDown->Wait(INFINITE,FALSE);
+ }
+
static void FinalizerThreadWait(DWORD timeout = INFINITE);
// We wake up a wait for finaliation for two reasons:
@@ -72,11 +79,9 @@ public:
static void SignalFinalizationDone(BOOL fFinalizer);
static VOID FinalizerThreadWorker(void *args);
- static void FinalizeObjectsOnShutdown(LPVOID args);
static DWORD WINAPI FinalizerThreadStart(void *args);
static void FinalizerThreadCreate();
- static BOOL FinalizerThreadWatchDog();
};
#endif // _FINALIZER_THREAD_H_
diff --git a/src/vm/frames.cpp b/src/vm/frames.cpp
index af41def0c1..f44f32a4c2 100644
--- a/src/vm/frames.cpp
+++ b/src/vm/frames.cpp
@@ -311,14 +311,6 @@ void Frame::Init()
} // void Frame::Init()
-// static
-void Frame::Term()
-{
- LIMITED_METHOD_CONTRACT;
- delete s_pFrameVTables;
- s_pFrameVTables = NULL;
-}
-
#endif // DACCESS_COMPILE
// Returns true if the Frame's VTablePtr is valid
diff --git a/src/vm/frames.h b/src/vm/frames.h
index 5cc5e37d5e..d219ac30a5 100644
--- a/src/vm/frames.h
+++ b/src/vm/frames.h
@@ -543,7 +543,6 @@ public:
static bool HasValidVTablePtr(Frame * pFrame);
static PTR_GSCookie SafeGetGSCookiePtr(Frame * pFrame);
static void Init();
- static void Term();
// Callers, note that the REGDISPLAY parameter is actually in/out. While
// UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index 43976a91ff..70c26118ea 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -5213,12 +5213,6 @@ DEBUG_NOINLINE void ThreadStore::Enter()
ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
CHECK_ONE_STORE();
m_Crst.Enter();
-
- // Threadstore needs special shutdown handling.
- if (g_fSuspendOnShutdown)
- {
- m_Crst.ReleaseAndBlockForShutdownIfNotSpecialThread();
- }
}
DEBUG_NOINLINE void ThreadStore::Leave()
diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp
index 1fee3b760c..9760fe4293 100644
--- a/src/vm/threadsuspend.cpp
+++ b/src/vm/threadsuspend.cpp
@@ -1356,7 +1356,6 @@ Thread::UserAbort(ThreadAbortRequester requester,
case eExitProcess:
case eFastExitProcess:
case eRudeExitProcess:
- case eDisableRuntime:
GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT);
_ASSERTE (!"Should not reach here");
@@ -1986,7 +1985,6 @@ LPrepareRetry:
case eExitProcess:
case eFastExitProcess:
case eRudeExitProcess:
- case eDisableRuntime:
GetEEPolicy()->NotifyHostOnTimeout(operation1, action1);
EEPolicy::HandleExitProcessFromEscalation(action1, HOST_E_EXITPROCESS_TIMEOUT);
_ASSERTE (!"Should not reach here");
@@ -2543,9 +2541,8 @@ void Thread::RareDisablePreemptiveGC()
// Note IsGCInProgress is also true for say Pause (anywhere SuspendEE happens) and GCThread is the
// thread that did the Pause. While in Pause if another thread attempts Rev/Pinvoke it should get inside the following and
// block until resume
- if (((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) ||
- (m_State & (TS_UserSuspendPending | TS_DebugSuspendPending | TS_StackCrawlNeeded))) &&
- (!g_fSuspendOnShutdown || IsFinalizerThread() || IsShutdownSpecialThread()))
+ if ((GCHeapUtilities::IsGCInProgress() && (this != ThreadSuspend::GetSuspensionThread())) ||
+ (m_State & (TS_UserSuspendPending | TS_DebugSuspendPending | TS_StackCrawlNeeded)))
{
if (!ThreadStore::HoldingThreadStore(this))
{
@@ -2653,47 +2650,6 @@ void Thread::RareDisablePreemptiveGC()
STRESS_LOG0(LF_SYNC, LL_INFO1000, "RareDisablePreemptiveGC: leaving\n");
}
- // Block all threads except finalizer and shutdown thread during shutdown.
- // If g_fSuspendFinalizerOnShutdown is set, block the finalizer too.
- if ((g_fSuspendOnShutdown && !IsFinalizerThread() && !IsShutdownSpecialThread()) ||
- (g_fSuspendFinalizerOnShutdown && IsFinalizerThread()))
- {
- STRESS_LOG1(LF_SYNC, LL_INFO1000, "RareDisablePreemptiveGC: entering. Thread state = %x\n", m_State.Load());
-
- EnablePreemptiveGC();
-
- // Cannot use GCX_PREEMP_NO_DTOR here because we're inside of the thread
- // PREEMP->COOP switch mechanism and GCX_PREEMP's assert's will fire.
- // Instead we use BEGIN_GCX_ASSERT_PREEMP to inform Scan of the mode
- // change here.
- BEGIN_GCX_ASSERT_PREEMP;
-
-#ifdef PROFILING_SUPPORTED
- // If profiler desires GC events, notify it that this thread is waiting until the GC is over
- // Do not send suspend notifications for debugger suspensions
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackSuspends());
- if (!(m_State & TS_DebugSuspendPending))
- {
- g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this);
- }
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
-
-
- // The thread is blocked for shutdown. We do not concern for GC violation.
- CONTRACT_VIOLATION(GCViolation);
-
- WaitForEndOfShutdown();
-
- END_GCX_ASSERT_PREEMP;
-
- __SwitchToThread(INFINITE, CALLER_LIMITS_SPINNING);
- _ASSERTE(!"Cannot reach here");
- }
-
Exit: ;
END_PRESERVE_LAST_ERROR;
}
@@ -2740,7 +2696,6 @@ void Thread::HandleThreadAbortTimeout()
case eExitProcess:
case eFastExitProcess:
case eRudeExitProcess:
- case eDisableRuntime:
GetEEPolicy()->NotifyHostOnTimeout(operation,action);
EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT);
_ASSERTE (!"Should not reach here");
@@ -2844,7 +2799,6 @@ void Thread::PreWorkForThreadAbort()
case eExitProcess:
case eFastExitProcess:
case eRudeExitProcess:
- case eDisableRuntime:
{
GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ThreadRudeAbortInCriticalRegion,action);
GetEEPolicy()->HandleExitProcessFromEscalation(action,HOST_E_EXITPROCESS_ADUNLOAD);
diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp
index 68473b6c1a..e4b790836e 100644
--- a/src/vm/vars.hpp
+++ b/src/vm/vars.hpp
@@ -529,10 +529,6 @@ EXTERN BOOL g_fComStarted;
GVAL_DECL(DWORD, g_fEEShutDown);
EXTERN DWORD g_fFastExitProcess;
EXTERN BOOL g_fFatalErrorOccurredOnGCThread;
-#ifndef DACCESS_COMPILE
-EXTERN BOOL g_fSuspendOnShutdown;
-EXTERN BOOL g_fSuspendFinalizerOnShutdown;
-#endif // DACCESS_COMPILE
EXTERN Volatile<LONG> g_fForbidEnterEE;
GVAL_DECL(bool, g_fProcessDetach);
EXTERN bool g_fManagedAttach;
diff --git a/src/vm/win32threadpool.cpp b/src/vm/win32threadpool.cpp
index b5014962d2..f340542b0c 100644
--- a/src/vm/win32threadpool.cpp
+++ b/src/vm/win32threadpool.cpp
@@ -3094,12 +3094,7 @@ void ThreadpoolMgr::DeregisterWait(WaitInfo* pArgs)
if (InterlockedDecrement(&waitInfo->refCount) == 0)
{
- // After we suspend EE during shutdown, a thread may be blocked in WaitForEndOfShutdown in alertable state.
- // We don't allow a thread reenter runtime while processing APC or pumping message.
- if (!g_fSuspendOnShutdown )
- {
- DeleteWait(waitInfo);
- }
+ DeleteWait(waitInfo);
}
return;
}