Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 080d07d

Browse files
committed
Avoid test deadlocks in threading WaitHandle tests
A bunch of the Mutex/EventWaitHandle/Semaphore tests are waiting indefinitely for a signal. If that signal never arrives due to the test failing, CI will end up waiting for several hours and then aborting the whole run. This change adds timeouts to those waits. It also changes a name used in one of the semaphore tests to be randomly generated; this should hopefully fix a pervasive failure we're seeing in CI right now.
1 parent 08512d6 commit 080d07d

File tree

4 files changed

+39
-22
lines changed

4 files changed

+39
-22
lines changed

src/System.Threading/tests/AutoResetEventTests.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
public class AutoResetEventTests
1010
{
11+
private const int FailedWaitTimeout = 30000;
12+
1113
[Fact]
1214
public void Ctor()
1315
{
@@ -40,7 +42,7 @@ public void WaitHandleWaitAll()
4042
for (int i = 0; i < handles.Length; i++)
4143
handles[i] = new AutoResetEvent(false);
4244

43-
Task<bool> t = Task.Run(() => WaitHandle.WaitAll(handles));
45+
Task<bool> t = Task.Run(() => WaitHandle.WaitAll(handles, FailedWaitTimeout));
4446
for (int i = 0; i < handles.Length; i++)
4547
{
4648
Assert.False(t.IsCompleted);
@@ -58,7 +60,7 @@ public void WaitHandleWaitAny()
5860
for (int i = 0; i < handles.Length; i++)
5961
handles[i] = new AutoResetEvent(false);
6062

61-
Task<int> t = Task.Run(() => WaitHandle.WaitAny(handles));
63+
Task<int> t = Task.Run(() => WaitHandle.WaitAny(handles, FailedWaitTimeout));
6264
handles[5].Set();
6365
Assert.Equal(5, t.Result);
6466

@@ -76,15 +78,15 @@ public void PingPong()
7678
{
7779
for (int i = 0; i < Iters; i++)
7880
{
79-
Assert.True(are1.WaitOne());
81+
Assert.True(are1.WaitOne(FailedWaitTimeout));
8082
are2.Set();
8183
}
8284
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default),
8385
Task.Factory.StartNew(() =>
8486
{
8587
for (int i = 0; i < Iters; i++)
8688
{
87-
Assert.True(are2.WaitOne());
89+
Assert.True(are2.WaitOne(FailedWaitTimeout));
8890
are1.Set();
8991
}
9092
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default));

src/System.Threading/tests/ManualResetEventTests.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
public class ManualResetEventTests
1010
{
11+
private const int FailedWaitTimeout = 30000;
12+
1113
[Fact]
1214
public void Ctor()
1315
{
@@ -41,7 +43,7 @@ public void WaitHandleWaitAll()
4143
for (int i = 0; i < handles.Length; i++)
4244
handles[i] = new ManualResetEvent(false);
4345

44-
Task<bool> t = Task.Run(() => WaitHandle.WaitAll(handles));
46+
Task<bool> t = Task.Run(() => WaitHandle.WaitAll(handles, FailedWaitTimeout));
4547
for (int i = 0; i < handles.Length; i++)
4648
{
4749
Assert.False(t.IsCompleted);
@@ -59,7 +61,7 @@ public void WaitHandleWaitAny()
5961
for (int i = 0; i < handles.Length; i++)
6062
handles[i] = new ManualResetEvent(false);
6163

62-
Task<int> t = Task.Run(() => WaitHandle.WaitAny(handles));
64+
Task<int> t = Task.Run(() => WaitHandle.WaitAny(handles, FailedWaitTimeout));
6365
handles[5].Set();
6466
Assert.Equal(5, t.Result);
6567

@@ -77,7 +79,7 @@ public void PingPong()
7779
{
7880
for (int i = 0; i < Iters; i++)
7981
{
80-
Assert.True(mre1.WaitOne());
82+
Assert.True(mre1.WaitOne(FailedWaitTimeout));
8183
mre1.Reset();
8284
mre2.Set();
8385
}
@@ -86,7 +88,7 @@ public void PingPong()
8688
{
8789
for (int i = 0; i < Iters; i++)
8890
{
89-
Assert.True(mre2.WaitOne());
91+
Assert.True(mre2.WaitOne(FailedWaitTimeout));
9092
mre2.Reset();
9193
mre1.Set();
9294
}

src/System.Threading/tests/MutexTests.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,26 @@
88

99
public class MutexTests
1010
{
11+
private const int FailedWaitTimeout = 30000;
12+
1113
[Fact]
1214
public void Ctor_ConstructWaitRelease()
1315
{
1416
using (Mutex m = new Mutex())
1517
{
16-
Assert.True(m.WaitOne());
18+
Assert.True(m.WaitOne(FailedWaitTimeout));
1719
m.ReleaseMutex();
1820
}
1921

2022
using (Mutex m = new Mutex(false))
2123
{
22-
Assert.True(m.WaitOne());
24+
Assert.True(m.WaitOne(FailedWaitTimeout));
2325
m.ReleaseMutex();
2426
}
2527

2628
using (Mutex m = new Mutex(true))
2729
{
28-
Assert.True(m.WaitOne());
30+
Assert.True(m.WaitOne(FailedWaitTimeout));
2931
m.ReleaseMutex();
3032
m.ReleaseMutex();
3133
}
@@ -86,11 +88,11 @@ public void OpenExisting_Windows()
8688
{
8789
using (Mutex m2 = Mutex.OpenExisting(name))
8890
{
89-
Assert.True(m1.WaitOne());
91+
Assert.True(m1.WaitOne(FailedWaitTimeout));
9092
Assert.False(Task.Factory.StartNew(() => m2.WaitOne(0), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Result);
9193
m1.ReleaseMutex();
9294

93-
Assert.True(m2.WaitOne());
95+
Assert.True(m2.WaitOne(FailedWaitTimeout));
9496
Assert.False(Task.Factory.StartNew(() => m1.WaitOne(0), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Result);
9597
m2.ReleaseMutex();
9698
}
@@ -106,14 +108,23 @@ public void AbandonExisting()
106108
{
107109
using (Mutex m = new Mutex())
108110
{
109-
Task.Factory.StartNew(() => m.WaitOne(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Wait();
110-
Assert.Throws<AbandonedMutexException>(() => m.WaitOne());
111+
Task t = Task.Factory.StartNew(() =>
112+
{
113+
Assert.True(m.WaitOne(FailedWaitTimeout));
114+
// don't release the mutex; abandon it on this thread
115+
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
116+
t.Wait();
117+
Assert.Throws<AbandonedMutexException>(() => m.WaitOne(FailedWaitTimeout));
111118
}
112119

113120
using (Mutex m = new Mutex())
114121
{
115-
Task.Factory.StartNew(() => m.WaitOne(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default).Wait();
116-
AbandonedMutexException ame = Assert.Throws<AbandonedMutexException>(() => WaitHandle.WaitAny(new[] { m }));
122+
Task t = Task.Factory.StartNew(() =>
123+
{
124+
Assert.True(m.WaitOne(FailedWaitTimeout));
125+
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
126+
t.Wait();
127+
AbandonedMutexException ame = Assert.Throws<AbandonedMutexException>(() => WaitHandle.WaitAny(new[] { m }, FailedWaitTimeout));
117128
Assert.Equal(0, ame.MutexIndex);
118129
}
119130
}

src/System.Threading/tests/SemaphoreTests.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace Test
1010
{
1111
public class SemaphoreTests
1212
{
13+
private const int FailedWaitTimeout = 30000;
14+
1315
[Theory]
1416
[InlineData(0, 1)]
1517
[InlineData(1, 1)]
@@ -154,7 +156,7 @@ public void AnonymousProducerConsumer()
154156
Task.Factory.StartNew(() =>
155157
{
156158
for (int i = 0; i < NumItems; i++)
157-
s.WaitOne();
159+
Assert.True(s.WaitOne(FailedWaitTimeout));
158160
Assert.False(s.WaitOne(0));
159161
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default),
160162
Task.Factory.StartNew(() =>
@@ -169,21 +171,21 @@ public void AnonymousProducerConsumer()
169171
[Fact]
170172
public void NamedProducerConsumer()
171173
{
172-
const string Name = "NamedProducerConsumerSemaphoreTest";
174+
string name = Guid.NewGuid().ToString("N");
173175
const int NumItems = 5;
174176
Task.WaitAll(
175177
Task.Factory.StartNew(() =>
176178
{
177-
using (Semaphore s = new Semaphore(0, Int32.MaxValue, Name))
179+
using (Semaphore s = new Semaphore(0, Int32.MaxValue, name))
178180
{
179181
for (int i = 0; i < NumItems; i++)
180-
s.WaitOne();
182+
Assert.True(s.WaitOne(1000));
181183
Assert.False(s.WaitOne(0));
182184
}
183185
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default),
184186
Task.Factory.StartNew(() =>
185187
{
186-
using (Semaphore s = new Semaphore(0, Int32.MaxValue, Name))
188+
using (Semaphore s = new Semaphore(0, Int32.MaxValue, name))
187189
{
188190
for (int i = 0; i < NumItems; i++)
189191
s.Release();

0 commit comments

Comments
 (0)