From 932a58ea407d6878d610cbe516d901293977aba1 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Mon, 25 Sep 2017 23:05:58 -0400 Subject: [PATCH] [w32handle] Only own first handle if doing WaitHandle.WaitAny (#5625) This is the behaviour on .NET, even if it goes against the documentation at https://msdn.microsoft.com/en-us/library/tdykks7z(v=vs.110).aspx#Anchor_2 Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=59281 --- mono/metadata/w32handle.c | 9 +++++-- mono/tests/Makefile.am | 3 ++- mono/tests/bug-59281.cs | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 mono/tests/bug-59281.cs diff --git a/mono/metadata/w32handle.c b/mono/metadata/w32handle.c index 98d4ace6d62..654b215538d 100644 --- a/mono/metadata/w32handle.c +++ b/mono/metadata/w32handle.c @@ -1218,8 +1218,13 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital signalled = (waitall && count == nhandles) || (!waitall && count > 0); if (signalled) { - for (i = 0; i < nhandles; i++) - own_if_signalled (handles [i], &abandoned [i]); + for (i = 0; i < nhandles; i++) { + if (own_if_signalled (handles [i], &abandoned [i]) && !waitall) { + /* if we are calling WaitHandle.WaitAny, .NET only owns the first one; it matters for Mutex which + * throw AbandonedMutexException in case we owned it but didn't release it */ + break; + } + } } mono_w32handle_unlock_handles (handles, nhandles); diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am index 729b663f91b..77f06635dde 100755 --- a/mono/tests/Makefile.am +++ b/mono/tests/Makefile.am @@ -519,7 +519,8 @@ TESTS_CS_SRC= \ imt_big_iface_test.cs \ bug-58782-plain-throw.cs \ bug-58782-capture-and-throw.cs \ - recursive-struct-arrays.cs + recursive-struct-arrays.cs \ + bug-59281.cs if AMD64 TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs diff --git a/mono/tests/bug-59281.cs b/mono/tests/bug-59281.cs new file mode 100644 index 00000000000..94250c277a7 --- /dev/null +++ b/mono/tests/bug-59281.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading; + +class Driver +{ + + static readonly Mutex[] mutexes = new Mutex[2]; + + public static void Main(string[] args) + { + for (int i = 0; i < mutexes.Length; i++) { + mutexes [i] = new Mutex(); + } + + Thread thread1 = new Thread(() => { + for (int i = 0; i < 1; i++) { + int idx = -1; + try { + idx = WaitHandle.WaitAny (mutexes); + Console.WriteLine($"Thread 1 iter: {i} with mutex: {idx}"); + } finally { + if (idx != -1) + mutexes [idx].ReleaseMutex(); + } + } + + Console.WriteLine("Thread 1 ended"); + }); + + thread1.Start(); + thread1.Join(); + + Thread thread2 = new Thread(() => { + for (int i = 0; i < 1000; i++) { + int idx = -1; + try { + idx = WaitHandle.WaitAny (mutexes); + Console.WriteLine($"Thread 2 iter: {i} with mutex: {idx}"); + } finally { + if (idx != -1) + mutexes [idx].ReleaseMutex(); + } + } + + Console.WriteLine("Thread 2 ended"); + }); + + thread2.Start(); + thread2.Join(); + } +} \ No newline at end of file -- 2.25.1