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