chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
 
namespace OpenTap
{
    internal static class PosixSignals
    { 
        public delegate void SignalCallback(dynamic signalContext);
        // Microsoft has invented their own signal codes for posix signals. Normally, SIGINT is 2, and SIGTERM is 15.
        internal const int SIGINT = -2;
        internal const int SIGTERM = -4;
 
        // Hold on to signal handlers so they don't get disposed.
        private static List<IDisposable> SignalHandlerGcHandles = new List<IDisposable>();
        
        
        private static MethodInfo signalHandlerCreateMethod = null;
        private static MethodInfo proxyInvoke = null;
        private static Type targetDelegateType = null; 
        public static void AddSignalHandler(int signal, SignalCallback callback)
        {
            if (signalHandlerCreateMethod == null)
            {
                var asm = typeof(object).Assembly;
                var type = asm.GetType("System.Runtime.InteropServices.PosixSignalRegistration")!;
                signalHandlerCreateMethod = type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public)!;
                proxyInvoke = typeof(DelegateProxy).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.NonPublic)!;
                targetDelegateType = signalHandlerCreateMethod.GetParameters()[1].ParameterType;
            }
 
            // We cannot create a signal handler without a delegate of the correct type.
            // To get this delegate, we need to create a delegate proxy with a more relaxed signature.
            var proxy = new DelegateProxy(callback); 
            Delegate d = Delegate.CreateDelegate(targetDelegateType, proxy, proxyInvoke);
            IDisposable handler = signalHandlerCreateMethod.Invoke(null, [signal, d]) as IDisposable;
            // Finally, add the handler to a list to ensure it will not be garbage collected.
            SignalHandlerGcHandles.Add(handler);
        }
 
        class DelegateProxy
        {
            private SignalCallback Proxy { get; } 
            public DelegateProxy(SignalCallback callback)
            {
                Proxy = callback;
            } 
            private void Invoke(object o)
            {
                Proxy(o);
            }
        } 
    }
}