Bug 41430 - Mono.Unix.UnixSignal.WaitAny blocks AsyncWaitHandle signals for other threads
Summary: Mono.Unix.UnixSignal.WaitAny blocks AsyncWaitHandle signals for other threads
Status: RESOLVED INVALID
Alias: None
Product: Runtime
Classification: Mono
Component: General ()
Version: 4.2.0 (C6)
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-06-01 12:45 UTC by j.peters
Modified: 2016-06-16 15:49 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED INVALID

Description j.peters 2016-06-01 12:45:25 UTC
Hi there,

It seems like Mono.Unix.UnixSignal.WaitAny in mono 4.2.3 blocks signals for other threads. See my example below. We are setting up a socket and use AsyncWaitHandle.WaitOne to implement a timeout. AsyncWaitHandle.WaitOne should return true once a signal has arrived. Connecting to a socket works repeately just fine, but unfortunately AsyncWaitHandle.WaitOne times out and returns false as soon as Mono.Unix.UnixSignal.WaitAny is set up in a different thread to catch a SIGINT signal. Interestly the signal for the socket connect does arrive once sigint is sent and WaitAny exits, so seems like WaitAny does not really eats the signals, but rather locks them for other threads.

Note that this does not happen with mono 4.0.4. On mono 4.0.4 we can keep succesfully connect to sockets, regardless UnixSignal.WaitAny is set up or not.
Just a shot in the dark, eventually this is connected to recent changes in support/signal.c (https://github.com/mono/mono/commits/master/support/signal.c), though really not sure.

Regards,
Jens

Sample program:
---------------

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Mono.Unix;
using Mono.Unix.Native;

namespace UnixSignalTest
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            int port;
            if(args.Length != 2 || !int.TryParse(args[1], out port))
            {
                Console.WriteLine("Usage: mono UnixSignalTest.exe [ip address] [port]" + Environment.NewLine +
                                    "Example mono UnixSignalTest.exe 127.0.0.1 3306");
                return;
            }

            var ip = IPAddress.Parse(args[0]);
            var cts = new CancellationTokenSource();

            Console.WriteLine("Starting.");
            var connectToDbTask = Task.Run(() =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    var endPoint = new IPEndPoint(ip, port);
                    var socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                    Console.WriteLine("+++ Trying to connect...");
                    var ias = socket.BeginConnect(endPoint, null, null);
                    if (!ias.AsyncWaitHandle.WaitOne(15 * 1000, false))
                    {
                        // We should never come here, but unfortunately UnixSignal.WaitAny seems to eat all signals
                        Console.WriteLine("+++ No signal :(."); 
                        socket.Close();
                    }
                    else
                    {
                        Console.WriteLine("+++ Signal received, connect successful.");
                        socket.EndConnect(ias);
                    }
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }
            }, cts.Token);

            Console.WriteLine("Wait a few seconds...");
            Thread.Sleep(TimeSpan.FromSeconds(5));

            var usixSignalTask = Task.Run(() =>
            {
                Console.WriteLine("*** Wait for Unix signals...");
                UnixSignal[] signals = { new UnixSignal(Signum.SIGINT) };
                var index = UnixSignal.WaitAny(signals, -1);
                Console.WriteLine("*** Got a {0} signal!", signals[index].Signum);
                cts.Cancel();

            }, cts.Token);

            Task.WaitAll(connectToDbTask, usixSignalTask);

            Console.WriteLine("Exit.");
        }
    }
}

My output:
----------

Starting.
Wait a few seconds...
+++ Trying to connect...
+++ Signal received, connect successful.
+++ Trying to connect...
+++ Signal received, connect successful.
+++ Trying to connect...
+++ Signal received, connect successful.
+++ Trying to connect...
+++ Signal received, connect successful.
+++ Trying to connect...
+++ Signal received, connect successful.
*** Wait for Unix signals...
+++ Trying to connect...
+++ No signal :(.
+++ Trying to connect...
+++ No signal :(.
+++ Trying to connect...
+++ No signal :(.
+++ Trying to connect...
+++ No signal :(.
+++ Trying to connect...
^C*** Got a SIGINT signal!
+++ Signal received, connect successful.
Exit.
Comment 1 j.peters 2016-06-02 09:35:33 UTC
Small typo: I meant to say that I can't reproduce this scenario on mono 4.0.5 not 4.0.4 as stated above, although I'm pretty sure that mono 4.0.4 runs fine too.

Furthermore I'm running centos 7 and mono is installed from http://download.mono-project.com/repo/centos/. 
Uname says: Linux 3.10.0-327.4.4.el7.x86_64 #1 SMP Tue Jan 5 16:07:00 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Comment 2 j.peters 2016-06-16 15:37:13 UTC
Alright, seems to be my error. As stated here http://www.mono-project.com/docs/faq/technical/#can-i-use-signal-handlers-with-mono "Typically you would create a thread to wait for the UnixSignal deliveries, as UnixSignal can not be mixed with other WaitHandles.". So modifying my test program to "new Thread" instead of "Task.Run" resolves it for me. Sorry for the noise. 

PS: Seems like mono 4.0 created a new thread when Task.Run was executed.