Skip to content

Commit

Permalink
Relax a mutex test condition (dotnet#39786)
Browse files Browse the repository at this point in the history
Fixes https://github.com/dotnet/corefx/issues/39694
- When doing a `WaitAny()` with mutexes that are expected to be abandoned and an event that is signaled, it has been seen in the CI on Windows that sometimes the `WaitAny()` may succeed due to event rather than identifying an abandoned mutex. The CLR doesn't do anything special and just delegates to the OS, the only way that could happen is if there could be a delay between the thread exiting and the mutex being released and abandoned. I haven't been able to repro that behavior or the test failure on my machine, it may not be easy to repro, even in the CI it fails only occasionally.
- It's not a bug as long as the mutex eventually gets released and abandoned. Relaxed the condition for `WaitAny()` with an event following a mutex to account for a delay.
  • Loading branch information
kouvel authored and stephentoub committed Jul 25, 2019
1 parent 3e36efc commit 97d5957
Showing 1 changed file with 47 additions and 4 deletions.
51 changes: 47 additions & 4 deletions src/System.Threading/tests/MutexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,21 +309,64 @@ public void AbandonExisting(
Assert.Equal(0, WaitHandle.WaitAny(waitHandles, 0));
AssertExtensions.Throws<AbandonedMutexException, bool>(
() => m.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
AssertExtensions.Throws<AbandonedMutexException, bool>(
() => m2.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
break;
}

if (waitCount != 1 && isNotAbandonedWaitObjectSignaled && notAbandonedWaitIndex != 0)
{
ame =
Assert.Throws<AbandonedMutexException>(() =>
{
ThreadTestHelpers.WaitForCondition(() =>
{
// Actually expecting an exception from WaitAny(), but there may be a delay before
// the mutex is actually released and abandoned. If there is no exception, the
// WaitAny() must have succeeded due to the event being signaled.
int r = WaitHandle.WaitAny(waitHandles, ThreadTestHelpers.UnexpectedTimeoutMilliseconds);
Assert.Equal(notAbandonedWaitIndex, r);
return false;
});
});
}
else
{
ame =
AssertExtensions.Throws<AbandonedMutexException, int>(
() => WaitHandle.WaitAny(waitHandles, ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
Assert.Equal(waitCount != 1 && notAbandonedWaitIndex == 0 ? 1 : 0, ame.MutexIndex);
Assert.Equal(m, ame.Mutex);
}

if (m2 != null)
// Due to a potential delay in abandoning mutexes, either mutex may have been seen to be
// abandoned first
Assert.True(ame.Mutex == m || (m2 != null && ame.Mutex == m2));
int mIndex = waitCount != 1 && notAbandonedWaitIndex == 0 ? 1 : 0;
int m2Index = waitCount != 1 && notAbandonedWaitIndex == 2 ? 1 : 2;
if (ame.Mutex == m)
{
Assert.Equal(mIndex, ame.MutexIndex);
}
else
{
Assert.True(m2Index < notAbandonedWaitIndex);
Assert.Equal(m2Index, ame.MutexIndex);
}

// Verify that the other mutex also gets abandoned
if (ame.MutexIndex == mIndex)
{
if (m2 != null)
{
AssertExtensions.Throws<AbandonedMutexException, bool>(
() => m2.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
}
}
else
{
AssertExtensions.Throws<AbandonedMutexException, bool>(
() => m2.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
() => m.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
}

break;

case WaitHandleWaitType.WaitAll:
Expand Down

0 comments on commit 97d5957

Please sign in to comment.