Skip to content

Commit

Permalink
Remove shutdown finalization
Browse files Browse the repository at this point in the history
Remove shutdown finalization. It makes CoreRT/PN consistent with .NETCore / CoreCLR. The long story is in https://github.com/dotnet/corefx/issues/5205. The shutdown finalization was not used by UWP apps because they are never shutdown gracefully.

[tfs-changeset: 1597160]
  • Loading branch information
jkotas committed Apr 19, 2016
1 parent a3340a1 commit 802eb6a
Show file tree
Hide file tree
Showing 14 changed files with 9 additions and 231 deletions.
7 changes: 4 additions & 3 deletions src/Native/Runtime/FinalizerHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,22 @@ EXTERN_C REDHAWK_API void __cdecl RhpSignalFinalizationComplete()
FinalizerThread::SignalFinalizationDone(TRUE);
}

#ifndef CORERT // @TODO: Remove on next breaking change sweep
#ifdef FEATURE_PREMORTEM_FINALIZATION
// Enable a last pass of the finalizer during (clean) runtime shutdown. Specify the number of milliseconds
// we'll wait before giving up a proceeding with the shutdown (INFINITE is an allowable value).
COOP_PINVOKE_HELPER(void, RhEnableShutdownFinalization, (UInt32 uiTimeout))
{
g_fPerformShutdownFinalization = true;
g_uiShutdownFinalizationTimeout = uiTimeout;
UNREFERENCED_PARAMETER(uiTimeout);
}

// Returns true when shutdown has started and it is no longer safe to access other objects from finalizers.
COOP_PINVOKE_HELPER(UInt8, RhHasShutdownStarted, ())
{
return g_fShutdownHasStarted ? 1 : 0;
return 0;
}
#endif // FEATURE_PREMORTEM_FINALIZATION
#endif

//
// The following helpers are special in that they interact with internal GC state or directly manipulate
Expand Down
22 changes: 0 additions & 22 deletions src/Native/Runtime/amd64/MiscStubs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,12 @@

include AsmMacros.inc

EXTERN RhpShutdownHelper : PROC
EXTERN GetClasslibCCtorCheck : PROC
EXTERN memcpy : PROC
EXTERN memcpyGCRefs : PROC
EXTERN memcpyGCRefsWithWriteBarrier : PROC
EXTERN memcpyAnyWithWriteBarrier : PROC

;;
;; Currently called only from a managed executable once Main returns, this routine does whatever is needed to
;; cleanup managed state before exiting.
;;
;; Input:
;; rcx : Process exit code
;;
NESTED_ENTRY RhpShutdown, _TEXT

INLINE_GETTHREAD rax, r10 ; rax <- Thread pointer, r10 <- trashed
PUSH_COOP_PINVOKE_FRAME rax, r10, no_extraStack ; rax <- in: Thread, out: trashed, r10 <- trashed
END_PROLOGUE

;; Call the bulk of the helper implemented in C++. Takes the exit code already in rcx.
call RhpShutdownHelper

POP_COOP_PINVOKE_FRAME no_extraStack
ret

NESTED_END RhpShutdown, _TEXT

;;
;; Checks whether the static class constructor for the type indicated by the context structure has been
;; executed yet. If not the classlib is called via their CheckStaticClassConstruction callback which will
Expand Down
19 changes: 0 additions & 19 deletions src/Native/Runtime/arm/MiscStubs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include "AsmMacros.h"

EXTERN RhpShutdownHelper
EXTERN GetClasslibCCtorCheck
EXTERN memcpy
EXTERN memcpyGCRefs
Expand All @@ -13,24 +12,6 @@

TEXTAREA

;;
;; Currently called only from a managed executable once Main returns, this routine does whatever is needed to
;; cleanup managed state before exiting.
;;
;; Input:
;; r0 : Process exit code
;;
NESTED_ENTRY RhpShutdown

COOP_PINVOKE_FRAME_PROLOG

;; Call the bulk of the helper implemented in C++. Takes the exit code already in r0.
bl RhpShutdownHelper

COOP_PINVOKE_FRAME_EPILOG

NESTED_END RhpShutdown

;;
;; Checks whether the static class constructor for the type indicated by the context structure has been
;; executed yet. If not the classlib is called via their CheckStaticClassConstruction callback which will
Expand Down
20 changes: 0 additions & 20 deletions src/Native/Runtime/gcenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,26 +227,6 @@ class SyncBlockCache

