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