WaitHandleTest.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. //
  2. // WaitHandleTest.cs
  3. //
  4. // Author:
  5. // Sebastien Pouliot <[email protected]>
  6. //
  7. // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
  8. //
  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:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  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.
  27. //
  28. using System;
  29. using System.Diagnostics;
  30. using System.Collections.Generic;
  31. using System.Threading;
  32. using NUnit.Framework;
  33. namespace MonoTests.System.Threading {
  34. [TestFixture]
  35. public class WaitHandleTest {
  36. TimeSpan Infinite = new TimeSpan (-10000); // -10000 ticks == -1 ms
  37. TimeSpan SmallNegative = new TimeSpan (-2); // between 0 and -1.0 (infinite) ms
  38. TimeSpan Negative = new TimeSpan (-20000); // really negative
  39. WaitHandle [] TooLarge = new Mutex [65];
  40. WaitHandle [] Empty = new Mutex [1];
  41. WaitHandle [] Single = new Mutex [1] { new Mutex (true) };
  42. [Test]
  43. [ExpectedException (typeof (ArgumentNullException))]
  44. public void WaitAny_WaitHandle_Null ()
  45. {
  46. WaitHandle.WaitAny (null);
  47. }
  48. [Test]
  49. [ExpectedException (typeof (NotSupportedException))]
  50. public void WaitAny_WaitHandle_TooLarge ()
  51. {
  52. WaitHandle.WaitAny (TooLarge);
  53. }
  54. [Test]
  55. [ExpectedException (typeof (ArgumentNullException))]
  56. public void WaitAny_WaitHandle_Empty ()
  57. {
  58. WaitHandle.WaitAny (Empty);
  59. }
  60. [Test]
  61. public void WaitAny_WaitHandle ()
  62. {
  63. Assert.AreEqual (0, WaitHandle.WaitAny (Single), "WaitAny");
  64. }
  65. [Test]
  66. [ExpectedException (typeof (ArgumentNullException))]
  67. public void WaitAny_WaitHandleNull_Int ()
  68. {
  69. WaitHandle.WaitAny (null, -1);
  70. }
  71. [Test]
  72. [ExpectedException (typeof (NotSupportedException))]
  73. public void WaitAny_WaitHandle_TooLarge_Int ()
  74. {
  75. WaitHandle.WaitAny (TooLarge, -1);
  76. }
  77. [Test]
  78. [ExpectedException (typeof (ArgumentNullException))]
  79. public void WaitAny_WaitHandle_Empty_Int ()
  80. {
  81. WaitHandle.WaitAny (Empty, -1);
  82. }
  83. [Test]
  84. public void WaitAny_WaitHandle_Int ()
  85. {
  86. // -1 is infinite
  87. Assert.AreEqual (0, WaitHandle.WaitAny (Single, -1), "WaitAny");
  88. }
  89. [Test]
  90. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  91. public void WaitAny_WaitHandle_Int_Negative ()
  92. {
  93. Assert.AreEqual (0, WaitHandle.WaitAny (Single, -2), "WaitAny");
  94. }
  95. [Test]
  96. [ExpectedException (typeof (ArgumentNullException))]
  97. public void WaitAny_WaitHandleNull_TimeSpan ()
  98. {
  99. WaitHandle.WaitAny (null, Infinite);
  100. }
  101. [Test]
  102. [ExpectedException (typeof (NotSupportedException))]
  103. public void WaitAny_WaitHandle_TooLarge_TimeSpan ()
  104. {
  105. WaitHandle.WaitAny (TooLarge, Infinite);
  106. }
  107. [Test]
  108. [ExpectedException (typeof (ArgumentNullException))]
  109. public void WaitAny_WaitHandle_Empty_TimeSpan ()
  110. {
  111. WaitHandle.WaitAny (Empty, Infinite);
  112. }
  113. [Test]
  114. public void WaitAny_WaitHandle_TimeSpan ()
  115. {
  116. Assert.AreEqual (Timeout.Infinite, (int) Infinite.TotalMilliseconds, "Infinite");
  117. Assert.AreEqual (0, WaitHandle.WaitAny (Single, Infinite), "WaitAny-Infinite");
  118. Assert.AreEqual (0, WaitHandle.WaitAny (Single, SmallNegative), "WaitAny-SmallNegative");
  119. }
  120. [Test]
  121. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  122. public void WaitAny_WaitHandle_TimeSpan_Negative ()
  123. {
  124. Assert.AreEqual (0, WaitHandle.WaitAny (Single, Negative), "WaitAny");
  125. }
  126. [Test]
  127. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  128. public void WaitAny_WaitHandle_TimeSpan_MaxValue ()
  129. {
  130. Assert.AreEqual (0, WaitHandle.WaitAny (Single, TimeSpan.MaxValue), "WaitAny");
  131. }
  132. [Test]
  133. [ExpectedException (typeof (ArgumentNullException))]
  134. public void WaitAll_WaitHandle_Null ()
  135. {
  136. WaitHandle.WaitAll (null);
  137. }
  138. [Test]
  139. [ExpectedException (typeof (NotSupportedException))]
  140. public void WaitAll_WaitHandle_TooLarge ()
  141. {
  142. WaitHandle.WaitAll (TooLarge);
  143. }
  144. [Test]
  145. [ExpectedException (typeof (ArgumentNullException))]
  146. public void WaitAll_WaitHandle_Empty ()
  147. {
  148. WaitHandle.WaitAll (Empty);
  149. }
  150. [Test]
  151. public void WaitAll_WaitHandle ()
  152. {
  153. Assert.IsTrue (WaitHandle.WaitAll (Single), "WaitAll");
  154. }
  155. [Test]
  156. [ExpectedException (typeof (ArgumentNullException))]
  157. public void WaitAll_WaitHandleNull_Int ()
  158. {
  159. WaitHandle.WaitAll (null, -1);
  160. }
  161. [Test]
  162. [ExpectedException (typeof (NotSupportedException))]
  163. public void WaitAll_WaitHandle_TooLarge_Int ()
  164. {
  165. WaitHandle.WaitAll (TooLarge, -1);
  166. }
  167. [Test]
  168. [ExpectedException (typeof (ArgumentNullException))]
  169. public void WaitAll_WaitHandle_Empty_Int ()
  170. {
  171. WaitHandle.WaitAll (Empty, -1);
  172. }
  173. [Test]
  174. public void WaitAll_WaitHandle_Int ()
  175. {
  176. // -1 is infinite
  177. Assert.IsTrue (WaitHandle.WaitAll (Single, -1), "WaitAll");
  178. }
  179. [Test]
  180. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  181. public void WaitAll_WaitHandle_Int_Negative ()
  182. {
  183. Assert.IsTrue (WaitHandle.WaitAll (Single, -2), "WaitAll");
  184. }
  185. [Test]
  186. [ExpectedException (typeof (ArgumentNullException))]
  187. public void WaitAll_WaitHandleNull_TimeSpan ()
  188. {
  189. WaitHandle.WaitAll (null, Infinite);
  190. }
  191. [Test]
  192. [ExpectedException (typeof (NotSupportedException))]
  193. public void WaitAll_WaitHandle_TooLarge_TimeSpan ()
  194. {
  195. WaitHandle.WaitAll (TooLarge, Infinite);
  196. }
  197. [Test]
  198. [ExpectedException (typeof (ArgumentNullException))]
  199. public void WaitAll_WaitHandle_Empty_TimeSpan ()
  200. {
  201. WaitHandle.WaitAll (Empty, Infinite);
  202. }
  203. [Test]
  204. public void WaitAll_WaitHandle_TimeSpan ()
  205. {
  206. Assert.AreEqual (Timeout.Infinite, (int) Infinite.TotalMilliseconds, "Infinite");
  207. Assert.IsTrue (WaitHandle.WaitAll (Single, Infinite), "WaitAll-Infinite");
  208. Assert.IsTrue (WaitHandle.WaitAll (Single, SmallNegative), "WaitAll-SmallNegative");
  209. }
  210. [Test]
  211. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  212. public void WaitAll_WaitHandle_TimeSpan_Negative ()
  213. {
  214. Assert.IsTrue (WaitHandle.WaitAll (Single, Negative), "WaitAll");
  215. }
  216. [Test]
  217. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  218. public void WaitAll_WaitHandle_TimeSpan_MaxValue ()
  219. {
  220. Assert.IsTrue (WaitHandle.WaitAll (Single, TimeSpan.MaxValue), "WaitAll");
  221. }
  222. [Test]
  223. public void WaitOne ()
  224. {
  225. Assert.IsTrue (Single [0].WaitOne (), "WaitOne");
  226. }
  227. [Test]
  228. public void WaitOne_Int ()
  229. {
  230. // -1 is infinite
  231. Assert.IsTrue (Single [0].WaitOne (-1), "WaitOne");
  232. }
  233. [Test]
  234. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  235. public void WaitOne_Int_Negative ()
  236. {
  237. Assert.IsTrue (Single [0].WaitOne (-2), "WaitOne");
  238. }
  239. [Test]
  240. public void WaitOne_TimeSpan ()
  241. {
  242. Assert.AreEqual (Timeout.Infinite, (int) Infinite.TotalMilliseconds, "Infinite");
  243. Assert.IsTrue (Single [0].WaitOne (Infinite), "WaitOne-Infinite");
  244. Assert.IsTrue (Single [0].WaitOne (SmallNegative), "WaitOne-SmallNegative");
  245. }
  246. [Test]
  247. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  248. public void WaitOne_TimeSpan_Negative ()
  249. {
  250. Assert.IsTrue (Single [0].WaitOne (Negative), "WaitOne");
  251. }
  252. [Test]
  253. [ExpectedException (typeof (ArgumentOutOfRangeException))]
  254. public void WaitOne_TimeSpan_MaxValue ()
  255. {
  256. Assert.IsTrue (Single [0].WaitOne (TimeSpan.MaxValue), "WaitOne");
  257. }
  258. [Test]
  259. [ExpectedException (typeof (ArgumentNullException))]
  260. public void WaitAll_Empty ()
  261. {
  262. WaitHandle.WaitAll (new WaitHandle [0]);
  263. }
  264. [Test]
  265. [ExpectedException (typeof (ArgumentException))]
  266. public void WaitAny_Empty ()
  267. {
  268. WaitHandle.WaitAny (new WaitHandle [0]);
  269. }
  270. [Test]
  271. public void InterrupedWaitAny ()
  272. {
  273. using (var m1 = new Mutex (true)) {
  274. using (var m2 = new Mutex (true)) {
  275. using (var done = new ManualResetEvent (false)) {
  276. var thread = new Thread (() =>
  277. {
  278. try {
  279. WaitHandle.WaitAny (new WaitHandle [] { m1, m2 });
  280. } catch (ThreadInterruptedException) {
  281. done.Set ();
  282. }
  283. });
  284. thread.Start ();
  285. Thread.Sleep (100); // wait a bit so the thread can enter its wait
  286. thread.Interrupt ();
  287. Assert.IsTrue (thread.Join (1000), "Join");
  288. Assert.IsTrue (done.WaitOne (1000), "done");
  289. m1.ReleaseMutex ();
  290. m2.ReleaseMutex ();
  291. }
  292. }
  293. }
  294. }
  295. [Test]
  296. public void InterrupedWaitAll ()
  297. {
  298. using (var m1 = new Mutex (true)) {
  299. using (var m2 = new Mutex (true)) {
  300. using (var done = new ManualResetEvent (false)) {
  301. var thread = new Thread (() =>
  302. {
  303. try {
  304. WaitHandle.WaitAll (new WaitHandle [] { m1, m2 });
  305. } catch (ThreadInterruptedException) {
  306. done.Set ();
  307. }
  308. });
  309. thread.Start ();
  310. Thread.Sleep (100); // wait a bit so the thread can enter its wait
  311. thread.Interrupt ();
  312. Assert.IsTrue (thread.Join (1000), "Join");
  313. Assert.IsTrue (done.WaitOne (1000), "done");
  314. m1.ReleaseMutex ();
  315. m2.ReleaseMutex ();
  316. }
  317. }
  318. }
  319. }
  320. [Test]
  321. public void InterrupedWaitOne ()
  322. {
  323. using (var m1 = new Mutex (true)) {
  324. using (var done = new ManualResetEvent (false)) {
  325. var thread = new Thread (() =>
  326. {
  327. try {
  328. m1.WaitOne ();
  329. } catch (ThreadInterruptedException) {
  330. done.Set ();
  331. }
  332. });
  333. thread.Start ();
  334. Thread.Sleep (100); // wait a bit so the thread can enter its wait
  335. thread.Interrupt ();
  336. Assert.IsTrue (thread.Join (1000), "Join");
  337. Assert.IsTrue (done.WaitOne (1000), "done");
  338. m1.ReleaseMutex ();
  339. }
  340. }
  341. }
  342. [Test]
  343. public void WaitOneWithAbandonedMutex ()
  344. {
  345. using (var m = new Mutex (false)) {
  346. var thread1 = new Thread (() => {
  347. m.WaitOne ();
  348. });
  349. thread1.Start ();
  350. thread1.Join (1000);
  351. try {
  352. m.WaitOne ();
  353. Assert.Fail ("Expected AbandonedMutexException");
  354. } catch (AbandonedMutexException) {
  355. }
  356. // Current thread should own the Mutex now
  357. var signalled = false;
  358. var thread2 = new Thread (() => {
  359. signalled = m.WaitOne (100);
  360. });
  361. thread2.Start ();
  362. thread2.Join (1000);
  363. Assert.IsFalse (signalled);
  364. // Since this thread owns the Mutex releasing it shouldn't fail
  365. m.ReleaseMutex ();
  366. // The Mutex should now be unowned
  367. try {
  368. m.ReleaseMutex ();
  369. Assert.Fail ("Expected ApplicationException");
  370. } catch (ApplicationException) {
  371. }
  372. }
  373. }
  374. [Test]
  375. public void WaitOneWithAbandonedMutexAndMultipleThreads ()
  376. {
  377. using (var m = new Mutex (true)) {
  378. var nonAbandoned = 0;
  379. var abandoned = 0;
  380. var n = 0;
  381. var threads = new List<Thread> ();
  382. for (int i = 0; i < 50; i++) {
  383. var thread = new Thread (() => {
  384. try {
  385. m.WaitOne ();
  386. nonAbandoned++;
  387. } catch (AbandonedMutexException) {
  388. abandoned++;
  389. }
  390. if (((n++) % 5) != 0)
  391. m.ReleaseMutex ();
  392. });
  393. thread.Start ();
  394. threads.Add (thread);
  395. }
  396. m.ReleaseMutex ();
  397. foreach (var thread in threads) {
  398. if (!thread.Join (1000)) {
  399. Assert.Fail ("Timed out");
  400. }
  401. }
  402. Assert.AreEqual (40, nonAbandoned);
  403. Assert.AreEqual (10, abandoned);
  404. }
  405. }
  406. [Test]
  407. public void WaitAnyWithSecondMutexAbandoned ()
  408. {
  409. using (var m1 = new Mutex (false)) {
  410. using (var m2 = new Mutex (false)) {
  411. var mainProceed = false;
  412. var thread2Proceed = false;
  413. var thread1 = new Thread (() => {
  414. m2.WaitOne ();
  415. });
  416. var thread2 = new Thread (() => {
  417. m1.WaitOne ();
  418. mainProceed = true;
  419. while (!thread2Proceed) {
  420. Thread.Sleep (10);
  421. }
  422. m1.ReleaseMutex ();
  423. });
  424. thread1.Start ();
  425. thread1.Join (1000);
  426. thread2.Start ();
  427. while (!mainProceed) {
  428. Thread.Sleep (10);
  429. }
  430. try {
  431. WaitHandle.WaitAny (new WaitHandle [] { m1, m2 });
  432. Assert.Fail ("Expected AbandonedMutexException");
  433. } catch (AbandonedMutexException e) {
  434. Assert.AreEqual (1, e.MutexIndex);
  435. Assert.AreEqual (m2, e.Mutex);
  436. } finally {
  437. thread2Proceed = true;
  438. thread2.Join (1000);
  439. }
  440. // Current thread should own the second Mutex now
  441. var signalled = -1;
  442. var thread3 = new Thread (() => {
  443. signalled = WaitHandle.WaitAny (new WaitHandle [] { m1, m2 }, 0);
  444. });
  445. thread3.Start ();
  446. thread3.Join (1000);
  447. Assert.AreEqual (0, signalled);
  448. // Since this thread owns the second Mutex releasing it shouldn't fail
  449. m2.ReleaseMutex ();
  450. // Second Mutex should now be unowned
  451. try {
  452. m2.ReleaseMutex ();
  453. Assert.Fail ("Expected ApplicationException");
  454. } catch (ApplicationException) {
  455. }
  456. // .NET allows the first Mutex which is now abandoned to be released multiple times by this thread
  457. m1.ReleaseMutex ();
  458. m1.ReleaseMutex ();
  459. }
  460. }
  461. }
  462. [Test]
  463. [ExpectedException (typeof (AbandonedMutexException))]
  464. public void WaitAllWithOneAbandonedMutex ()
  465. {
  466. using (var m1 = new Mutex (false)) {
  467. using (var m2 = new Mutex (false)) {
  468. var thread = new Thread (() => {
  469. m1.WaitOne ();
  470. });
  471. thread.Start ();
  472. thread.Join (1000);
  473. WaitHandle.WaitAll (new WaitHandle [] { m1, m2 });
  474. }
  475. }
  476. }
  477. #if MONO_FEATURE_THREAD_SUSPEND_RESUME
  478. [Test]
  479. public void WaitOneWithTimeoutAndSpuriousWake ()
  480. {
  481. /* This is to test that WaitEvent.WaitOne is not going to wait largely
  482. * more than its timeout. In this test, it shouldn't wait more than
  483. * 1500 milliseconds, with its timeout being 1000ms */
  484. using (ManualResetEvent mre = new ManualResetEvent (false))
  485. using (ManualResetEvent ready = new ManualResetEvent (false)) {
  486. var thread = new Thread (() => {
  487. ready.Set ();
  488. mre.WaitOne (1000);
  489. });
  490. thread.Start ();
  491. ready.WaitOne ();
  492. Thread.Sleep (10); // wait a bit so we enter mre.WaitOne
  493. var sw = Stopwatch.StartNew ();
  494. while (sw.ElapsedMilliseconds <= 500) {
  495. thread.Suspend ();
  496. thread.Resume ();
  497. }
  498. Assert.IsTrue (thread.Join (1000), "#1");
  499. }
  500. }
  501. [Test]
  502. public void WaitAnyWithTimeoutAndSpuriousWake ()
  503. {
  504. /* This is to test that WaitEvent.WaitAny is not going to wait largely
  505. * more than its timeout. In this test, it shouldn't wait more than
  506. * 1500 milliseconds, with its timeout being 1000ms */
  507. using (ManualResetEvent mre1 = new ManualResetEvent (false))
  508. using (ManualResetEvent mre2 = new ManualResetEvent (false))
  509. using (ManualResetEvent ready = new ManualResetEvent (false)) {
  510. var thread = new Thread (() => {
  511. ready.Set ();
  512. WaitHandle.WaitAny (new [] { mre1, mre2 }, 1000);
  513. });
  514. thread.Start ();
  515. ready.WaitOne ();
  516. Thread.Sleep (10); // wait a bit so we enter WaitHandle.WaitAny ({mre1, mre2})
  517. var sw = Stopwatch.StartNew ();
  518. while (sw.ElapsedMilliseconds <= 500) {
  519. thread.Suspend ();
  520. thread.Resume ();
  521. }
  522. Assert.IsTrue (thread.Join (1000), "#1");
  523. }
  524. }
  525. [Test]
  526. public void WaitAllWithTimeoutAndSpuriousWake ()
  527. {
  528. /* This is to test that WaitEvent.WaitAll is not going to wait largely
  529. * more than its timeout. In this test, it shouldn't wait more than
  530. * 1500 milliseconds, with its timeout being 1000ms */
  531. using (ManualResetEvent mre1 = new ManualResetEvent (false))
  532. using (ManualResetEvent mre2 = new ManualResetEvent (false))
  533. using (ManualResetEvent ready = new ManualResetEvent (false)) {
  534. var thread = new Thread (() => {
  535. ready.Set ();
  536. WaitHandle.WaitAll (new [] { mre1, mre2 }, 1000);
  537. });
  538. thread.Start ();
  539. ready.WaitOne ();
  540. Thread.Sleep (10); // wait a bit so we enter WaitHandle.WaitAll ({mre1, mre2})
  541. var sw = Stopwatch.StartNew ();
  542. while (sw.ElapsedMilliseconds <= 500) {
  543. thread.Suspend ();
  544. thread.Resume ();
  545. }
  546. Assert.IsTrue (thread.Join (1000), "#1");
  547. }
  548. }
  549. #endif // MONO_FEATURE_THREAD_SUSPEND_RESUME
  550. [Test]
  551. public static void SignalAndWait()
  552. {
  553. using (var eventToSignal = new AutoResetEvent (false))
  554. using (var eventToWait = new AutoResetEvent (false))
  555. {
  556. eventToWait.Set ();
  557. Assert.IsTrue (WaitHandle.SignalAndWait (eventToSignal, eventToWait), "#1");
  558. Assert.IsTrue (eventToSignal.WaitOne (), "#2");
  559. }
  560. }
  561. }
  562. }