#endif // VERIFY_HEAP

//
// -----------------------------------------------------------------------------------------------------------
//
// Support for shutdown finalization, which is off by default but can be enabled by the class library.
//

// If true runtime shutdown will attempt to finalize all finalizable objects (even those still rooted).
extern bool g_fPerformShutdownFinalization;

// Time to wait (in milliseconds) for the above finalization to complete before giving up and proceeding with
// shutdown. Can specify INFINITE for no timeout.
extern UInt32 g_uiShutdownFinalizationTimeout;

// Flag set to true once we've begun shutdown (and before shutdown finalization begins). This is exported to
// the class library so that managed code can tell when it is safe to access other objects from finalizers.
extern bool g_fShutdownHasStarted;




EXTERN_C UInt32 _tls_index;
inline UInt16 GetClrInstanceId()
{
Expand Down
92 changes: 0 additions & 92 deletions src/Native/Runtime/gcrhenv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -925,40 +925,11 @@ COOP_PINVOKE_HELPER(void, RhUnbox, (Object * pObj, void * pData, EEType * pUnbox
}
}

#endif // !DACCESS_COMPILE

//
// -----------------------------------------------------------------------------------------------------------
//
// Support for shutdown finalization, which is off by default but can be enabled by the class library.
//

// If true runtime shutdown will attempt to finalize all finalizable objects (even those still rooted).
bool g_fPerformShutdownFinalization = false;

// Time to wait (in milliseconds) for the above finalization to complete before giving up and proceeding with
// shutdown. Can specify INFINITE for no timeout.
UInt32 g_uiShutdownFinalizationTimeout = 0;

// Flag set to true once we've begun shutdown (and before shutdown finalization begins). This is exported to
// the class library so that managed code can tell when it is safe to access other objects from finalizers.
bool g_fShutdownHasStarted = false;

#ifndef DACCESS_COMPILE
Thread * GetThread()
{
return ThreadStore::GetCurrentThread();
}

// If the class library has requested it, call this method on clean shutdown (i.e. return from Main) to
// perform a final pass of finalization where all finalizable objects are processed regardless of whether
// they are still rooted.
// static
void RedhawkGCInterface::ShutdownFinalization()
{
FinalizerThread::WatchDog();
}

// Thread static representing the last allocation.
// This is used to log the type information for each slow allocation.
DECLSPEC_THREAD
Expand Down Expand Up @@ -1253,69 +1224,6 @@ HANDLE FinalizerThread::GetFinalizerEvent()
return hEventFinalizer->GetOSEvent();
}

// This is called during runtime shutdown to perform a final finalization run with all pontentially
// finalizable objects being finalized (as if their roots had all been cleared). The default behaviour is to
// skip this step, the classlib has to make an explicit request for this functionality and also specifies the
// maximum amount of time it will let the finalization take before we will give up and just let the shutdown
// proceed.
bool FinalizerThread::WatchDog()
{
// Set the flag indicating that shutdown has started. This is only of interest to managed code running
// finalizers as it lets them know when it is no longer safe to access other objects (which from this
// point on can be finalized even if you hold a reference to them).
g_fShutdownHasStarted = true;

if (g_fPerformShutdownFinalization)
{
#ifdef BACKGROUND_GC
// Switch off concurrent GC if necessary.
gc_heap::gc_can_use_concurrent = FALSE;

if (pGenGCHeap->settings.concurrent)
pGenGCHeap->background_gc_wait();
#endif //BACKGROUND_GC

DWORD dwTimeout = g_uiShutdownFinalizationTimeout;

// Wait for any outstanding finalization run to complete. Time this initial operation so that it forms
// part of the overall timeout budget.
DWORD dwStartTime = PalGetTickCount();
Wait(dwTimeout);
DWORD dwEndTime = PalGetTickCount();

// In the exceedingly rare case that the tick count wrapped then we'll just reset the timeout to its
// initial value. Otherwise we'll subtract the time we waited from the timeout budget (being mindful
// of the fact that we might have waited slightly longer than the timeout specified).
if (dwTimeout != INFINITE)
{
if (dwEndTime < dwStartTime)
dwTimeout = g_uiShutdownFinalizationTimeout;
else
dwTimeout -= min(dwTimeout, dwEndTime - dwStartTime);

if (dwTimeout == 0)
return false;
}

// Inform the GC that all finalizable objects should now be placed in the queue for finalization. FALSE
// here means we don't hold the finalizer lock (so the routine will take it for us).
GCHeap::GetGCHeap()->SetFinalizeQueueForShutdown(FALSE);

// Wait for the finalizer to process all of these objects.
Wait(dwTimeout);

if (dwTimeout == INFINITE)
return true;

// Do a zero timeout wait of the finalizer done event to determine if we timed out above (we don't
// want to modify the signature of GCHeap::FinalizerThreadWait to return this data since that bleeds
// into a CLR visible change to gc.h which is not really worth it for this minor case).
return hEventFinalizerDone->Wait(0, FALSE) == WAIT_OBJECT_0;
}

return true;
}

