Skip to content

Commit

Permalink
[w32handle] Only own first handle if doing WaitHandle.WaitAny (#5625)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
luhenry authored and marek-safar committed Sep 29, 2017
1 parent 7ba4e9e commit 0dd35e9
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
9 changes: 7 additions & 2 deletions mono/metadata/w32handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -1297,8 +1297,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);
Expand Down
3 changes: 2 additions & 1 deletion mono/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,8 @@ TESTS_CS_SRC= \
runtime-invoke.gen.cs \
imt_big_iface_test.cs \
bug-58782-plain-throw.cs \
bug-58782-capture-and-throw.cs
bug-58782-capture-and-throw.cs \
bug-59281.cs

if AMD64
TESTS_CS_SRC += async-exc-compilation.cs finally_guard.cs finally_block_ending_in_dead_bb.cs
Expand Down
51 changes: 51 additions & 0 deletions mono/tests/bug-59281.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}

0 comments on commit 0dd35e9

Please sign in to comment.