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;
14 using System.Threading;
16 using Mono.Unix.Android;
17 using Mono.Unix.Native;
19 namespace MonoTests.Mono.Unix {
21 [TestFixture, Category ("NotOnWindows")]
22 public class UnixSignalTest {
24 // helper method to create a thread waiting on a UnixSignal
25 static Thread CreateWaitSignalThread (UnixSignal signal, int timeout)
27 Thread t1 = new Thread(delegate() {
28 DateTime start = DateTime.Now;
29 bool r = signal.WaitOne (timeout, false);
30 DateTime end = DateTime.Now;
31 Assert.AreEqual (signal.Count, 1);
32 Assert.AreEqual (r, true);
33 if ((end - start) > new TimeSpan (0, 0, timeout/1000))
34 throw new InvalidOperationException ("Signal slept too long");
39 // helper method to create a two-thread test
40 static void MultiThreadTest (UnixSignal signal, int timeout, ThreadStart tstart)
42 Thread t1 = CreateWaitSignalThread (signal, timeout);
43 Thread t2 = new Thread (tstart);
51 public void TestNestedInvocation()
53 UnixSignal s = new UnixSignal(Signum.SIGINT);
54 Thread a = new Thread(delegate() {
55 bool r = s.WaitOne (1000, false);
57 Thread b = new Thread(delegate() {
58 bool r = s.WaitOne (500, false);
67 public void TestWaitAnyFailsWithMore64Signals()
69 UnixSignal s1 = new UnixSignal(Signum.SIGINT);
70 UnixSignal[] signals = new UnixSignal[65];
71 for (int i=0; i<65; ++i)
74 Assert.That(UnixSignal.WaitAny(signals, new TimeSpan(0,0,1)), Is.EqualTo(-1));
78 public void TestConcurrentWaitOne()
80 UnixSignal s1 = new UnixSignal(Signum.SIGINT);
81 UnixSignal s2 = new UnixSignal(Signum.SIGINT);
82 Thread a = CreateWaitSignalThread(s1, 10000);
83 Thread b = CreateWaitSignalThread(s2, 5000);
84 Thread c = new Thread (delegate () {
86 Stdlib.raise (Signum.SIGINT);
94 Assert.That(s1.Count, Is.EqualTo(1), "Expected 1 signal raised");
95 Assert.That(s2.Count, Is.EqualTo(1), "Expected 1 signal raised");
99 public void TestConcurrentWaitOneSameInstance()
101 UnixSignal s1 = new UnixSignal(Signum.SIGINT);
102 Thread a = CreateWaitSignalThread(s1, 10000);
103 Thread b = CreateWaitSignalThread(s1, 10000);
104 Thread c = new Thread (delegate () {
106 Stdlib.raise (Signum.SIGINT);
117 [Category ("AndroidNotWorking")] // Crashes (silently) the runtime in similar fashion to real-time signals
118 public void TestSignumProperty ()
120 UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
121 Assert.That (signal1.Signum, Is.EqualTo (Signum.SIGSEGV));
125 [Category ("NotOnMac")]
126 public void TestRealTimeCstor ()
128 if (!TestHelper.CanUseRealTimeSignals ())
130 RealTimeSignum rts = new RealTimeSignum (0);
131 using (UnixSignal s = new UnixSignal (rts))
133 Assert.That(s.IsRealTimeSignal);
134 Assert.That(s.RealTimeSignum, Is.EqualTo (rts));
140 [Category ("NotOnMac")]
141 public void TestSignumPropertyThrows ()
143 if (!TestHelper.CanUseRealTimeSignals ())
145 UnixSignal signal1 = new UnixSignal (new RealTimeSignum (0));
146 Signum s = signal1.Signum;
150 [Category ("NotOnMac")]
151 public void TestRealTimeSignumProperty ()
153 if (!TestHelper.CanUseRealTimeSignals ())
155 RealTimeSignum rts = new RealTimeSignum (0);
156 UnixSignal signal1 = new UnixSignal (rts);
157 Assert.That (signal1.RealTimeSignum, Is.EqualTo (rts));
162 [Category ("NotOnMac")]
163 public void TestRealTimePropertyThrows ()
165 if (!TestHelper.CanUseRealTimeSignals ())
167 UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
168 RealTimeSignum s = signal1.RealTimeSignum;
172 [Category ("NotOnMac")]
173 public void TestRaiseRTMINSignal ()
175 if (!TestHelper.CanUseRealTimeSignals ())
177 RealTimeSignum rts = new RealTimeSignum (0);
178 using (UnixSignal signal = new UnixSignal (rts))
180 MultiThreadTest (signal, 5000, delegate() {
188 [Category ("NotOnMac")]
189 public void TestRaiseRTMINPlusOneSignal ()
191 if (!TestHelper.CanUseRealTimeSignals ())
193 /*this number is a guestimate, but it's ok*/
194 for (int i = 1; i < 10; ++i) {
195 RealTimeSignum rts = new RealTimeSignum (i);
198 signal = new UnixSignal (rts);
199 } catch (ArgumentException) { /*skip the ones that are unavailable*/
204 MultiThreadTest (signal, 5000, delegate() {
211 Assert.IsTrue (false, "#1 No available RT signal");
215 [Category ("NotOnMac")]
216 public void TestCanRegisterRTSignalMultipleTimes ()
218 if (!TestHelper.CanUseRealTimeSignals ())
220 /*this number is a guestimate, but it's ok*/
221 for (int i = 1; i < 10; ++i) {
222 RealTimeSignum rts = new RealTimeSignum (i);
225 signal = new UnixSignal (rts);
226 } catch (ArgumentException) { /*skip the ones that are unavailable*/
230 using (UnixSignal signal2 = new UnixSignal (rts))
235 } catch (ArgumentException) { /*skip the ones that are unavailable*/
236 Assert.IsTrue (false, "#1 Could not register second signal handler");
239 Assert.IsTrue (false, "#2 No available RT signal");
243 public void TestRaise ()
245 Thread t1 = new Thread (delegate () {
246 using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
247 DateTime start = DateTime.Now;
248 bool r = a.WaitOne (5000, false);
249 DateTime end = DateTime.Now;
250 Assert.AreEqual (a.Count, 1);
251 Assert.AreEqual (r, true);
252 if ((end - start) > new TimeSpan (0, 0, 5))
253 throw new InvalidOperationException ("Signal slept too long");
256 Thread t2 = new Thread (delegate () {
258 Stdlib.raise (Signum.SIGINT);
267 public void TestRaiseAny ()
269 Thread t1 = new Thread (delegate () {
270 using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
271 DateTime start = DateTime.Now;
272 int idx = UnixSignal.WaitAny (new UnixSignal[]{a}, 5000);
273 DateTime end = DateTime.Now;
274 Assert.AreEqual (idx, 0);
275 Assert.AreEqual (a.Count, 1);
276 if ((end - start) > new TimeSpan (0, 0, 5))
277 throw new InvalidOperationException ("Signal slept too long");
280 Thread t2 = new Thread (delegate () {
282 Stdlib.raise (Signum.SIGINT);
291 public void TestSeparation ()
293 Thread t1 = new Thread (delegate () {
294 using (UnixSignal a = new UnixSignal (Signum.SIGINT))
295 using (UnixSignal b = new UnixSignal (Signum.SIGTERM)) {
296 DateTime start = DateTime.Now;
297 int idx = UnixSignal.WaitAny (new UnixSignal[]{a, b}, 5000);
298 DateTime end = DateTime.Now;
299 Assert.AreEqual (idx, 1);
300 Assert.AreEqual (a.Count, 0);
301 Assert.AreEqual (b.Count, 1);
302 if ((end - start) > new TimeSpan (0, 0, 5))
303 throw new InvalidOperationException ("Signal slept too long");
306 Thread t2 = new Thread (delegate () {
308 Stdlib.raise (Signum.SIGTERM);
317 public void TestNoEmit ()
319 using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
320 DateTime start = DateTime.Now;
321 bool r = u.WaitOne (5100, false);
322 Assert.AreEqual (r, false);
323 DateTime end = DateTime.Now;
324 if ((end - start) < new TimeSpan (0, 0, 5))
325 throw new InvalidOperationException ("Signal didn't block for 5s; blocked for " + (end-start).ToString());
330 public void TestNoEmitAny ()
332 using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
333 int idx = UnixSignal.WaitAny (new UnixSignal[]{u}, 5100);
334 Assert.AreEqual (idx, 5100);
339 public void TestDispose1 ()
341 UnixSignal a = new UnixSignal (Signum.SIGINT);
342 UnixSignal b = new UnixSignal (Signum.SIGINT);
344 Stdlib.raise (Signum.SIGINT);
345 SleepUntilSignaled (a);
347 Assert.AreEqual (a.Count, 1);
348 Assert.AreEqual (b.Count, 1);
353 Stdlib.raise (Signum.SIGINT);
354 SleepUntilSignaled (b);
355 Assert.AreEqual (b.Count, 1);
360 static void SleepUntilSignaled (UnixSignal s)
362 for (int i = 0; i < 10; ++i) {
370 public void TestDispose2 ()
372 UnixSignal a = new UnixSignal (Signum.SIGINT);
373 UnixSignal b = new UnixSignal (Signum.SIGINT);
375 Stdlib.raise (Signum.SIGINT);
376 SleepUntilSignaled (a);
378 Assert.AreEqual (a.Count, 1);
379 Assert.AreEqual (b.Count, 1);
384 Stdlib.raise (Signum.SIGINT);
385 SleepUntilSignaled (a);
386 Assert.AreEqual (a.Count, 1);
392 [Category ("AndroidNotWorking")] // Android 4.4.4 doesn't have signal(2)
393 public void TestSignalActionInteraction ()
395 using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
396 Stdlib.SetSignalAction (Signum.SIGINT, SignalAction.Ignore);
397 Stdlib.raise (Signum.SIGINT);
398 Assert.AreEqual (a.Count, 0); // never invoked
402 static readonly Signum[] signals = new Signum[] {
403 Signum.SIGHUP, Signum.SIGINT, Signum.SIGTERM, Signum.SIGCONT,
406 const int StormCount = 100000;
409 public void TestRaiseStorm ()
411 UnixSignal[] usignals = CreateSignals (signals);
412 Thread[] threads = new Thread[]{
413 CreateRaiseStormThread (StormCount/4),
414 CreateRaiseStormThread (StormCount/4),
415 CreateRaiseStormThread (StormCount/4),
416 CreateRaiseStormThread (StormCount/4),
418 foreach (Thread t in threads)
420 foreach (Thread t in threads)
422 AssertCountSet (usignals);
423 // signal delivery might take some time, wait a bit before closing
424 // the UnixSignal so we can ignore it and not terminate the process
425 // when a SIGHUP/SIGTERM arrives afterwards
427 CloseSignals (usignals);
430 static void AssertCount (UnixSignal[] usignals)
433 foreach (UnixSignal s in usignals)
435 Assert.AreEqual (sum, StormCount);
438 static void AssertCountSet (UnixSignal[] usignals)
440 foreach (UnixSignal s in usignals) {
441 Assert.IsTrue (s.Count > 0);
445 static UnixSignal[] CreateSignals (Signum[] signals)
447 UnixSignal[] s = new UnixSignal [signals.Length];
448 for (int i = 0; i < signals.Length; ++i)
449 s [i] = new UnixSignal (signals [i]);
453 static void CloseSignals (UnixSignal[] signals)
455 foreach (UnixSignal s in signals)
459 // Create thread that issues many signals from a set of harmless signals
460 static Thread CreateRaiseStormThread (int max)
462 return new Thread (delegate () {
463 Random r = new Random (Environment.TickCount);
464 for (int i = 0; i < max; ++i) {
465 int n = r.Next (0, signals.Length);
466 Stdlib.raise (signals [n]);
472 public void TestAddRemove ()
474 UnixSignal[] usignals = CreateSignals (signals);
476 Thread[] threads = new Thread[]{
477 CreateRaiseStormThread (StormCount),
478 CreateSignalCreatorThread (),
481 foreach (Thread t in threads)
483 foreach (Thread t in threads)
486 AssertCountSet (usignals);
487 CloseSignals (usignals);
490 // Create thread that repeatedly registers then unregisters signal handlers
491 static Thread CreateSignalCreatorThread ()
493 return new Thread (delegate () {
494 Random r = new Random (Environment.TickCount << 4);
495 for (int i = 0; i < StormCount; ++i) {
496 int n = r.Next (0, signals.Length);
497 using (new UnixSignal (signals [n]))
498 using (new UnixSignal (signals [(n+1)%signals.Length]))
499 using (new UnixSignal (signals [(n+2)%signals.Length]))
500 using (new UnixSignal (signals [(n+3)%signals.Length])) {
507 public void TestWaitAny ()
509 UnixSignal[] usignals = CreateSignals (signals);
511 Thread[] threads = new Thread[]{
512 CreateRaiseStormThread (StormCount),
513 CreateSignalCreatorThread (),
514 CreateWaitAnyThread (usignals [0], usignals [2]),
515 CreateWaitAnyThread (usignals [1], usignals [3]),
516 CreateWaitAnyThread (usignals [1], usignals [2]),
519 foreach (Thread t in threads)
521 foreach (Thread t in threads)
524 AssertCountSet (usignals);
525 CloseSignals (usignals);
528 // Create thread that blocks until at least one of the given signals is received
529 static Thread CreateWaitAnyThread (params UnixSignal[] usignals)
531 return new Thread (delegate () {
532 int idx = UnixSignal.WaitAny (usignals, 30000);
533 Assert.AreEqual (idx >= 0 && idx < usignals.Length, true);