Fix Interop/PInvoke/Miscellaneous/HandleRef tests under GCStress (#21131)
[platform/upstream/coreclr.git] / tests / src / Interop / PInvoke / Miscellaneous / HandleRef / HandleRefTest.cs
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 // See the LICENSE file in the project root for more information.
4
5 using System.Runtime.InteropServices;
6 using System;
7 using System.Reflection;
8 using System.Text;
9 using TestLibrary;
10
11 class HandleRefTest
12 {
13     [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)]
14     private static extern int MarshalPointer_In(HandleRef pintValue, int stackGuard);
15
16     [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)]
17     private static extern int MarshalPointer_InOut(HandleRef pintValue, int stackGuard);
18
19     [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)]
20     private static extern int MarshalPointer_Out(HandleRef pintValue, int stackGuard);
21
22     [DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)]
23     private static extern int TestNoGC(HandleRef pintValue, Action gcCallback);
24
25     public unsafe static int Main(string[] args)
26     {
27         try{
28             const int intManaged = 1000;
29             const int intNative = 2000;
30             const int intReturn = 3000;
31             const int stackGuard = 5000;
32
33             Console.WriteLine("MarshalPointer_In");
34             int int1 = intManaged;
35             int* int1Ptr = &int1;
36             HandleRef hr1 = new HandleRef(new Object(), (IntPtr)int1Ptr);
37             Assert.AreEqual(intReturn, MarshalPointer_In(hr1, stackGuard), "The return value is wrong");
38             Assert.AreEqual(intManaged, int1, "The parameter value is changed");
39             
40             Console.WriteLine("MarshalPointer_InOut");
41             int int2 = intManaged;
42             int* int2Ptr = &int2;
43             HandleRef hr2 = new HandleRef(new Object(), (IntPtr)int2Ptr);
44             Assert.AreEqual(intReturn, MarshalPointer_InOut(hr2, stackGuard), "The return value is wrong");
45             Assert.AreEqual(intNative, int2, "The passed value is wrong");
46             
47             Console.WriteLine("MarshalPointer_Out");
48             int int3 = intManaged;
49             int* int3Ptr = &int3;
50             HandleRef hr3 = new HandleRef(new Object(), (IntPtr)int3Ptr);
51             Assert.AreEqual(intReturn, MarshalPointer_Out(hr3, stackGuard), "The return value is wrong");
52             Assert.AreEqual(intNative, int3, "The passed value is wrong");
53
54             // Note that this scenario will always pass in a debug build because all values 
55             // stay rooted until the end of the method. 
56             Console.WriteLine("TestNoGC");
57
58             int* int4Ptr = (int*)Marshal.AllocHGlobal(sizeof(int)); // We don't free this memory so we don't have to worry about a GC run between freeing and return (possible in a GCStress mode).
59             Console.WriteLine("2");
60             *int4Ptr = intManaged;
61             CollectableClass collectableClass = new CollectableClass(int4Ptr);
62             HandleRef hr4 = new HandleRef(collectableClass, (IntPtr)int4Ptr);
63             Action gcCallback = () => { Console.WriteLine("GC callback now"); GC.Collect(2, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); GC.Collect(2, GCCollectionMode.Forced); };
64             Assert.AreEqual(intReturn, TestNoGC(hr4, gcCallback), "The return value is wrong");
65             Console.WriteLine("Native code finished");
66
67             return 100;
68         } catch (Exception e){
69             Console.WriteLine($"Test Failure: {e}"); 
70             return 101; 
71         }
72     }
73
74     /// <summary>
75     /// Class that will change a pointer passed to native code when this class gets finalized.
76     /// Native code can check whether the pointer changed during a P/Invoke
77     /// </summary>
78     unsafe class CollectableClass
79     {
80         int* PtrToChange;
81         public CollectableClass(int* ptrToChange)
82         {
83             PtrToChange = ptrToChange;
84         }
85
86         ~CollectableClass()
87         {
88             Console.WriteLine("CollectableClass collected");
89             *PtrToChange = Int32.MaxValue;
90         }
91     }
92 }