public void AbandonExisting( string name, WaitHandleWaitType waitType, int waitCount, int notAbandonedWaitIndex, bool isNotAbandonedWaitObjectSignaled, bool abandonDuringWait) { ThreadTestHelpers.RunTestInBackgroundThread(() => { using (var m = new Mutex(false, name)) using (Mutex m2 = waitCount == 1 ? null : new Mutex(false, name == null ? null : name + "_2")) using (ManualResetEvent e = waitCount == 1 ? null : new ManualResetEvent(isNotAbandonedWaitObjectSignaled)) using (ManualResetEvent threadReadyForAbandon = abandonDuringWait ? new ManualResetEvent(false) : null) using (ManualResetEvent abandonSoon = abandonDuringWait ? new ManualResetEvent(false) : null) { WaitHandle[] waitHandles = null; if (waitType != WaitHandleWaitType.WaitOne) { waitHandles = new WaitHandle[waitCount]; if (waitCount == 1) { waitHandles[0] = m; } else { waitHandles[notAbandonedWaitIndex] = e; waitHandles[notAbandonedWaitIndex == 0 ? 1 : 0] = m; waitHandles[notAbandonedWaitIndex == 2 ? 1 : 2] = m2; } } Thread t = ThreadTestHelpers.CreateGuardedThread(out Action waitForThread, () => { Assert.True(m.WaitOne(0)); if (m2 != null) { Assert.True(m2.WaitOne(0)); } if (abandonDuringWait) { threadReadyForAbandon.Set(); abandonSoon.CheckedWait(); Thread.Sleep(ThreadTestHelpers.ExpectedTimeoutMilliseconds); } // don't release the mutexes; abandon them on this thread }); t.IsBackground = true; t.Start(); if (abandonDuringWait) { threadReadyForAbandon.CheckedWait(); abandonSoon.Set(); } else { waitForThread(); } AbandonedMutexException ame; switch (waitType) { case WaitHandleWaitType.WaitOne: ame = AssertExtensions.Throws <AbandonedMutexException, bool>( () => m.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); Assert.Equal(-1, ame.MutexIndex); Assert.Null(ame.Mutex); break; case WaitHandleWaitType.WaitAny: if (waitCount != 1 && isNotAbandonedWaitObjectSignaled && notAbandonedWaitIndex == 0) { 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)); } // 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>( () => m.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); } break; case WaitHandleWaitType.WaitAll: if (waitCount != 1 && !isNotAbandonedWaitObjectSignaled) { Assert.False(WaitHandle.WaitAll(waitHandles, ThreadTestHelpers.ExpectedTimeoutMilliseconds * 2)); Assert.True(e.Set()); } ame = AssertExtensions.Throws <AbandonedMutexException, bool>( () => WaitHandle.WaitAll(waitHandles, ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); Assert.Equal(-1, ame.MutexIndex); Assert.Null(ame.Mutex); break; } if (abandonDuringWait) { waitForThread(); } m.ReleaseMutex(); m2?.ReleaseMutex(); } }); }
public void AbandonExisting( string name, WaitHandleWaitType waitType, int waitCount, int notAbandonedWaitIndex, bool isNotAbandonedWaitObjectSignaled, bool abandonDuringWait) { ThreadTestHelpers.RunTestInBackgroundThread(() => { using (var m = new Mutex(false, name)) using (Mutex m2 = waitCount == 1 ? null : new Mutex(false, name == null ? null : name + "_2")) using (ManualResetEvent e = waitCount == 1 ? null : new ManualResetEvent(isNotAbandonedWaitObjectSignaled)) using (ManualResetEvent threadReadyForAbandon = abandonDuringWait ? new ManualResetEvent(false) : null) using (ManualResetEvent abandonSoon = abandonDuringWait ? new ManualResetEvent(false) : null) { WaitHandle[] waitHandles = null; if (waitType != WaitHandleWaitType.WaitOne) { waitHandles = new WaitHandle[waitCount]; if (waitCount == 1) { waitHandles[0] = m; } else { waitHandles[notAbandonedWaitIndex] = e; waitHandles[notAbandonedWaitIndex == 0 ? 1 : 0] = m; waitHandles[notAbandonedWaitIndex == 2 ? 1 : 2] = m2; } } Thread t = ThreadTestHelpers.CreateGuardedThread(out Action waitForThread, () => { Assert.True(m.WaitOne(0)); if (m2 != null) { Assert.True(m2.WaitOne(0)); } if (abandonDuringWait) { threadReadyForAbandon.Set(); abandonSoon.CheckedWait(); Thread.Sleep(ThreadTestHelpers.ExpectedTimeoutMilliseconds); } // don't release the mutexes; abandon them on this thread }); t.IsBackground = true; t.Start(); if (abandonDuringWait) { threadReadyForAbandon.CheckedWait(); abandonSoon.Set(); } else { waitForThread(); } AbandonedMutexException ame; switch (waitType) { case WaitHandleWaitType.WaitOne: ame = AssertExtensions.Throws <AbandonedMutexException, bool>( () => m.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); Assert.Equal(-1, ame.MutexIndex); Assert.Null(ame.Mutex); break; case WaitHandleWaitType.WaitAny: if (waitCount != 1 && isNotAbandonedWaitObjectSignaled && notAbandonedWaitIndex == 0) { Assert.Equal(0, WaitHandle.WaitAny(waitHandles, 0)); AssertExtensions.Throws <AbandonedMutexException, bool>( () => m.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); } 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) { AssertExtensions.Throws <AbandonedMutexException, bool>( () => m2.WaitOne(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); } break; case WaitHandleWaitType.WaitAll: if (waitCount != 1 && !isNotAbandonedWaitObjectSignaled) { Assert.False(WaitHandle.WaitAll(waitHandles, ThreadTestHelpers.ExpectedTimeoutMilliseconds * 2)); Assert.True(e.Set()); } ame = AssertExtensions.Throws <AbandonedMutexException, bool>( () => WaitHandle.WaitAll(waitHandles, ThreadTestHelpers.UnexpectedTimeoutMilliseconds)); Assert.Equal(-1, ame.MutexIndex); Assert.Null(ame.Mutex); break; } if (abandonDuringWait) { waitForThread(); } m.ReleaseMutex(); m2?.ReleaseMutex(); } }); }