[w32handle] Only own first handle if doing WaitHandle.WaitAny (#5625)
authorLudovic Henry <luhenry@microsoft.com>
Tue, 26 Sep 2017 03:05:58 +0000 (23:05 -0400)
committerGitHub <noreply@github.com>
Tue, 26 Sep 2017 03:05:58 +0000 (23:05 -0400)
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
mono/tests/Makefile.am
mono/tests/bug-59281.cs [new file with mode: 0644]

index 98d4ace6d62593b62e3b0e1be6ace694f8333ff6..654b215538d800de195db57afeca5ccaaa9176e9 100644 (file)
@@ -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);
index 729b663f91ba9cfb66dbdee3e980641d7a843803..77f06635dde8017a61e1b2cdf018e915e63a44d7 100755 (executable)
@@ -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 (file)
index 0000000..94250c2
--- /dev/null
@@ -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