From 97f9e376409a6851e322e3f7aaccae5819aff25b Mon Sep 17 00:00:00 2001 From: Anton Lapounov Date: Tue, 20 Sep 2022 22:34:59 -0700 Subject: [PATCH 1/3] Fix critical finalization test --- .../critical_finalization.cs | 53 -------------- .../finalization/CriticalFinalizer.cs | 72 +++++++++++++++++++ .../CriticalFinalizer.csproj} | 2 +- 3 files changed, 73 insertions(+), 54 deletions(-) delete mode 100644 src/tests/baseservices/critical_finalization/critical_finalization.cs create mode 100644 src/tests/baseservices/finalization/CriticalFinalizer.cs rename src/tests/baseservices/{critical_finalization/critical_finalization.csproj => finalization/CriticalFinalizer.csproj} (73%) diff --git a/src/tests/baseservices/critical_finalization/critical_finalization.cs b/src/tests/baseservices/critical_finalization/critical_finalization.cs deleted file mode 100644 index 553ccfc5a1b954..00000000000000 --- a/src/tests/baseservices/critical_finalization/critical_finalization.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Runtime.ConstrainedExecution; - -class P { - - static public int count = 0; - - ~P () { - count++; - } -} - -class Q : CriticalFinalizerObject { - static public int count = 0; - static public int first_p_count = -1; - static public int last_p_count = 0; - ~Q () { - count++; - if (first_p_count < 0) - first_p_count = P.count; - last_p_count = P.count; - } -} - -class T : P { - - static void makeP () { - P p = new P (); - Q q = new Q (); - p = null; - q = null; - } - - static void callMakeP () { - makeP (); - } - - static int Main () { - for (int i = 0; i < 100; ++i) - callMakeP (); - GC.Collect (); - GC.WaitForPendingFinalizers (); - Console.WriteLine (P.count); - Console.WriteLine (Q.count); - Console.WriteLine (Q.first_p_count); - Console.WriteLine (Q.last_p_count); - if (P.count == 0) - return 1; - if (Q.first_p_count < P.count) - return 1; - return 100; - } -} diff --git a/src/tests/baseservices/finalization/CriticalFinalizer.cs b/src/tests/baseservices/finalization/CriticalFinalizer.cs new file mode 100644 index 00000000000000..80107d25d69c9a --- /dev/null +++ b/src/tests/baseservices/finalization/CriticalFinalizer.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Tests a weak ordering among normal and critical finalizers: for objects reclaimed by garbage collection +// at the same time, all the noncritical finalizers must be called before any of the critical finalizers. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; + +class Normal +{ + public static int Finalized; + + ~Normal() => Finalized++; +} + +class Critical : CriticalFinalizerObject +{ + public static int Finalized; + public static int NormalFinalizedBeforeFirstCritical; + + ~Critical() + { + if (++Finalized == 1) + NormalFinalizedBeforeFirstCritical = Normal.Finalized; + } +} + +static class CriticalFinalizerTest +{ + [MethodImpl(MethodImplOptions.NoInlining)] + static void AllocateObjects(int count) + { + List list = new(); + + for (int i = 0; i < count; i++) + { + list.Add(new Normal()); + list.Add(new Critical()); + } + + GC.KeepAlive(list); + } + + static int Main() + { + const int Count = 100; + + // Allocate a bunch of Normal and Critical objects in alternating order, then unroot them + AllocateObjects(Count); + + // Force a garbage collection and wait until all finalizers are executed + GC.Collect(); + GC.WaitForPendingFinalizers(); + + // Check that all Normal objects were finalized before all Critical objects + int normalFinalized = Normal.Finalized; + int criticalFinalized = Critical.Finalized; + int normalFinalizedBeforeFirstCritical = Critical.NormalFinalizedBeforeFirstCritical; + + if (normalFinalized != Count || criticalFinalized != Count || normalFinalizedBeforeFirstCritical != Count) + { + Console.WriteLine($"Finalized {normalFinalized} {nameof(Normal)} and {criticalFinalized} {nameof(Critical)} objects."); + Console.WriteLine($"The first {nameof(Critical)} object was finalized after {normalFinalizedBeforeFirstCritical} {nameof(Normal)} objects."); + return 101; + } + + return 100; + } +} diff --git a/src/tests/baseservices/critical_finalization/critical_finalization.csproj b/src/tests/baseservices/finalization/CriticalFinalizer.csproj similarity index 73% rename from src/tests/baseservices/critical_finalization/critical_finalization.csproj rename to src/tests/baseservices/finalization/CriticalFinalizer.csproj index 295bb31a5f70ce..d83ad37e49f1d7 100644 --- a/src/tests/baseservices/critical_finalization/critical_finalization.csproj +++ b/src/tests/baseservices/finalization/CriticalFinalizer.csproj @@ -3,6 +3,6 @@ Exe - + From 87bd2f8b6e1d45f4cfb70922a01a3f515fef6932 Mon Sep 17 00:00:00 2001 From: Anton Lapounov Date: Wed, 21 Sep 2022 11:45:40 -0700 Subject: [PATCH 2/3] Update issues.targets --- src/tests/issues.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 8653f6e609172b..e6de4c3c83f152 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -3345,7 +3345,7 @@ - + https://github.com/dotnet/runtime/issues/75756 From 9b6106dd9379836a58d601667c4d278916e35fc3 Mon Sep 17 00:00:00 2001 From: Anton Lapounov Date: Wed, 21 Sep 2022 19:48:01 -0700 Subject: [PATCH 3/3] Address feedback --- .../finalization/CriticalFinalizer.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tests/baseservices/finalization/CriticalFinalizer.cs b/src/tests/baseservices/finalization/CriticalFinalizer.cs index 80107d25d69c9a..9ea7d56d881a87 100644 --- a/src/tests/baseservices/finalization/CriticalFinalizer.cs +++ b/src/tests/baseservices/finalization/CriticalFinalizer.cs @@ -1,13 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// Tests a weak ordering among normal and critical finalizers: for objects reclaimed by garbage collection +// Tests the weak ordering among normal and critical finalizers: for objects reclaimed by garbage collection // at the same time, all the noncritical finalizers must be called before any of the critical finalizers. using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; +using System.Threading.Tasks; class Normal { @@ -33,22 +34,22 @@ static class CriticalFinalizerTest [MethodImpl(MethodImplOptions.NoInlining)] static void AllocateObjects(int count) { - List list = new(); + var arr = new object[checked(count * 2)]; - for (int i = 0; i < count; i++) + Parallel.For(0, count, i => { - list.Add(new Normal()); - list.Add(new Critical()); - } + arr[i * 2] = new Normal(); + arr[i * 2 + 1] = new Critical(); + }); - GC.KeepAlive(list); + GC.KeepAlive(arr); } static int Main() { const int Count = 100; - // Allocate a bunch of Normal and Critical objects in alternating order, then unroot them + // Allocate a bunch of Normal and Critical objects, then unroot them AllocateObjects(Count); // Force a garbage collection and wait until all finalizers are executed