blob: 0dbc18de4415c281d7b4ba471be085bfb55056a6 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
//
// Implements the single finalizer thread for a Redhawk instance. Essentially waits for an event to fire
// indicating finalization is necessary then drains the queue of pending finalizable objects, calling the
// finalize method for each one.
//
namespace System.Runtime
{
// We choose this name to avoid clashing with any future public class with the name Finalizer.
internal static class __Finalizer
{
private static bool s_fHaveNewClasslibs /* = false */;
[NativeCallable(EntryPoint = "ProcessFinalizers", CallingConvention = CallingConvention.Cdecl)]
public static void ProcessFinalizers()
{
while (true)
{
// Wait until there's some work to be done. If true is returned we should finalize objects,
// otherwise memory is low and we should initiate a collection.
if (InternalCalls.RhpWaitForFinalizerRequest() != 0)
{
if (s_fHaveNewClasslibs)
{
s_fHaveNewClasslibs = false;
MakeFinalizerInitCallbacks();
}
DrainQueue();
// Tell anybody that's interested that the finalization pass is complete (there is a race condition here
// where we might immediately signal a new request as complete, but this is acceptable).
InternalCalls.RhpSignalFinalizationComplete();
}
else
{
// RhpWaitForFinalizerRequest() returned false and indicated that memory is low. We help
// out by initiating a garbage collection and then go back to waiting for another request.
InternalCalls.RhCollect(-1, InternalGCCollectionMode.Blocking);
}
}
}
// Do not inline this method -- we do not want to accidentally have any temps in ProcessFinalizers which contain
// objects that came off of the finalizer queue. If such temps were reported across the duration of the
// finalizer thread wait operation, it could cause unpredictable behavior with weak handles.
[MethodImpl(MethodImplOptions.NoInlining)]
private static unsafe void DrainQueue()
{
// Drain the queue of finalizable objects.
while (true)
{
object target = InternalCalls.RhpGetNextFinalizableObject();
if (target == null)
return;
// Call the finalizer on the current target object. If the finalizer throws we'll fail
// fast via normal Redhawk exception semantics (since we don't attempt to catch
// anything).
CalliIntrinsics.CallVoid(target.EEType->FinalizerCode, target);
}
}
// Each class library can sign up for a callback to run code on the finalizer thread before any
// objects derived from that class library's System.Object are finalized. This is where we make those
// callbacks. When a class library is loaded, we set the s_fHasNewClasslibs flag and then the next
// time the finalizer runs, we call this function to make any outstanding callbacks.
private static unsafe void MakeFinalizerInitCallbacks()
{
while (true)
{
IntPtr pfnFinalizerInitCallback = InternalCalls.RhpGetNextFinalizerInitCallback();
if (pfnFinalizerInitCallback == IntPtr.Zero)
return;
CalliIntrinsics.CallVoid(pfnFinalizerInitCallback);
}
}
[RuntimeExport("RhpSetHaveNewClasslibs")]
public static void RhpSetHaveNewClasslibs()
{
s_fHaveNewClasslibs = true;
}
}
}
|