5 // Sebastien Pouliot <sebastien@ximian.com>
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections.Generic;
32 using System.Threading;
34 using NUnit.Framework;
36 namespace MonoTests.System.Threading {
39 public class WaitHandleTest {
41 TimeSpan Infinite = new TimeSpan (-10000); // -10000 ticks == -1 ms
42 TimeSpan SmallNegative = new TimeSpan (-2); // between 0 and -1.0 (infinite) ms
43 TimeSpan Negative = new TimeSpan (-20000); // really negative
45 WaitHandle [] TooLarge = new Mutex [65];
46 WaitHandle [] Empty = new Mutex [1];
47 WaitHandle [] Single = new Mutex [1] { new Mutex (true) };
51 [ExpectedException (typeof (ArgumentNullException))]
52 public void WaitAny_WaitHandle_Null ()
54 WaitHandle.WaitAny (null);
58 [ExpectedException (typeof (NotSupportedException))]
59 public void WaitAny_WaitHandle_TooLarge ()
61 WaitHandle.WaitAny (TooLarge);
65 [ExpectedException (typeof (ArgumentNullException))]
66 public void WaitAny_WaitHandle_Empty ()
68 WaitHandle.WaitAny (Empty);
72 public void WaitAny_WaitHandle ()
74 Assert.AreEqual (0, WaitHandle.WaitAny (Single), "WaitAny");
78 [ExpectedException (typeof (ArgumentNullException))]
79 public void WaitAny_WaitHandleNull_Int ()
81 WaitHandle.WaitAny (null, -1);
85 [ExpectedException (typeof (NotSupportedException))]
86 public void WaitAny_WaitHandle_TooLarge_Int ()
88 WaitHandle.WaitAny (TooLarge, -1);
92 [ExpectedException (typeof (ArgumentNullException))]
93 public void WaitAny_WaitHandle_Empty_Int ()
95 WaitHandle.WaitAny (Empty, -1);
99 public void WaitAny_WaitHandle_Int ()
102 Assert.AreEqual (0, WaitHandle.WaitAny (Single, -1), "WaitAny");
106 [ExpectedException (typeof (ArgumentOutOfRangeException))]
107 public void WaitAny_WaitHandle_Int_Negative ()
109 Assert.AreEqual (0, WaitHandle.WaitAny (Single, -2), "WaitAny");
113 [ExpectedException (typeof (ArgumentNullException))]
114 public void WaitAny_WaitHandleNull_TimeSpan ()
116 WaitHandle.WaitAny (null, Infinite);
120 [ExpectedException (typeof (NotSupportedException))]
121 public void WaitAny_WaitHandle_TooLarge_TimeSpan ()
123 WaitHandle.WaitAny (TooLarge, Infinite);
127 [ExpectedException (typeof (ArgumentNullException))]
128 public void WaitAny_WaitHandle_Empty_TimeSpan ()
130 WaitHandle.WaitAny (Empty, Infinite);
134 public void WaitAny_WaitHandle_TimeSpan ()
136 Assert.AreEqual (Timeout.Infinite, (int) Infinite.TotalMilliseconds, "Infinite");
137 Assert.AreEqual (0, WaitHandle.WaitAny (Single, Infinite), "WaitAny-Infinite");
138 Assert.AreEqual (0, WaitHandle.WaitAny (Single, SmallNegative), "WaitAny-SmallNegative");
142 [ExpectedException (typeof (ArgumentOutOfRangeException))]
143 public void WaitAny_WaitHandle_TimeSpan_Negative ()
145 Assert.AreEqual (0, WaitHandle.WaitAny (Single, Negative), "WaitAny");
149 [ExpectedException (typeof (ArgumentOutOfRangeException))]
150 public void WaitAny_WaitHandle_TimeSpan_MaxValue ()
152 Assert.AreEqual (0, WaitHandle.WaitAny (Single, TimeSpan.MaxValue), "WaitAny");
157 [ExpectedException (typeof (ArgumentNullException))]
158 public void WaitAll_WaitHandle_Null ()
160 WaitHandle.WaitAll (null);
164 [ExpectedException (typeof (NotSupportedException))]
165 public void WaitAll_WaitHandle_TooLarge ()
167 WaitHandle.WaitAll (TooLarge);
171 [ExpectedException (typeof (ArgumentNullException))]
172 public void WaitAll_WaitHandle_Empty ()
174 WaitHandle.WaitAll (Empty);
178 public void WaitAll_WaitHandle ()
180 Assert.IsTrue (WaitHandle.WaitAll (Single), "WaitAll");
184 [ExpectedException (typeof (ArgumentNullException))]
185 public void WaitAll_WaitHandleNull_Int ()
187 WaitHandle.WaitAll (null, -1);
191 [ExpectedException (typeof (NotSupportedException))]
192 public void WaitAll_WaitHandle_TooLarge_Int ()
194 WaitHandle.WaitAll (TooLarge, -1);
198 [ExpectedException (typeof (ArgumentNullException))]
199 public void WaitAll_WaitHandle_Empty_Int ()
201 WaitHandle.WaitAll (Empty, -1);
205 public void WaitAll_WaitHandle_Int ()
208 Assert.IsTrue (WaitHandle.WaitAll (Single, -1), "WaitAll");
212 [ExpectedException (typeof (ArgumentOutOfRangeException))]
213 public void WaitAll_WaitHandle_Int_Negative ()
215 Assert.IsTrue (WaitHandle.WaitAll (Single, -2), "WaitAll");
219 [ExpectedException (typeof (ArgumentNullException))]
220 public void WaitAll_WaitHandleNull_TimeSpan ()
222 WaitHandle.WaitAll (null, Infinite);
226 [ExpectedException (typeof (NotSupportedException))]
227 public void WaitAll_WaitHandle_TooLarge_TimeSpan ()
229 WaitHandle.WaitAll (TooLarge, Infinite);
233 [ExpectedException (typeof (ArgumentNullException))]
234 public void WaitAll_WaitHandle_Empty_TimeSpan ()
236 WaitHandle.WaitAll (Empty, Infinite);
240 public void WaitAll_WaitHandle_TimeSpan ()
242 Assert.AreEqual (Timeout.Infinite, (int) Infinite.TotalMilliseconds, "Infinite");
243 Assert.IsTrue (WaitHandle.WaitAll (Single, Infinite), "WaitAll-Infinite");
244 Assert.IsTrue (WaitHandle.WaitAll (Single, SmallNegative), "WaitAll-SmallNegative");
248 [ExpectedException (typeof (ArgumentOutOfRangeException))]
249 public void WaitAll_WaitHandle_TimeSpan_Negative ()
251 Assert.IsTrue (WaitHandle.WaitAll (Single, Negative), "WaitAll");
255 [ExpectedException (typeof (ArgumentOutOfRangeException))]
256 public void WaitAll_WaitHandle_TimeSpan_MaxValue ()
258 Assert.IsTrue (WaitHandle.WaitAll (Single, TimeSpan.MaxValue), "WaitAll");
263 public void WaitOne ()
265 Assert.IsTrue (Single [0].WaitOne (), "WaitOne");
269 public void WaitOne_Int ()
272 Assert.IsTrue (Single [0].WaitOne (-1), "WaitOne");
276 [ExpectedException (typeof (ArgumentOutOfRangeException))]
277 public void WaitOne_Int_Negative ()
279 Assert.IsTrue (Single [0].WaitOne (-2), "WaitOne");
283 public void WaitOne_TimeSpan ()
285 Assert.AreEqual (Timeout.Infinite, (int) Infinite.TotalMilliseconds, "Infinite");
286 Assert.IsTrue (Single [0].WaitOne (Infinite), "WaitOne-Infinite");
287 Assert.IsTrue (Single [0].WaitOne (SmallNegative), "WaitOne-SmallNegative");
291 [ExpectedException (typeof (ArgumentOutOfRangeException))]
292 public void WaitOne_TimeSpan_Negative ()
294 Assert.IsTrue (Single [0].WaitOne (Negative), "WaitOne");
298 [ExpectedException (typeof (ArgumentOutOfRangeException))]
299 public void WaitOne_TimeSpan_MaxValue ()
301 Assert.IsTrue (Single [0].WaitOne (TimeSpan.MaxValue), "WaitOne");
305 [ExpectedException (typeof (ArgumentNullException))]
306 public void WaitAll_Empty ()
308 WaitHandle.WaitAll (new WaitHandle [0]);
312 [ExpectedException (typeof (ArgumentException))]
313 public void WaitAny_Empty ()
315 WaitHandle.WaitAny (new WaitHandle [0]);
319 public void InterrupedWaitAny ()
321 using (var m1 = new Mutex (true)) {
322 using (var m2 = new Mutex (true)) {
323 using (var done = new ManualResetEvent (false)) {
324 var thread = new Thread (() =>
327 WaitHandle.WaitAny (new WaitHandle [] { m1, m2 });
328 } catch (ThreadInterruptedException) {
333 Thread.Sleep (100); // wait a bit so the thread can enter its wait
336 Assert.IsTrue (thread.Join (1000), "Join");
337 Assert.IsTrue (done.WaitOne (1000), "done");
347 public void InterrupedWaitAll ()
349 using (var m1 = new Mutex (true)) {
350 using (var m2 = new Mutex (true)) {
351 using (var done = new ManualResetEvent (false)) {
352 var thread = new Thread (() =>
355 WaitHandle.WaitAll (new WaitHandle [] { m1, m2 });
356 } catch (ThreadInterruptedException) {
361 Thread.Sleep (100); // wait a bit so the thread can enter its wait
364 Assert.IsTrue (thread.Join (1000), "Join");
365 Assert.IsTrue (done.WaitOne (1000), "done");
375 public void InterrupedWaitOne ()
377 using (var m1 = new Mutex (true)) {
378 using (var done = new ManualResetEvent (false)) {
379 var thread = new Thread (() =>
383 } catch (ThreadInterruptedException) {
388 Thread.Sleep (100); // wait a bit so the thread can enter its wait
391 Assert.IsTrue (thread.Join (1000), "Join");
392 Assert.IsTrue (done.WaitOne (1000), "done");
400 public void WaitOneWithAbandonedMutex ()
402 using (var m = new Mutex (false)) {
403 var thread1 = new Thread (() => {
410 Assert.Fail ("Expected AbandonedMutexException");
411 } catch (AbandonedMutexException) {
413 // Current thread should own the Mutex now
414 var signalled = false;
415 var thread2 = new Thread (() => {
416 signalled = m.WaitOne (100);
420 Assert.IsFalse (signalled);
422 // Since this thread owns the Mutex releasing it shouldn't fail
424 // The Mutex should now be unowned
427 Assert.Fail ("Expected ApplicationException");
428 } catch (ApplicationException) {
434 public void WaitOneWithAbandonedMutexAndMultipleThreads ()
436 using (var m = new Mutex (true)) {
437 var nonAbandoned = 0;
440 var threads = new List<Thread> ();
441 for (int i = 0; i < 50; i++) {
442 var thread = new Thread (() => {
446 } catch (AbandonedMutexException) {
449 if (((n++) % 5) != 0)
453 threads.Add (thread);
456 foreach (var thread in threads) {
457 if (!thread.Join (1000)) {
458 Assert.Fail ("Timed out");
461 Assert.AreEqual (40, nonAbandoned);
462 Assert.AreEqual (10, abandoned);
467 public void WaitAnyWithSecondMutexAbandoned ()
469 using (var m1 = new Mutex (false)) {
470 using (var m2 = new Mutex (false)) {
471 var mainProceed = false;
472 var thread2Proceed = false;
473 var thread1 = new Thread (() => {
476 var thread2 = new Thread (() => {
479 while (!thread2Proceed) {
487 while (!mainProceed) {
491 WaitHandle.WaitAny (new WaitHandle [] { m1, m2 });
492 Assert.Fail ("Expected AbandonedMutexException");
493 } catch (AbandonedMutexException e) {
494 Assert.AreEqual (1, e.MutexIndex);
495 Assert.AreEqual (m2, e.Mutex);
497 thread2Proceed = true;
501 // Current thread should own the second Mutex now
503 var thread3 = new Thread (() => {
504 signalled = WaitHandle.WaitAny (new WaitHandle [] { m1, m2 }, 0);
508 Assert.AreEqual (0, signalled);
510 // Since this thread owns the second Mutex releasing it shouldn't fail
512 // Second Mutex should now be unowned
515 Assert.Fail ("Expected ApplicationException");
516 } catch (ApplicationException) {
518 // .NET allows the first Mutex which is now abandoned to be released multiple times by this thread
526 [ExpectedException (typeof (AbandonedMutexException))]
527 public void WaitAllWithOneAbandonedMutex ()
529 using (var m1 = new Mutex (false)) {
530 using (var m2 = new Mutex (false)) {
531 var thread = new Thread (() => {
536 WaitHandle.WaitAll (new WaitHandle [] { m1, m2 });
541 #if MONO_FEATURE_THREAD_SUSPEND_RESUME
543 public void WaitOneWithTimeoutAndSpuriousWake ()
545 /* This is to test that WaitEvent.WaitOne is not going to wait largely
546 * more than its timeout. In this test, it shouldn't wait more than
547 * 1500 milliseconds, with its timeout being 1000ms */
549 using (ManualResetEvent mre = new ManualResetEvent (false))
550 using (ManualResetEvent ready = new ManualResetEvent (false)) {
551 var thread = new Thread (() => {
559 Thread.Sleep (10); // wait a bit so we enter mre.WaitOne
561 DateTime end = DateTime.Now.AddMilliseconds (500);
562 while (DateTime.Now < end) {
567 Assert.IsTrue (thread.Join (1000), "#1");
572 public void WaitAnyWithTimeoutAndSpuriousWake ()
574 /* This is to test that WaitEvent.WaitAny is not going to wait largely
575 * more than its timeout. In this test, it shouldn't wait more than
576 * 1500 milliseconds, with its timeout being 1000ms */
578 using (ManualResetEvent mre1 = new ManualResetEvent (false))
579 using (ManualResetEvent mre2 = new ManualResetEvent (false))
580 using (ManualResetEvent ready = new ManualResetEvent (false)) {
581 var thread = new Thread (() => {
583 WaitHandle.WaitAny (new [] { mre1, mre2 }, 1000);
589 Thread.Sleep (10); // wait a bit so we enter WaitHandle.WaitAny ({mre1, mre2})
591 DateTime end = DateTime.Now.AddMilliseconds (500);
592 while (DateTime.Now < end) {
597 Assert.IsTrue (thread.Join (1000), "#1");
602 public void WaitAllWithTimeoutAndSpuriousWake ()
604 /* This is to test that WaitEvent.WaitAll is not going to wait largely
605 * more than its timeout. In this test, it shouldn't wait more than
606 * 1500 milliseconds, with its timeout being 1000ms */
608 using (ManualResetEvent mre1 = new ManualResetEvent (false))
609 using (ManualResetEvent mre2 = new ManualResetEvent (false))
610 using (ManualResetEvent ready = new ManualResetEvent (false)) {
611 var thread = new Thread (() => {
613 WaitHandle.WaitAll (new [] { mre1, mre2 }, 1000);
619 Thread.Sleep (10); // wait a bit so we enter WaitHandle.WaitAll ({mre1, mre2})
621 DateTime end = DateTime.Now.AddMilliseconds (500);
622 while (DateTime.Now < end) {
627 Assert.IsTrue (thread.Join (1000), "#1");
630 #endif // MONO_FEATURE_THREAD_SUSPEND_RESUME