1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "threads/Event.h"
10 #include "threads/IRunnable.h"
11 #include "threads/SharedSection.h"
12 #include "threads/SingleLock.h"
13 #include "threads/test/TestHelpers.h"
14 
15 #include <stdio.h>
16 
17 //=============================================================================
18 // Helper classes
19 //=============================================================================
20 
21 template<class L>
22 class locker : public IRunnable
23 {
24   CSharedSection& sec;
25   CEvent* wait;
26 
27   std::atomic<long>* mutex;
28 public:
29   volatile bool haslock;
30   volatile bool obtainedlock;
31 
locker(CSharedSection & o,std::atomic<long> * mutex_=NULL,CEvent * wait_=NULL)32   inline locker(CSharedSection& o, std::atomic<long>* mutex_ = NULL, CEvent* wait_ = NULL) :
33     sec(o), wait(wait_), mutex(mutex_), haslock(false), obtainedlock(false) {}
34 
locker(CSharedSection & o,CEvent * wait_=NULL)35   inline locker(CSharedSection& o, CEvent* wait_ = NULL) :
36     sec(o), wait(wait_), mutex(NULL), haslock(false), obtainedlock(false) {}
37 
Run()38   void Run() override
39   {
40     AtomicGuard g(mutex);
41     L lock(sec);
42     haslock = true;
43     obtainedlock = true;
44     if (wait)
45       wait->Wait();
46     haslock = false;
47   }
48 };
49 
TEST(TestCritSection,General)50 TEST(TestCritSection, General)
51 {
52   CCriticalSection sec;
53 
54   CSingleLock l1(sec);
55   CSingleLock l2(sec);
56 }
57 
TEST(TestSharedSection,General)58 TEST(TestSharedSection, General)
59 {
60   CSharedSection sec;
61 
62   CSharedLock l1(sec);
63   CSharedLock l2(sec);
64 }
65 
TEST(TestSharedSection,GetSharedLockWhileTryingExclusiveLock)66 TEST(TestSharedSection, GetSharedLockWhileTryingExclusiveLock)
67 {
68   std::atomic<long> mutex(0L);
69   CEvent event;
70 
71   CSharedSection sec;
72 
73   CSharedLock l1(sec); // get a shared lock
74 
75   locker<CExclusiveLock> l2(sec,&mutex);
76   thread waitThread1(l2); // try to get an exclusive lock
77 
78   EXPECT_TRUE(waitForThread(mutex,1,10000));
79   SleepMillis(10);  // still need to give it a chance to move ahead
80 
81   EXPECT_TRUE(!l2.haslock);  // this thread is waiting ...
82   EXPECT_TRUE(!l2.obtainedlock);  // this thread is waiting ...
83 
84   // now try and get a SharedLock
85   locker<CSharedLock> l3(sec,&mutex,&event);
86   thread waitThread3(l3); // try to get a shared lock
87   EXPECT_TRUE(waitForThread(mutex,2,10000));
88   SleepMillis(10);
89   EXPECT_TRUE(l3.haslock);
90 
91   event.Set();
92   EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
93 
94   // l3 should have released.
95   EXPECT_TRUE(!l3.haslock);
96 
97   // but the exclusive lock should still not have happened
98   EXPECT_TRUE(!l2.haslock);  // this thread is waiting ...
99   EXPECT_TRUE(!l2.obtainedlock);  // this thread is waiting ...
100 
101   // let it go
102   l1.Leave(); // the last shared lock leaves.
103 
104   EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
105 
106   EXPECT_TRUE(l2.obtainedlock);  // the exclusive lock was captured
107   EXPECT_TRUE(!l2.haslock);  // ... but it doesn't have it anymore
108 }
109 
TEST(TestSharedSection,TwoCase)110 TEST(TestSharedSection, TwoCase)
111 {
112   CSharedSection sec;
113 
114   CEvent event;
115   std::atomic<long> mutex(0L);
116 
117   locker<CSharedLock> l1(sec,&mutex,&event);
118 
119   {
120     CSharedLock lock(sec);
121     thread waitThread1(l1);
122 
123     EXPECT_TRUE(waitForWaiters(event,1,10000));
124     EXPECT_TRUE(l1.haslock);
125 
126     event.Set();
127 
128     EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
129   }
130 
131   locker<CSharedLock> l2(sec,&mutex,&event);
132   {
133     CExclusiveLock lock(sec); // get exclusive lock
134     thread waitThread2(l2); // thread should block
135 
136     EXPECT_TRUE(waitForThread(mutex,1,10000));
137     SleepMillis(10);
138 
139     EXPECT_TRUE(!l2.haslock);
140 
141     lock.Leave();
142 
143     EXPECT_TRUE(waitForWaiters(event,1,10000));
144     SleepMillis(10);
145     EXPECT_TRUE(l2.haslock);
146 
147     event.Set();
148 
149     EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
150   }
151 }
152 
TEST(TestMultipleSharedSection,General)153 TEST(TestMultipleSharedSection, General)
154 {
155   CSharedSection sec;
156 
157   CEvent event;
158   std::atomic<long> mutex(0L);
159 
160   locker<CSharedLock> l1(sec,&mutex, &event);
161 
162   {
163     CSharedLock lock(sec);
164     thread waitThread1(l1);
165 
166     EXPECT_TRUE(waitForThread(mutex,1,10000));
167     SleepMillis(10);
168 
169     EXPECT_TRUE(l1.haslock);
170 
171     event.Set();
172 
173     EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
174   }
175 
176   locker<CSharedLock> l2(sec,&mutex,&event);
177   locker<CSharedLock> l3(sec,&mutex,&event);
178   locker<CSharedLock> l4(sec,&mutex,&event);
179   locker<CSharedLock> l5(sec,&mutex,&event);
180   {
181     CExclusiveLock lock(sec);
182     thread waitThread1(l2);
183     thread waitThread2(l3);
184     thread waitThread3(l4);
185     thread waitThread4(l5);
186 
187     EXPECT_TRUE(waitForThread(mutex,4,10000));
188     SleepMillis(10);
189 
190     EXPECT_TRUE(!l2.haslock);
191     EXPECT_TRUE(!l3.haslock);
192     EXPECT_TRUE(!l4.haslock);
193     EXPECT_TRUE(!l5.haslock);
194 
195     lock.Leave();
196 
197     EXPECT_TRUE(waitForWaiters(event,4,10000));
198 
199     EXPECT_TRUE(l2.haslock);
200     EXPECT_TRUE(l3.haslock);
201     EXPECT_TRUE(l4.haslock);
202     EXPECT_TRUE(l5.haslock);
203 
204     event.Set();
205 
206     EXPECT_TRUE(waitThread1.timed_join(MILLIS(10000)));
207     EXPECT_TRUE(waitThread2.timed_join(MILLIS(10000)));
208     EXPECT_TRUE(waitThread3.timed_join(MILLIS(10000)));
209     EXPECT_TRUE(waitThread4.timed_join(MILLIS(10000)));
210   }
211 }
212 
213