[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / threads / test / TestEvent.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "threads/Event.h"
22 #include "threads/Atomics.h"
23
24 #include "threads/test/TestHelpers.h"
25
26 #include <boost/shared_array.hpp>
27 #include <stdio.h>
28
29 using namespace XbmcThreads;
30
31 //=============================================================================
32 // Helper classes
33 //=============================================================================
34
35 class waiter : public IRunnable
36 {
37   CEvent& event;
38 public:
39   bool& result;
40
41   volatile bool waiting;
42
43   waiter(CEvent& o, bool& flag) : event(o), result(flag), waiting(false) {}
44   
45   void Run()
46   {
47     waiting = true;
48     result = event.Wait();
49     waiting = false;
50   }
51 };
52
53 class timed_waiter : public IRunnable
54 {
55   CEvent& event;
56   unsigned int waitTime;
57 public:
58   int& result;
59
60   volatile bool waiting;
61
62   timed_waiter(CEvent& o, int& flag, int waitTimeMillis) : event(o), waitTime(waitTimeMillis), result(flag), waiting(false) {}
63   
64   void Run()
65   {
66     waiting = true;
67     result = 0;
68     result = event.WaitMSec(waitTime) ? 1 : -1;
69     waiting = false;
70   }
71 };
72
73 class group_wait : public IRunnable
74 {
75   CEventGroup& event;
76   int timeout;
77 public:
78   CEvent* result;
79   bool waiting;
80
81   group_wait(CEventGroup& o) : event(o), timeout(-1), result(NULL), waiting(false) {}
82   group_wait(CEventGroup& o, int timeout_) : event(o), timeout(timeout_), result(NULL), waiting(false) {}
83
84   void Run()
85   {
86     waiting = true;
87     if (timeout == -1)
88       result = event.wait();
89     else
90       result = event.wait((unsigned int)timeout);
91     waiting = false;
92   }
93 };
94
95 //=============================================================================
96
97 TEST(TestEvent, General)
98 {
99   CEvent event;
100   bool result = false;
101   waiter w1(event,result);
102   thread waitThread(w1);
103
104   EXPECT_TRUE(waitForWaiters(event,1,10000));
105
106   EXPECT_TRUE(!result);
107
108   event.Set();
109
110   EXPECT_TRUE(waitThread.timed_join(10000));
111
112   EXPECT_TRUE(result);
113 }
114
115 TEST(TestEvent, TwoWaits)
116 {
117   CEvent event;
118   bool result1 = false;
119   bool result2 = false;
120   waiter w1(event,result1);
121   waiter w2(event,result2);
122   thread waitThread1(w1);
123   thread waitThread2(w2);
124
125   EXPECT_TRUE(waitForWaiters(event,2,10000));
126
127   EXPECT_TRUE(!result1);
128   EXPECT_TRUE(!result2);
129
130   event.Set();
131
132   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
133   EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
134
135   EXPECT_TRUE(result1);
136   EXPECT_TRUE(result2);
137
138 }
139
140 TEST(TestEvent, TimedWaits)
141 {
142   CEvent event;
143   int result1 = 10;
144   timed_waiter w1(event,result1,100);
145   thread waitThread1(w1);
146
147   EXPECT_TRUE(waitForWaiters(event,1,10000));
148
149   EXPECT_TRUE(result1 == 0);
150
151   event.Set();
152
153   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
154
155   EXPECT_TRUE(result1 == 1);
156 }
157
158 TEST(TestEvent, TimedWaitsTimeout)
159 {
160   CEvent event;
161   int result1 = 10;
162   timed_waiter w1(event,result1,50);
163   thread waitThread1(w1);
164
165   EXPECT_TRUE(waitForWaiters(event,1,100));
166
167   EXPECT_TRUE(result1 == 0);
168
169   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
170
171   EXPECT_TRUE(result1 == -1);
172 }
173
174 TEST(TestEvent, Group)
175 {
176   CEvent event1;
177   CEvent event2;
178
179   CEventGroup group(&event1,&event2,NULL);
180
181   bool result1 = false;
182   bool result2 = false;
183
184   waiter w1(event1,result1);
185   waiter w2(event2,result2);
186   group_wait w3(group);
187
188   thread waitThread1(w1);
189   thread waitThread2(w2);
190   thread waitThread3(w3);
191
192   EXPECT_TRUE(waitForWaiters(event1,1,10000));
193   EXPECT_TRUE(waitForWaiters(event2,1,10000));
194   EXPECT_TRUE(waitForWaiters(group,1,10000));
195
196   EXPECT_TRUE(!result1);
197   EXPECT_TRUE(!result2);
198
199   EXPECT_TRUE(w3.waiting);
200   EXPECT_TRUE(w3.result == NULL);
201
202   event1.Set();
203
204   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
205   EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
206   SleepMillis(10);
207
208   EXPECT_TRUE(result1);
209   EXPECT_TRUE(!w1.waiting);
210   EXPECT_TRUE(!result2);
211   EXPECT_TRUE(w2.waiting);
212   EXPECT_TRUE(!w3.waiting);
213   EXPECT_TRUE(w3.result == &event1);
214
215   event2.Set();
216
217   EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
218
219 }
220
221 TEST(TestEvent, GroupLimitedGroupScope)
222 {
223   CEvent event1;
224   CEvent event2;
225
226   {
227     CEventGroup group(&event1,&event2,NULL);
228
229     bool result1 = false;
230     bool result2 = false;
231
232     waiter w1(event1,result1);
233     waiter w2(event2,result2);
234     group_wait w3(group);
235
236     thread waitThread1(w1);
237     thread waitThread2(w2);
238     thread waitThread3(w3);
239
240     EXPECT_TRUE(waitForWaiters(event1,1,10000));
241     EXPECT_TRUE(waitForWaiters(event2,1,10000));
242     EXPECT_TRUE(waitForWaiters(group,1,10000));
243
244     EXPECT_TRUE(!result1);
245     EXPECT_TRUE(!result2);
246
247     EXPECT_TRUE(w3.waiting);
248     EXPECT_TRUE(w3.result == NULL);
249
250     event1.Set();
251
252     EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
253     EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
254     SleepMillis(10);
255
256     EXPECT_TRUE(result1);
257     EXPECT_TRUE(!w1.waiting);
258     EXPECT_TRUE(!result2);
259     EXPECT_TRUE(w2.waiting);
260     EXPECT_TRUE(!w3.waiting);
261     EXPECT_TRUE(w3.result == &event1);
262   }
263
264   event2.Set();
265
266   SleepMillis(50); // give thread 2 a chance to exit
267 }
268
269 TEST(TestEvent, TwoGroups)
270 {
271   CEvent event1;
272   CEvent event2;
273
274   CEventGroup group1(2, &event1,&event2);
275   CEventGroup group2(&event1,&event2,NULL);
276
277   bool result1 = false;
278   bool result2 = false;
279
280   waiter w1(event1,result1);
281   waiter w2(event2,result2);
282   group_wait w3(group1);
283   group_wait w4(group2);
284
285   thread waitThread1(w1);
286   thread waitThread2(w2);
287   thread waitThread3(w3);
288   thread waitThread4(w4);
289
290   EXPECT_TRUE(waitForWaiters(event1,1,10000));
291   EXPECT_TRUE(waitForWaiters(event2,1,10000));
292   EXPECT_TRUE(waitForWaiters(group1,1,10000));
293   EXPECT_TRUE(waitForWaiters(group2,1,10000));
294
295   EXPECT_TRUE(!result1);
296   EXPECT_TRUE(!result2);
297
298   EXPECT_TRUE(w3.waiting);
299   EXPECT_EQ(w3.result,(void*)NULL);
300   EXPECT_TRUE(w4.waiting);
301   EXPECT_EQ(w4.result,(void*)NULL);
302
303   event1.Set();
304
305   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
306   EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
307   EXPECT_TRUE(waitThread4.timed_join(MILLIS(10000)));
308   SleepMillis(10);
309
310   EXPECT_TRUE(result1);
311   EXPECT_TRUE(!w1.waiting);
312   EXPECT_TRUE(!result2);
313   EXPECT_TRUE(w2.waiting);
314   EXPECT_TRUE(!w3.waiting);
315   EXPECT_TRUE(w3.result == &event1);
316   EXPECT_TRUE(!w4.waiting);
317   EXPECT_TRUE(w4.result == &event1);
318
319   event2.Set();
320
321   EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
322 }
323
324 TEST(TestEvent, AutoResetBehavior)
325 {
326   CEvent event;
327
328   EXPECT_TRUE(!event.WaitMSec(1));
329
330   event.Set(); // event will remain signaled if there are no waits
331
332   EXPECT_TRUE(event.WaitMSec(1));
333 }
334
335 TEST(TestEvent, ManualReset)
336 {
337   CEvent event(true);
338   bool result = false;
339   waiter w1(event,result);
340   thread waitThread(w1);
341
342   EXPECT_TRUE(waitForWaiters(event,1,10000));
343
344   EXPECT_TRUE(!result);
345
346   event.Set();
347
348   EXPECT_TRUE(waitThread.timed_join(MILLIS(10000)));
349
350   EXPECT_TRUE(result);
351
352   // with manual reset, the state should remain signaled
353   EXPECT_TRUE(event.WaitMSec(1));
354
355   event.Reset();
356
357   EXPECT_TRUE(!event.WaitMSec(1));
358 }
359
360 TEST(TestEvent, InitVal)
361 {
362   CEvent event(false,true);
363   EXPECT_TRUE(event.WaitMSec(50));
364 }
365
366 TEST(TestEvent, SimpleTimeout)
367 {
368   CEvent event;
369   EXPECT_TRUE(!event.WaitMSec(50));
370 }
371
372 TEST(TestEvent, GroupChildSet)
373 {
374   CEvent event1(true);
375   CEvent event2;
376
377   event1.Set();
378   CEventGroup group(&event1,&event2,NULL);
379
380   bool result1 = false;
381   bool result2 = false;
382
383   waiter w1(event1,result1);
384   waiter w2(event2,result2);
385   group_wait w3(group);
386
387   thread waitThread1(w1);
388   thread waitThread2(w2);
389   thread waitThread3(w3);
390
391   EXPECT_TRUE(waitForWaiters(event2,1,10000));
392   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
393   EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
394   SleepMillis(10);
395
396   EXPECT_TRUE(result1);
397   EXPECT_TRUE(!result2);
398
399   EXPECT_TRUE(!w3.waiting);
400   EXPECT_TRUE(w3.result == &event1);
401
402   event2.Set();
403
404   EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
405 }
406
407 TEST(TestEvent, GroupChildSet2)
408 {
409   CEvent event1(true,true);
410   CEvent event2;
411
412   CEventGroup group(&event1,&event2,NULL);
413
414   bool result1 = false;
415   bool result2 = false;
416
417   waiter w1(event1,result1);
418   waiter w2(event2,result2);
419   group_wait w3(group);
420
421   thread waitThread1(w1);
422   thread waitThread2(w2);
423   thread waitThread3(w3);
424
425   EXPECT_TRUE(waitForWaiters(event2,1,10000));
426   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
427   EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
428   SleepMillis(10);
429
430   EXPECT_TRUE(result1);
431   EXPECT_TRUE(!result2);
432
433   EXPECT_TRUE(!w3.waiting);
434   EXPECT_TRUE(w3.result == &event1);
435
436   event2.Set();
437
438   EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
439 }
440
441 TEST(TestEvent, GroupWaitResetsChild)
442 {
443   CEvent event1;
444   CEvent event2;
445
446   CEventGroup group(&event1,&event2,NULL);
447
448   group_wait w3(group);
449
450   thread waitThread3(w3);
451
452   EXPECT_TRUE(waitForWaiters(group,1,10000));
453
454   EXPECT_TRUE(w3.waiting);
455   EXPECT_TRUE(w3.result == NULL);
456
457   event2.Set();
458
459   EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
460
461   EXPECT_TRUE(!w3.waiting);
462   EXPECT_TRUE(w3.result == &event2);
463   // event2 should have been reset.
464   EXPECT_TRUE(event2.WaitMSec(1) == false);
465 }
466
467 TEST(TestEvent, GroupTimedWait)
468 {
469   CEvent event1;
470   CEvent event2;
471   CEventGroup group(&event1,&event2,NULL);
472
473   bool result1 = false;
474   bool result2 = false;
475
476   waiter w1(event1,result1);
477   waiter w2(event2,result2);
478
479   thread waitThread1(w1);
480   thread waitThread2(w2);
481
482   EXPECT_TRUE(waitForWaiters(event1,1,10000));
483   EXPECT_TRUE(waitForWaiters(event2,1,10000));
484
485   EXPECT_TRUE(group.wait(20) == NULL); // waited ... got nothing
486
487   group_wait w3(group,50);
488   thread waitThread3(w3);
489
490   EXPECT_TRUE(waitForWaiters(group,1,10000));
491
492   EXPECT_TRUE(!result1);
493   EXPECT_TRUE(!result2);
494
495   EXPECT_TRUE(w3.waiting);
496   EXPECT_TRUE(w3.result == NULL);
497
498   // this should end given the wait is for only 50 millis
499   EXPECT_TRUE(waitThread3.timed_join(MILLIS(100)));
500
501   EXPECT_TRUE(!w3.waiting);
502   EXPECT_TRUE(w3.result == NULL);
503
504   group_wait w4(group,50);
505   thread waitThread4(w4);
506
507   EXPECT_TRUE(waitForWaiters(group,1,10000));
508
509   EXPECT_TRUE(w4.waiting);
510   EXPECT_TRUE(w4.result == NULL);
511
512   event1.Set();
513
514   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
515   EXPECT_TRUE(waitThread4.timed_join(MILLIS(10000)));
516   SleepMillis(10);
517
518   EXPECT_TRUE(result1);
519   EXPECT_TRUE(!result2);
520
521   EXPECT_TRUE(!w4.waiting);
522   EXPECT_TRUE(w4.result == &event1);
523
524   event2.Set();
525
526   EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
527 }
528
529 #define TESTNUM 100000l
530 #define NUMTHREADS 100l
531
532 CEvent* g_event = NULL;
533 volatile long g_mutex;
534
535 class mass_waiter : public IRunnable
536 {
537 public:
538   CEvent& event;
539   bool result;
540
541   volatile bool waiting;
542
543   mass_waiter() : event(*g_event), waiting(false) {}
544   
545   void Run()
546   {
547     waiting = true;
548     AtomicGuard g(&g_mutex);
549     result = event.Wait();
550     waiting = false;
551   }
552 };
553
554 class poll_mass_waiter : public IRunnable
555 {
556 public:
557   CEvent& event;
558   bool result;
559
560   volatile bool waiting;
561
562   poll_mass_waiter() : event(*g_event), waiting(false) {}
563   
564   void Run()
565   {
566     waiting = true;
567     AtomicGuard g(&g_mutex);
568     while ((result = event.WaitMSec(0)) == false);
569     waiting = false;
570   }
571 };
572
573 template <class W> void RunMassEventTest(boost::shared_array<W>& m, bool canWaitOnEvent)
574 {
575   boost::shared_array<thread> t;
576   t.reset(new thread[NUMTHREADS]);
577   for(size_t i=0; i<NUMTHREADS; i++)
578     t[i] = thread(m[i]);
579
580   EXPECT_TRUE(waitForThread(g_mutex,NUMTHREADS,10000));
581   if (canWaitOnEvent)
582   {
583     EXPECT_TRUE(waitForWaiters(*g_event,NUMTHREADS,10000));
584   }
585
586   SleepMillis(100);// give them a little more time
587
588   for(size_t i=0; i<NUMTHREADS; i++)
589   {
590     EXPECT_TRUE(m[i].waiting);
591   }
592
593   g_event->Set();
594
595   for(size_t i=0; i<NUMTHREADS; i++)
596   {
597     EXPECT_TRUE(t[i].timed_join(MILLIS(10000)));
598   }
599
600   for(size_t i=0; i<NUMTHREADS; i++)
601   {
602     EXPECT_TRUE(!m[i].waiting);
603     EXPECT_TRUE(m[i].result);
604   }
605 }
606
607
608 TEST(TestMassEvent, General)
609 {
610   g_event = new CEvent();
611
612   boost::shared_array<mass_waiter> m;
613   m.reset(new mass_waiter[NUMTHREADS]);
614
615   RunMassEventTest(m,true);
616   delete g_event;
617 }
618
619 TEST(TestMassEvent, Polling)
620 {
621   g_event = new CEvent(true); // polling needs to avoid the auto-reset
622
623   boost::shared_array<poll_mass_waiter> m;
624   m.reset(new poll_mass_waiter[NUMTHREADS]);
625
626   RunMassEventTest(m,false);
627   delete g_event;
628 }
629