2 // UnixSignalTest.cs - NUnit Test Cases for Mono.Unix.UnixSignal
5 // Jonathan Pryor <jonpryor@vt.edu>
7 // (C) 2008 Jonathan Pryor
10 using NUnit.Framework;
12 using NUnit.Framework.SyntaxHelpers;
16 using System.Threading;
18 using Mono.Unix.Android;
19 using Mono.Unix.Native;
21 namespace NUnit.Framework.SyntaxHelpers { class Dummy {} }
23 namespace MonoTests.Mono.Unix {
26 public class UnixSignalTest {
28 // helper method to create a thread waiting on a UnixSignal
29 static Thread CreateWaitSignalThread (UnixSignal signal, int timeout)
31 Thread t1 = new Thread(delegate() {
32 DateTime start = DateTime.Now;
33 bool r = signal.WaitOne (timeout, false);
34 DateTime end = DateTime.Now;
35 Assert.AreEqual (signal.Count, 1);
36 Assert.AreEqual (r, true);
37 if ((end - start) > new TimeSpan (0, 0, timeout/1000))
38 throw new InvalidOperationException ("Signal slept too long");
43 // helper method to create a two-thread test
44 static void MultiThreadTest (UnixSignal signal, int timeout, ThreadStart tstart)
46 Thread t1 = CreateWaitSignalThread (signal, timeout);
47 Thread t2 = new Thread (tstart);
55 public void TestNestedInvocation()
57 UnixSignal s = new UnixSignal(Signum.SIGINT);
58 Thread a = new Thread(delegate() {
59 bool r = s.WaitOne (1000, false);
61 Thread b = new Thread(delegate() {
62 bool r = s.WaitOne (500, false);
71 public void TestWaitAnyFailsWithMore64Signals()
73 UnixSignal s1 = new UnixSignal(Signum.SIGINT);
74 UnixSignal[] signals = new UnixSignal[65];
75 for (int i=0; i<65; ++i)
78 Assert.That(UnixSignal.WaitAny(signals, new TimeSpan(0,0,1)), Is.EqualTo(-1));
82 public void TestConcurrentWaitOne()
84 UnixSignal s1 = new UnixSignal(Signum.SIGINT);
85 UnixSignal s2 = new UnixSignal(Signum.SIGINT);
86 Thread a = CreateWaitSignalThread(s1, 10000);
87 Thread b = CreateWaitSignalThread(s2, 5000);
88 Thread c = new Thread (delegate () {
90 Stdlib.raise (Signum.SIGINT);
98 Assert.That(s1.Count, Is.EqualTo(1), "Expected 1 signal raised");
99 Assert.That(s2.Count, Is.EqualTo(1), "Expected 1 signal raised");
103 public void TestConcurrentWaitOneSameInstance()
105 UnixSignal s1 = new UnixSignal(Signum.SIGINT);
106 Thread a = CreateWaitSignalThread(s1, 10000);
107 Thread b = CreateWaitSignalThread(s1, 10000);
108 Thread c = new Thread (delegate () {
110 Stdlib.raise (Signum.SIGINT);
121 [Category ("AndroidNotWorking")] // Crashes (silently) the runtime in similar fashion to real-time signals
122 public void TestSignumProperty ()
124 UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
125 Assert.That (signal1.Signum, Is.EqualTo (Signum.SIGSEGV));
129 [Category ("NotOnMac")]
130 public void TestRealTimeCstor ()
132 if (!TestHelper.CanUseRealTimeSignals ())
134 RealTimeSignum rts = new RealTimeSignum (0);
135 using (UnixSignal s = new UnixSignal (rts))
137 Assert.That(s.IsRealTimeSignal);
138 Assert.That(s.RealTimeSignum, Is.EqualTo (rts));
144 [Category ("NotOnMac")]
145 public void TestSignumPropertyThrows ()
147 if (!TestHelper.CanUseRealTimeSignals ())
149 UnixSignal signal1 = new UnixSignal (new RealTimeSignum (0));
150 Signum s = signal1.Signum;
154 [Category ("NotOnMac")]
155 public void TestRealTimeSignumProperty ()
157 if (!TestHelper.CanUseRealTimeSignals ())
159 RealTimeSignum rts = new RealTimeSignum (0);
160 UnixSignal signal1 = new UnixSignal (rts);
161 Assert.That (signal1.RealTimeSignum, Is.EqualTo (rts));
166 [Category ("NotOnMac")]
167 public void TestRealTimePropertyThrows ()
169 if (!TestHelper.CanUseRealTimeSignals ())
171 UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
172 RealTimeSignum s = signal1.RealTimeSignum;
176 [Category ("NotOnMac")]
177 public void TestRaiseRTMINSignal ()
179 if (!TestHelper.CanUseRealTimeSignals ())
181 RealTimeSignum rts = new RealTimeSignum (0);
182 using (UnixSignal signal = new UnixSignal (rts))
184 MultiThreadTest (signal, 5000, delegate() {
192 [Category ("NotOnMac")]
193 public void TestRaiseRTMINPlusOneSignal ()
195 if (!TestHelper.CanUseRealTimeSignals ())
197 /*this number is a guestimate, but it's ok*/
198 for (int i = 1; i < 10; ++i) {
199 RealTimeSignum rts = new RealTimeSignum (i);
202 signal = new UnixSignal (rts);
203 } catch (ArgumentException) { /*skip the ones that are unavailable*/
208 MultiThreadTest (signal, 5000, delegate() {
215 Assert.IsTrue (false, "#1 No available RT signal");
219 [Category ("NotOnMac")]
220 public void TestCanRegisterRTSignalMultipleTimes ()
222 if (!TestHelper.CanUseRealTimeSignals ())
224 /*this number is a guestimate, but it's ok*/
225 for (int i = 1; i < 10; ++i) {
226 RealTimeSignum rts = new RealTimeSignum (i);
229 signal = new UnixSignal (rts);
230 } catch (ArgumentException) { /*skip the ones that are unavailable*/
234 using (UnixSignal signal2 = new UnixSignal (rts))
239 } catch (ArgumentException) { /*skip the ones that are unavailable*/
240 Assert.IsTrue (false, "#1 Could not register second signal handler");
243 Assert.IsTrue (false, "#2 No available RT signal");
247 public void TestRaise ()
249 Thread t1 = new Thread (delegate () {
250 using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
251 DateTime start = DateTime.Now;
252 bool r = a.WaitOne (5000, false);
253 DateTime end = DateTime.Now;
254 Assert.AreEqual (a.Count, 1);
255 Assert.AreEqual (r, true);
256 if ((end - start) > new TimeSpan (0, 0, 5))
257 throw new InvalidOperationException ("Signal slept too long");
260 Thread t2 = new Thread (delegate () {
262 Stdlib.raise (Signum.SIGINT);
271 public void TestRaiseAny ()
273 Thread t1 = new Thread (delegate () {
274 using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
275 DateTime start = DateTime.Now;
276 int idx = UnixSignal.WaitAny (new UnixSignal[]{a}, 5000);
277 DateTime end = DateTime.Now;
278 Assert.AreEqual (idx, 0);
279 Assert.AreEqual (a.Count, 1);
280 if ((end - start) > new TimeSpan (0, 0, 5))
281 throw new InvalidOperationException ("Signal slept too long");
284 Thread t2 = new Thread (delegate () {
286 Stdlib.raise (Signum.SIGINT);
295 public void TestSeparation ()
297 Thread t1 = new Thread (delegate () {
298 using (UnixSignal a = new UnixSignal (Signum.SIGINT))
299 using (UnixSignal b = new UnixSignal (Signum.SIGTERM)) {
300 DateTime start = DateTime.Now;
301 int idx = UnixSignal.WaitAny (new UnixSignal[]{a, b}, 5000);
302 DateTime end = DateTime.Now;
303 Assert.AreEqual (idx, 1);
304 Assert.AreEqual (a.Count, 0);
305 Assert.AreEqual (b.Count, 1);
306 if ((end - start) > new TimeSpan (0, 0, 5))
307 throw new InvalidOperationException ("Signal slept too long");
310 Thread t2 = new Thread (delegate () {
312 Stdlib.raise (Signum.SIGTERM);
321 public void TestNoEmit ()
323 using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
324 DateTime start = DateTime.Now;
325 bool r = u.WaitOne (5100, false);
326 Assert.AreEqual (r, false);
327 DateTime end = DateTime.Now;
328 if ((end - start) < new TimeSpan (0, 0, 5))
329 throw new InvalidOperationException ("Signal didn't block for 5s; blocked for " + (end-start).ToString());
334 public void TestNoEmitAny ()
336 using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
337 int idx = UnixSignal.WaitAny (new UnixSignal[]{u}, 5100);
338 Assert.AreEqual (idx, 5100);
343 public void TestDispose1 ()
345 UnixSignal a = new UnixSignal (Signum.SIGINT);
346 UnixSignal b = new UnixSignal (Signum.SIGINT);
348 Stdlib.raise (Signum.SIGINT);
349 SleepUntilSignaled (a);
351 Assert.AreEqual (a.Count, 1);
352 Assert.AreEqual (b.Count, 1);
357 Stdlib.raise (Signum.SIGINT);
358 SleepUntilSignaled (b);
359 Assert.AreEqual (b.Count, 1);
364 static void SleepUntilSignaled (UnixSignal s)
366 for (int i = 0; i < 10; ++i) {
374 public void TestDispose2 ()
376 UnixSignal a = new UnixSignal (Signum.SIGINT);
377 UnixSignal b = new UnixSignal (Signum.SIGINT);
379 Stdlib.raise (Signum.SIGINT);
380 SleepUntilSignaled (a);
382 Assert.AreEqual (a.Count, 1);
383 Assert.AreEqual (b.Count, 1);
388 Stdlib.raise (Signum.SIGINT);
389 SleepUntilSignaled (a);
390 Assert.AreEqual (a.Count, 1);
396 [Category ("AndroidNotWorking")] // Android 4.4.4 doesn't have signal(2)
397 public void TestSignalActionInteraction ()
399 using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
400 Stdlib.SetSignalAction (Signum.SIGINT, SignalAction.Ignore);
401 Stdlib.raise (Signum.SIGINT);
402 Assert.AreEqual (a.Count, 0); // never invoked
406 static readonly Signum[] signals = new Signum[] {
407 Signum.SIGHUP, Signum.SIGINT, Signum.SIGTERM, Signum.SIGCONT,
410 const int StormCount = 100000;
413 public void TestRaiseStorm ()
415 UnixSignal[] usignals = CreateSignals (signals);
416 Thread[] threads = new Thread[]{
417 CreateRaiseStormThread (StormCount/4),
418 CreateRaiseStormThread (StormCount/4),
419 CreateRaiseStormThread (StormCount/4),
420 CreateRaiseStormThread (StormCount/4),
422 foreach (Thread t in threads)
424 foreach (Thread t in threads)
426 AssertCountSet (usignals);
427 // signal delivery might take some time, wait a bit before closing
428 // the UnixSignal so we can ignore it and not terminate the process
429 // when a SIGHUP/SIGTERM arrives afterwards
431 CloseSignals (usignals);
434 static void AssertCount (UnixSignal[] usignals)
437 foreach (UnixSignal s in usignals)
439 Assert.AreEqual (sum, StormCount);
442 static void AssertCountSet (UnixSignal[] usignals)
444 foreach (UnixSignal s in usignals) {
445 Assert.IsTrue (s.Count > 0);
449 static UnixSignal[] CreateSignals (Signum[] signals)
451 UnixSignal[] s = new UnixSignal [signals.Length];
452 for (int i = 0; i < signals.Length; ++i)
453 s [i] = new UnixSignal (signals [i]);
457 static void CloseSignals (UnixSignal[] signals)
459 foreach (UnixSignal s in signals)
463 // Create thread that issues many signals from a set of harmless signals
464 static Thread CreateRaiseStormThread (int max)
466 return new Thread (delegate () {
467 Random r = new Random (Environment.TickCount);
468 for (int i = 0; i < max; ++i) {
469 int n = r.Next (0, signals.Length);
470 Stdlib.raise (signals [n]);
476 public void TestAddRemove ()
478 UnixSignal[] usignals = CreateSignals (signals);
480 Thread[] threads = new Thread[]{
481 CreateRaiseStormThread (StormCount),
482 CreateSignalCreatorThread (),
485 foreach (Thread t in threads)
487 foreach (Thread t in threads)
490 AssertCountSet (usignals);
491 CloseSignals (usignals);
494 // Create thread that repeatedly registers then unregisters signal handlers
495 static Thread CreateSignalCreatorThread ()
497 return new Thread (delegate () {
498 Random r = new Random (Environment.TickCount << 4);
499 for (int i = 0; i < StormCount; ++i) {
500 int n = r.Next (0, signals.Length);
501 using (new UnixSignal (signals [n]))
502 using (new UnixSignal (signals [(n+1)%signals.Length]))
503 using (new UnixSignal (signals [(n+2)%signals.Length]))
504 using (new UnixSignal (signals [(n+3)%signals.Length])) {
511 public void TestWaitAny ()
513 UnixSignal[] usignals = CreateSignals (signals);
515 Thread[] threads = new Thread[]{
516 CreateRaiseStormThread (StormCount),
517 CreateSignalCreatorThread (),
518 CreateWaitAnyThread (usignals [0], usignals [2]),
519 CreateWaitAnyThread (usignals [1], usignals [3]),
520 CreateWaitAnyThread (usignals [1], usignals [2]),
523 foreach (Thread t in threads)
525 foreach (Thread t in threads)
528 AssertCountSet (usignals);
529 CloseSignals (usignals);
532 // Create thread that blocks until at least one of the given signals is received
533 static Thread CreateWaitAnyThread (params UnixSignal[] usignals)
535 return new Thread (delegate () {
536 int idx = UnixSignal.WaitAny (usignals, 30000);
537 Assert.AreEqual (idx >= 0 && idx < usignals.Length, true);