P / Invoke: фатальная ошибка. Недопустимая программа: попытка вызова метода NativeCallable из безопасного для времени выполнения кода - PullRequest
0 голосов
/ 28 апреля 2020

Я пытаюсь поймать сигнал уничтожения в фоновой задаче в системе Linux (Ubuntu), используя sigaction из libstd. Вот мой класс Program и объявления DllImport:

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace Signal
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            var pid = LibStd.GetPid();
            Console.WriteLine($"PID: {pid}");

            var sa = new Sigaction()
            {
                Handler = SignalHandler
            };

            LibStd.SigEmptySet(sa.Mask);
            var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
            Marshal.StructureToPtr(sa, ptr, true);

            _ = Task.Run(async() =>
            {
                while (true)
                {
                    // Check SIGUSR1
                    if (LibStd.Sigaction(10, ptr, IntPtr.Zero) == -1)
                    {
                        // error
                    }

                    await Task.Delay(1);
                }
            });

            while (true)
            {
                // Do something
            }
        }

        static LibStd.SignalHandler SignalHandler = new LibStd.SignalHandler(Handler);

        static void Handler(int sig)
        {
            Console.WriteLine($"RECEIVED SIGNAL {sig}");
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct Sigaction
    {
        public LibStd.SignalHandler Handler;
        public IntPtr Mask;
        public int Flags;
    }

    internal static class LibStd
    {
        private const string LibName = "c";

        [DllImport(LibName, EntryPoint = "getpid")]
        internal static extern int GetPid();

        [DllImport(LibName, EntryPoint = "sigaction", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int Sigaction(int sig, IntPtr act, IntPtr oldact);

        [DllImport(LibName, EntryPoint = "sigemptyset", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int SigEmptySet(IntPtr mask);

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        internal delegate void SignalHandler(int t);
    }
}

Мне нужно проверить сигналы в фоновом режиме, потому что я хочу поместить этот код в настольное приложение GUI в будущем, поэтому обработка сигналов не должна блокировать поток пользовательского интерфейса. , Однако, когда я запускаю эту программу, затем вызываю kill -SIGUSR1 <pid>, она выводит на консоль следующую ошибку: Неустранимая ошибка. Недопустимая программа: попытка вызова метода NativeCallable из безопасного для времени выполнения кода. Если я добавлю обработку сигналов в основную while (true) { } l oop, она будет работать как положено.
Было бы здорово, если бы кто-нибудь помог мне исправить это. Спасибо

1 Ответ

1 голос
/ 06 мая 2020

Для Ubuntu 18 я обнаружил, что необходимая структура была

[StructLayout(LayoutKind.Sequential)]
internal struct Sigaction
{
    public LibStd.SignalHandler Handler;
    public IntPtr Mask;
    public int Flags;
    public LibStd.SignalHandler sa_restorer;
}

, не рассматривайте возможность запуска потока для обработки сигнала

static private void ListenToSignal()
{
    var sa = new Sigaction()
    {
        Handler = SignalHandler
    };

    LibStd.SigEmptySet(sa.Mask);
    var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
    Marshal.StructureToPtr(sa, ptr, true);

    if (LibStd.Sigaction(10, ptr, IntPtr.Zero) == -1)
    {
        Console.WriteLine("Sigaction -1");
    }
    Console.WriteLine("Sigaction done");        
}

Это настраивает обработку в главном потоке. Когда приходит сигнал, он обрабатывается и на нем. Нет необходимости продолжать опрос Sigaction

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...