Skip to content

Commit 6bfb9e1

Browse files
committed
Added internal Gen2GcCallback type
1 parent 0cb2ea6 commit 6bfb9e1

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.ConstrainedExecution;
5+
using System.Runtime.InteropServices;
6+
7+
namespace System
8+
{
9+
/// <summary>
10+
/// Schedules a callback roughly every gen 2 GC (you may see a Gen 0 an Gen 1 but only once).
11+
/// Ported from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Gen2GcCallback.cs.
12+
/// </summary>
13+
internal sealed class Gen2GcCallback : CriticalFinalizerObject
14+
{
15+
/// <summary>
16+
/// The callback to invoke at each GC.
17+
/// </summary>
18+
private readonly Action<object> callback;
19+
20+
/// <summary>
21+
/// A weak <see cref="GCHandle"/> to the target object to pass to <see cref="callback"/>.
22+
/// </summary>
23+
private GCHandle handle;
24+
25+
/// <summary>
26+
/// Initializes a new instance of the <see cref="Gen2GcCallback"/> class.
27+
/// </summary>
28+
/// <param name="callback">The callback to invoke at each GC.</param>
29+
/// <param name="target">The target object to pass as argument to <paramref name="callback"/>.</param>
30+
private Gen2GcCallback(Action<object> callback, object target)
31+
{
32+
this.callback = callback;
33+
this.handle = GCHandle.Alloc(target, GCHandleType.Weak);
34+
}
35+
36+
/// <summary>
37+
/// Schedules a callback to be called on each GC until the target is collected.
38+
/// </summary>
39+
/// <param name="callback">The callback to invoke at each GC.</param>
40+
/// <param name="target">The target object to pass as argument to <paramref name="callback"/>.</param>
41+
public static void Register(Action<object> callback, object target)
42+
{
43+
_ = new Gen2GcCallback(callback, target);
44+
}
45+
46+
/// <summary>
47+
/// Finalizes an instance of the <see cref="Gen2GcCallback"/> class.
48+
/// This finalizer is re-registered with <see cref="GC.ReRegisterForFinalize(object)"/> as long as
49+
/// the target object is alive, which means it will be executed again every time a generation 2
50+
/// collection is triggered (as the <see cref="Gen2GcCallback"/> instance itself would be moved to
51+
/// that generation after surviving the generation 0 and 1 collections the first time).
52+
/// </summary>
53+
~Gen2GcCallback()
54+
{
55+
if (this.handle.Target is object target)
56+
{
57+
try
58+
{
59+
this.callback(target);
60+
}
61+
catch
62+
{
63+
}
64+
65+
GC.ReRegisterForFinalize(this);
66+
}
67+
else
68+
{
69+
handle.Free();
70+
}
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)