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