void FinalizerThread::Wait(DWORD timeout, bool allowReentrantWait)
{
// Can't call this from the finalizer thread itself.
Expand Down
5 changes: 0 additions & 5 deletions src/Native/Runtime/gcrhinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,6 @@ class RedhawkGCInterface
static GcScanObjectFunction GetCurrentScanCallbackFunction();
static void* GetCurrentScanContext();

// If the class library has requested it, call this method on clean shutdown (i.e. return from Main) to
// perform a final pass of finalization where all finalizable objects are processed regardless of whether
// they are still rooted.
static void ShutdownFinalization();

// Returns size GCDesc. Used by type cloning.
static UInt32 GetGCDescSize(void * pType);

Expand Down
33 changes: 0 additions & 33 deletions src/Native/Runtime/i386/MiscStubs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,12 @@

include AsmMacros.inc

EXTERN @RhpShutdownHelper@4 : PROC
EXTERN @GetClasslibCCtorCheck@4 : PROC
EXTERN _memcpy : PROC
EXTERN _memcpyGCRefs : PROC
EXTERN _memcpyGCRefsWithWriteBarrier : PROC
EXTERN _memcpyAnyWithWriteBarrier : PROC

;;
;; Currently called only from a managed executable once Main returns, this routine does whatever is needed to
;; cleanup managed state before exiting. This routine never returns.
;;
;; Input:
;; ecx : Process exit code
;;
FASTCALL_FUNC RhpShutdown, 4

;; Build an EBP frame, mostly so we get a good stack trace during debugging.
push ebp
mov ebp, esp

;; edx = GetThread(), TRASHES eax
INLINE_GETTHREAD edx, eax

;; Save managed state in a frame and update the thread so it can find this frame once we transition to
;; pre-emptive mode in the garbage collection.
PUSH_COOP_PINVOKE_FRAME edx

;; Call the bulk of the helper implemented in C++. Takes the exit code already in ecx.
call @RhpShutdownHelper@4

;; Restore register state.
POP_COOP_PINVOKE_FRAME

;; Epilog, tear down EBP frame and return.
pop ebp
ret

FASTCALL_ENDFUNC

;;
;; Checks whether the static class constructor for the type indicated by the context structure has been
;; executed yet. If not the classlib is called via their CheckStaticClassConstruction callback which will
Expand Down
5 changes: 1 addition & 4 deletions src/Native/Runtime/startup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,8 @@ HANDLE RtuCreateRuntimeInstance(HANDLE hPalInstance)
// @TODO: Eventually we'll probably have a hosting API and explicit shutdown request. When that happens we'll
// something more sophisticated here since we won't be able to rely on the OS cleaning up after us.
//
COOP_PINVOKE_HELPER(void, RhpShutdownHelper, (UInt32 /*uExitCode*/))
COOP_PINVOKE_HELPER(void, RhpShutdown, ())
{
// If the classlib has requested it perform a last pass of the finalizer thread.
RedhawkGCInterface::ShutdownFinalization();

#ifdef FEATURE_PROFILING
GetRuntimeInstance()->WriteProfileInfo();
#endif // FEATURE_PROFILING
Expand Down
1 change: 0 additions & 1 deletion src/Native/gc/env/gcenv.base.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,6 @@ class FinalizerThread

static bool IsCurrentThreadFinalizer();
static void Wait(DWORD timeout, bool allowReentrantWait = false);
static bool WatchDog();
static void SignalFinalizationDone(bool fFinalizer);
static void SetFinalizerThread(Thread * pThread);
static HANDLE GetFinalizerEvent();
Expand Down
2 changes: 1 addition & 1 deletion src/Runtime.Base/src/System/Runtime/RuntimeExports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace System.Runtime
{
internal static class RuntimeExports
{
#if !CORERT
#if !CORERT // @TODO: Remove on next breaking change sweep
//
// internalcalls for System.Runtime.InteropServices.GCHandle.
//
Expand Down
2 changes: 0 additions & 2 deletions src/System.Private.CoreLib/src/MembersMustExist.AnalyzerData
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ internal static extern void System.Runtime.RuntimeImports.RhCheckArrayStore(obje
internal static extern void System.Runtime.RuntimeImports.RhCollect(int generation, System.InternalGCCollectionMode mode)
private static extern int System.Runtime.RuntimeImports.RhCompatibleReentrantWaitAny(int alertable, int timeout, int count, System.IntPtr* handles)
internal static extern bool System.Runtime.RuntimeImports.RhCreateGenericInstanceDescForType2(System.EETypePtr pEEType, int arity, int nonGcStaticDataSize, int nonGCStaticDataOffset, int gcStaticDataSize, int threadStaticsOffset, void* pGcStaticsDesc, void* pThreadStaticsDesc, int* pGenericVarianceFlags)
internal static extern void System.Runtime.RuntimeImports.RhEnableShutdownFinalization(uint timeout)
internal static extern bool System.Runtime.RuntimeImports.RhFindBlob(System.IntPtr hOsModule, uint blobId, byte** ppbBlob, uint* pcbBlob)
internal static extern System.IntPtr System.Runtime.RuntimeImports.RhFindMethodStartAddress(System.IntPtr codeAddr)
internal static extern System.IntPtr System.Runtime.RuntimeImports.RhGetCodeTarget(System.IntPtr pCode)
Expand Down Expand Up @@ -167,7 +166,6 @@ internal static extern void System.Runtime.RuntimeImports.RhHandleSetDependentSe
internal static extern void System.Runtime.RuntimeImports.RhHandleSetVariableType(System.IntPtr handle, uint type)
internal static extern bool System.Runtime.RuntimeImports.RhHasCctor(System.EETypePtr pEEType)
internal static extern bool System.Runtime.RuntimeImports.RhHasReferenceFields(System.EETypePtr pEEType)
internal static extern bool System.Runtime.RuntimeImports.RhHasShutdownStarted()
internal static extern bool System.Runtime.RuntimeImports.RhIsArray(System.EETypePtr pEEType)
internal static extern bool System.Runtime.RuntimeImports.RhIsDynamicType(System.EETypePtr pEEType)
internal static extern bool System.Runtime.RuntimeImports.RhIsInterface(System.EETypePtr pEEType)
Expand Down
14 changes: 2 additions & 12 deletions src/System.Private.CoreLib/src/System/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ public static bool HasShutdownStarted
{
get
{
return RuntimeImports.RhHasShutdownStarted();
// .NET Core does not have shutdown finalization
return false;
}
}

Expand Down Expand Up @@ -118,17 +119,6 @@ public static string[] GetCommandLineArgs()
}
#endif

#if CORERT
// .NET Core abandoned shutdown finalization.
// See discussion in https://github.com/dotnet/corefx/issues/5205
// We should get rid of this in Project N too.
#else
static Environment()
{
RuntimeImports.RhEnableShutdownFinalization(0xffffffffu);
}
#endif

public static String StackTrace
{
get
Expand Down
13 changes: 1 addition & 12 deletions src/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,16 +448,8 @@ internal enum RuntimeHelperKind
internal static unsafe extern IntPtr RhGetDispatchMapForType(EETypePtr pEEType);

//
// calls to runtime for process status
// Support for GC and HandleTable callouts.
//
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhEnableShutdownFinalization")]
internal static extern void RhEnableShutdownFinalization(uint timeout);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhHasShutdownStarted")]
internal static extern bool RhHasShutdownStarted();


internal enum GcRestrictedCalloutKind
{
Expand All @@ -467,9 +459,6 @@ internal enum GcRestrictedCalloutKind
// no handles have been cleared
}

//
// Support for GC and HandleTable callouts.
//
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhRegisterGcCallout")]
internal static extern bool RhRegisterGcCallout(GcRestrictedCalloutKind eKind, IntPtr pCalloutMethod);
Expand Down
Loading

0 comments on commit 802eb6a

Please sign in to comment.