Merge pull request #1949 from lewurm/fixtype
[mono.git] / mcs / class / Mono.Posix / Test / Mono.Unix / UnixSignalTest.cs
1 //
2 // UnixSignalTest.cs - NUnit Test Cases for Mono.Unix.UnixSignal
3 //
4 // Authors:
5 //      Jonathan Pryor  <jonpryor@vt.edu>
6 //
7 // (C) 2008 Jonathan Pryor
8 //
9
10 using NUnit.Framework;
11 #if !MONODROID
12 using NUnit.Framework.SyntaxHelpers;
13 #endif
14 using System;
15 using System.Text;
16 using System.Threading;
17 using Mono.Unix;
18 using Mono.Unix.Android;
19 using Mono.Unix.Native;
20 #if !MONODROID
21 namespace NUnit.Framework.SyntaxHelpers { class Dummy {} }
22 #endif
23 namespace MonoTests.Mono.Unix {
24
25         [TestFixture]
26         public class UnixSignalTest {
27
28                 // helper method to create a thread waiting on a UnixSignal
29                 static Thread CreateWaitSignalThread (UnixSignal signal, int timeout)
30                 {
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");
39                                         });
40                         return t1;
41                 }
42
43                 // helper method to create a two-thread test
44                 static void MultiThreadTest (UnixSignal signal, int timeout, ThreadStart tstart)
45                 {
46                         Thread t1 = CreateWaitSignalThread (signal, timeout);
47                         Thread t2 = new Thread (tstart);
48                         t1.Start ();
49                         t2.Start ();
50                         t1.Join ();
51                         t2.Join ();
52                 }
53
54                 [Test]
55                 public void TestNestedInvocation()
56                 {
57                         UnixSignal s = new UnixSignal(Signum.SIGINT);
58                         Thread a = new Thread(delegate() {
59                                         bool r = s.WaitOne (1000, false);
60       });
61                         Thread b = new Thread(delegate() {
62                                         bool r = s.WaitOne (500, false);
63       });
64                         a.Start();
65                         b.Start();
66                         a.Join();
67                         b.Join();
68                 }
69
70                 [Test]
71                 public void TestWaitAnyFailsWithMore64Signals()
72                 {
73                         UnixSignal s1 = new UnixSignal(Signum.SIGINT);
74                         UnixSignal[] signals = new UnixSignal[65];
75                         for (int i=0; i<65; ++i)
76                                 signals[i] = s1;
77                         
78                         Assert.That(UnixSignal.WaitAny(signals, new TimeSpan(0,0,1)), Is.EqualTo(-1));
79                 }
80
81                 [Test]
82                 public void TestConcurrentWaitOne()
83                 {
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 () {
89                                         Thread.Sleep (1000);
90                                         Stdlib.raise (Signum.SIGINT);
91                         });
92                         a.Start();
93                         b.Start();
94                         c.Start();
95                         a.Join();
96                         b.Join();
97                         c.Join();
98                         Assert.That(s1.Count, Is.EqualTo(1), "Expected 1 signal raised");
99                         Assert.That(s2.Count, Is.EqualTo(1), "Expected 1 signal raised");
100                 }
101
102                 [Test]
103                 public void TestConcurrentWaitOneSameInstance()
104                 {
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 () {
109                                         Thread.Sleep (500);
110                                         Stdlib.raise (Signum.SIGINT);
111                         });
112                         a.Start();
113                         b.Start();
114                         c.Start();
115                         a.Join();
116                         b.Join();
117                         c.Join();
118                 }
119
120                 [Test]
121                 [Category ("AndroidNotWorking")] // Crashes (silently) the runtime in similar fashion to real-time signals
122                 public void TestSignumProperty ()
123                 {
124                         UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
125                         Assert.That (signal1.Signum, Is.EqualTo (Signum.SIGSEGV));
126                 }
127         
128                 [Test]
129                 [Category ("NotOnMac")]
130                 public void TestRealTimeCstor ()
131                 {
132                         if (!TestHelper.CanUseRealTimeSignals ())
133                                 return;
134                         RealTimeSignum rts = new RealTimeSignum (0);
135                         using (UnixSignal s = new UnixSignal (rts))
136                         {
137                                 Assert.That(s.IsRealTimeSignal);
138                                 Assert.That(s.RealTimeSignum, Is.EqualTo (rts));
139                         }
140                 }
141
142                 [Test]
143                 [ExpectedException]
144                 [Category ("NotOnMac")]
145                 public void TestSignumPropertyThrows ()
146                 {
147                         if (!TestHelper.CanUseRealTimeSignals ())
148                                 return;
149                         UnixSignal signal1 = new UnixSignal (new RealTimeSignum (0));
150                         Signum s = signal1.Signum;
151                 }
152
153                 [Test]
154                 [Category ("NotOnMac")]
155                 public void TestRealTimeSignumProperty ()
156                 {
157                         if (!TestHelper.CanUseRealTimeSignals ())
158                                 return;
159                         RealTimeSignum rts = new RealTimeSignum (0);
160                         UnixSignal signal1 = new UnixSignal (rts);
161                         Assert.That (signal1.RealTimeSignum, Is.EqualTo (rts));
162                 }
163         
164                 [Test]
165                 [ExpectedException]
166                 [Category ("NotOnMac")]
167                 public void TestRealTimePropertyThrows ()
168                 {
169                         if (!TestHelper.CanUseRealTimeSignals ())
170                                 return;
171                         UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
172                         RealTimeSignum s = signal1.RealTimeSignum;
173                 }
174
175                 [Test]
176                 [Category ("NotOnMac")]
177                 public void TestRaiseRTMINSignal ()
178                 {
179                         if (!TestHelper.CanUseRealTimeSignals ())
180                                 return;
181                         RealTimeSignum rts = new RealTimeSignum (0);
182                         using (UnixSignal signal = new UnixSignal (rts))
183                         {
184                                 MultiThreadTest (signal, 5000, delegate() {
185                                         Thread.Sleep (1000);
186                                         Stdlib.raise (rts);
187                                         });
188                         }
189                 }
190
191                 [Test]
192                 [Category ("NotOnMac")]
193                 public void TestRaiseRTMINPlusOneSignal ()
194                 {
195                         if (!TestHelper.CanUseRealTimeSignals ())
196                                 return;
197                         /*this number is a guestimate, but it's ok*/
198                         for (int i = 1; i < 10; ++i) {
199                                 RealTimeSignum rts = new RealTimeSignum (i);
200                                 UnixSignal signal;
201                                 try {
202                                         signal  = new UnixSignal (rts);
203                                 } catch (ArgumentException) { /*skip the ones that are unavailable*/
204                                         continue;
205                                 }
206                                 using (signal)
207                                 {
208                                         MultiThreadTest (signal, 5000, delegate() {
209                                                 Thread.Sleep(1000);
210                                                 Stdlib.raise(rts);
211                                                 });
212                                 }
213                                 return;
214                         }
215                         Assert.IsTrue (false, "#1 No available RT signal");
216                 }
217
218                 [Test]
219                 [Category ("NotOnMac")]
220                 public void TestCanRegisterRTSignalMultipleTimes ()
221                 {
222                         if (!TestHelper.CanUseRealTimeSignals ())
223                                 return;
224                         /*this number is a guestimate, but it's ok*/
225                         for (int i = 1; i < 10; ++i) {
226                                 RealTimeSignum rts = new RealTimeSignum (i);
227                                 UnixSignal signal;
228                                 try {
229                                         signal  = new UnixSignal (rts);
230                                 } catch (ArgumentException) { /*skip the ones that are unavailable*/
231                                         continue;
232                                 }
233                                 try {
234                                         using (UnixSignal signal2 =  new UnixSignal (rts))
235                                         {
236                                                 //ok
237                                                 return;
238                                         }
239                                 } catch (ArgumentException) { /*skip the ones that are unavailable*/
240                                                 Assert.IsTrue (false, "#1 Could not register second signal handler");
241                                 }
242                         }
243                         Assert.IsTrue (false, "#2 No available RT signal");
244                 }
245
246                 [Test]
247                 public void TestRaise ()
248                 {
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");
258                                         }
259                         });
260                         Thread t2 = new Thread (delegate () {
261                                         Thread.Sleep (1000);
262                                         Stdlib.raise (Signum.SIGINT);
263                         });
264                         t1.Start ();
265                         t2.Start ();
266                         t1.Join ();
267                         t2.Join ();
268                 }
269
270                 [Test]
271                 public void TestRaiseAny ()
272                 {
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");
282                                         }
283                         });
284                         Thread t2 = new Thread (delegate () {
285                                         Thread.Sleep (1000);
286                                         Stdlib.raise (Signum.SIGINT);
287                         });
288                         t1.Start ();
289                         t2.Start ();
290                         t1.Join ();
291                         t2.Join ();
292                 }
293
294                 [Test]
295                 public void TestSeparation ()
296                 {
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");
308                                         }
309                         });
310                         Thread t2 = new Thread (delegate () {
311                                         Thread.Sleep (1000);
312                                         Stdlib.raise (Signum.SIGTERM);
313                         });
314                         t1.Start ();
315                         t2.Start ();
316                         t1.Join ();
317                         t2.Join ();
318                 }
319
320                 [Test]
321                 public void TestNoEmit ()
322                 {
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());
330                         }
331                 }
332
333                 [Test]
334                 public void TestNoEmitAny ()
335                 {
336                         using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
337                                 int idx = UnixSignal.WaitAny (new UnixSignal[]{u}, 5100);
338                                 Assert.AreEqual (idx, 5100);
339                         }
340                 }
341
342                 [Test]
343                 public void TestDispose1 ()
344                 {
345                         UnixSignal a = new UnixSignal (Signum.SIGINT);
346                         UnixSignal b = new UnixSignal (Signum.SIGINT);
347
348                         Stdlib.raise (Signum.SIGINT);
349                         SleepUntilSignaled (a);
350
351                         Assert.AreEqual (a.Count, 1);
352                         Assert.AreEqual (b.Count, 1);
353
354                         a.Close ();
355                         b.Reset ();
356
357                         Stdlib.raise (Signum.SIGINT);
358                         SleepUntilSignaled (b);
359                         Assert.AreEqual (b.Count, 1);
360
361                         b.Close ();
362                 }
363
364                 static void SleepUntilSignaled (UnixSignal s)
365                 {
366                         for (int i = 0; i < 10; ++i) {
367                                 if (s.Count > 0)
368                                         break;
369                                 Thread.Sleep (100);
370                         }
371                 }
372
373                 [Test]
374                 public void TestDispose2 ()
375                 {
376                         UnixSignal a = new UnixSignal (Signum.SIGINT);
377                         UnixSignal b = new UnixSignal (Signum.SIGINT);
378
379                         Stdlib.raise (Signum.SIGINT);
380                         SleepUntilSignaled (a);
381
382                         Assert.AreEqual (a.Count, 1);
383                         Assert.AreEqual (b.Count, 1);
384
385                         b.Close ();
386                         a.Reset ();
387
388                         Stdlib.raise (Signum.SIGINT);
389                         SleepUntilSignaled (a);
390                         Assert.AreEqual (a.Count, 1);
391
392                         a.Close ();
393                 }
394
395                 [Test]
396                 [Category ("AndroidNotWorking")] // Android 4.4.4 doesn't have signal(2)
397                 public void TestSignalActionInteraction ()
398                 {
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
403                         }
404                 }
405
406                 static readonly Signum[] signals = new Signum[] {
407                         Signum.SIGHUP, Signum.SIGINT, Signum.SIGTERM, Signum.SIGCONT,
408                 };
409
410                 const int StormCount = 100000;
411
412                 [Test]
413                 public void TestRaiseStorm ()
414                 {
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),
421                         };
422                         foreach (Thread t in threads)
423                                 t.Start ();
424                         foreach (Thread t in threads)
425                                 t.Join ();
426                         AssertCountSet (usignals);
427                         CloseSignals (usignals);
428                 }
429
430                 static void AssertCount (UnixSignal[] usignals)
431                 {
432                         int sum = 0;
433                         foreach (UnixSignal s in usignals)
434                                 sum += s.Count;
435                         Assert.AreEqual (sum, StormCount);
436                 }
437
438                 static void AssertCountSet (UnixSignal[] usignals)
439                 {
440                         foreach (UnixSignal s in usignals) {
441                                 Assert.IsTrue (s.Count > 0);
442                         }
443                 }
444
445                 static UnixSignal[] CreateSignals (Signum[] signals)
446                 {
447                         UnixSignal[] s = new UnixSignal [signals.Length];
448                         for (int i = 0; i < signals.Length; ++i)
449                                 s [i] = new UnixSignal (signals [i]);
450                         return s;
451                 }
452
453                 static void CloseSignals (UnixSignal[] signals)
454                 {
455                         foreach (UnixSignal s in signals)
456                                 s.Close ();
457                 }
458
459                 static Thread CreateRaiseStormThread (int max)
460                 {
461                         return new Thread (delegate () {
462                                 Random r = new Random (Environment.TickCount);
463                                 for (int i = 0; i < max; ++i) {
464                                         int n = r.Next (0, signals.Length);
465                                         Stdlib.raise (signals [n]);
466                                 }
467                         });
468                 }
469
470                 [Test]
471                 public void TestAddRemove ()
472                 {
473                         UnixSignal[] usignals = CreateSignals (signals);
474
475                         Thread[] threads = new Thread[]{
476                                 CreateRaiseStormThread (StormCount),
477                                 CreateSignalCreatorThread (),
478                         };
479
480                         foreach (Thread t in threads)
481                                 t.Start ();
482                         foreach (Thread t in threads)
483                                 t.Join ();
484
485                         AssertCountSet (usignals);
486                         CloseSignals (usignals);
487                 }
488
489                 static Thread CreateSignalCreatorThread ()
490                 {
491                         return new Thread (delegate () {
492                                 Random r = new Random (Environment.TickCount << 4);
493                                 for (int i = 0; i < StormCount; ++i) {
494                                         int n = r.Next (0, signals.Length);
495                                         using (new UnixSignal (signals [n]))
496                                         using (new UnixSignal (signals [(n+1)%signals.Length]))
497                                         using (new UnixSignal (signals [(n+2)%signals.Length]))
498                                         using (new UnixSignal (signals [(n+3)%signals.Length])) {
499                                         }
500                                 }
501                         });
502                 }
503
504                 [Test]
505                 public void TestWaitAny ()
506                 {
507                         UnixSignal[] usignals = CreateSignals (signals);
508
509                         Thread[] threads = new Thread[]{
510                                 CreateRaiseStormThread (StormCount),
511                                 CreateSignalCreatorThread (),
512                                 CreateWaitAnyThread (usignals [0], usignals [2]),
513                                 CreateWaitAnyThread (usignals [1], usignals [3]),
514                                 CreateWaitAnyThread (usignals [1], usignals [2]),
515                         };
516
517                         foreach (Thread t in threads)
518                                 t.Start ();
519                         foreach (Thread t in threads)
520                                 t.Join ();
521
522                         AssertCountSet (usignals);
523                         CloseSignals (usignals);
524                 }
525
526                 static Thread CreateWaitAnyThread (params UnixSignal[] usignals)
527                 {
528                         return new Thread (delegate () {
529                                 int idx = UnixSignal.WaitAny (usignals, 30000);
530                                 Assert.AreEqual (idx >= 0 && idx < usignals.Length, true);
531                         });
532                 }
533         }
534 }