1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/synchronization/mutex.h"
16
17 #ifdef _WIN32
18 #include <windows.h>
19 #endif
20
21 #include <algorithm>
22 #include <atomic>
23 #include <cstdlib>
24 #include <functional>
25 #include <memory>
26 #include <random>
27 #include <string>
28 #include <thread> // NOLINT(build/c++11)
29 #include <vector>
30
31 #include "gtest/gtest.h"
32 #include "absl/base/attributes.h"
33 #include "absl/base/config.h"
34 #include "absl/base/internal/raw_logging.h"
35 #include "absl/base/internal/sysinfo.h"
36 #include "absl/memory/memory.h"
37 #include "absl/synchronization/internal/thread_pool.h"
38 #include "absl/time/clock.h"
39 #include "absl/time/time.h"
40
41 namespace {
42
43 // TODO(dmauro): Replace with a commandline flag.
44 static constexpr bool kExtendedTest = false;
45
CreatePool(int threads)46 std::unique_ptr<absl::synchronization_internal::ThreadPool> CreatePool(
47 int threads) {
48 return absl::make_unique<absl::synchronization_internal::ThreadPool>(threads);
49 }
50
51 std::unique_ptr<absl::synchronization_internal::ThreadPool>
CreateDefaultPool()52 CreateDefaultPool() {
53 return CreatePool(kExtendedTest ? 32 : 10);
54 }
55
56 // Hack to schedule a function to run on a thread pool thread after a
57 // duration has elapsed.
ScheduleAfter(absl::synchronization_internal::ThreadPool * tp,absl::Duration after,const std::function<void ()> & func)58 static void ScheduleAfter(absl::synchronization_internal::ThreadPool *tp,
59 absl::Duration after,
60 const std::function<void()> &func) {
61 tp->Schedule([func, after] {
62 absl::SleepFor(after);
63 func();
64 });
65 }
66
67 struct TestContext {
68 int iterations;
69 int threads;
70 int g0; // global 0
71 int g1; // global 1
72 absl::Mutex mu;
73 absl::CondVar cv;
74 };
75
76 // To test whether the invariant check call occurs
77 static std::atomic<bool> invariant_checked;
78
GetInvariantChecked()79 static bool GetInvariantChecked() {
80 return invariant_checked.load(std::memory_order_relaxed);
81 }
82
SetInvariantChecked(bool new_value)83 static void SetInvariantChecked(bool new_value) {
84 invariant_checked.store(new_value, std::memory_order_relaxed);
85 }
86
CheckSumG0G1(void * v)87 static void CheckSumG0G1(void *v) {
88 TestContext *cxt = static_cast<TestContext *>(v);
89 ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in CheckSumG0G1");
90 SetInvariantChecked(true);
91 }
92
TestMu(TestContext * cxt,int c)93 static void TestMu(TestContext *cxt, int c) {
94 for (int i = 0; i != cxt->iterations; i++) {
95 absl::MutexLock l(&cxt->mu);
96 int a = cxt->g0 + 1;
97 cxt->g0 = a;
98 cxt->g1--;
99 }
100 }
101
TestTry(TestContext * cxt,int c)102 static void TestTry(TestContext *cxt, int c) {
103 for (int i = 0; i != cxt->iterations; i++) {
104 do {
105 std::this_thread::yield();
106 } while (!cxt->mu.TryLock());
107 int a = cxt->g0 + 1;
108 cxt->g0 = a;
109 cxt->g1--;
110 cxt->mu.Unlock();
111 }
112 }
113
TestR20ms(TestContext * cxt,int c)114 static void TestR20ms(TestContext *cxt, int c) {
115 for (int i = 0; i != cxt->iterations; i++) {
116 absl::ReaderMutexLock l(&cxt->mu);
117 absl::SleepFor(absl::Milliseconds(20));
118 cxt->mu.AssertReaderHeld();
119 }
120 }
121
TestRW(TestContext * cxt,int c)122 static void TestRW(TestContext *cxt, int c) {
123 if ((c & 1) == 0) {
124 for (int i = 0; i != cxt->iterations; i++) {
125 absl::WriterMutexLock l(&cxt->mu);
126 cxt->g0++;
127 cxt->g1--;
128 cxt->mu.AssertHeld();
129 cxt->mu.AssertReaderHeld();
130 }
131 } else {
132 for (int i = 0; i != cxt->iterations; i++) {
133 absl::ReaderMutexLock l(&cxt->mu);
134 ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in TestRW");
135 cxt->mu.AssertReaderHeld();
136 }
137 }
138 }
139
140 struct MyContext {
141 int target;
142 TestContext *cxt;
143 bool MyTurn();
144 };
145
MyTurn()146 bool MyContext::MyTurn() {
147 TestContext *cxt = this->cxt;
148 return cxt->g0 == this->target || cxt->g0 == cxt->iterations;
149 }
150
TestAwait(TestContext * cxt,int c)151 static void TestAwait(TestContext *cxt, int c) {
152 MyContext mc;
153 mc.target = c;
154 mc.cxt = cxt;
155 absl::MutexLock l(&cxt->mu);
156 cxt->mu.AssertHeld();
157 while (cxt->g0 < cxt->iterations) {
158 cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn));
159 ABSL_RAW_CHECK(mc.MyTurn(), "Error in TestAwait");
160 cxt->mu.AssertHeld();
161 if (cxt->g0 < cxt->iterations) {
162 int a = cxt->g0 + 1;
163 cxt->g0 = a;
164 mc.target += cxt->threads;
165 }
166 }
167 }
168
TestSignalAll(TestContext * cxt,int c)169 static void TestSignalAll(TestContext *cxt, int c) {
170 int target = c;
171 absl::MutexLock l(&cxt->mu);
172 cxt->mu.AssertHeld();
173 while (cxt->g0 < cxt->iterations) {
174 while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
175 cxt->cv.Wait(&cxt->mu);
176 }
177 if (cxt->g0 < cxt->iterations) {
178 int a = cxt->g0 + 1;
179 cxt->g0 = a;
180 cxt->cv.SignalAll();
181 target += cxt->threads;
182 }
183 }
184 }
185
TestSignal(TestContext * cxt,int c)186 static void TestSignal(TestContext *cxt, int c) {
187 ABSL_RAW_CHECK(cxt->threads == 2, "TestSignal should use 2 threads");
188 int target = c;
189 absl::MutexLock l(&cxt->mu);
190 cxt->mu.AssertHeld();
191 while (cxt->g0 < cxt->iterations) {
192 while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
193 cxt->cv.Wait(&cxt->mu);
194 }
195 if (cxt->g0 < cxt->iterations) {
196 int a = cxt->g0 + 1;
197 cxt->g0 = a;
198 cxt->cv.Signal();
199 target += cxt->threads;
200 }
201 }
202 }
203
TestCVTimeout(TestContext * cxt,int c)204 static void TestCVTimeout(TestContext *cxt, int c) {
205 int target = c;
206 absl::MutexLock l(&cxt->mu);
207 cxt->mu.AssertHeld();
208 while (cxt->g0 < cxt->iterations) {
209 while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
210 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
211 }
212 if (cxt->g0 < cxt->iterations) {
213 int a = cxt->g0 + 1;
214 cxt->g0 = a;
215 cxt->cv.SignalAll();
216 target += cxt->threads;
217 }
218 }
219 }
220
G0GE2(TestContext * cxt)221 static bool G0GE2(TestContext *cxt) { return cxt->g0 >= 2; }
222
TestTime(TestContext * cxt,int c,bool use_cv)223 static void TestTime(TestContext *cxt, int c, bool use_cv) {
224 ABSL_RAW_CHECK(cxt->iterations == 1, "TestTime should only use 1 iteration");
225 ABSL_RAW_CHECK(cxt->threads > 2, "TestTime should use more than 2 threads");
226 const bool kFalse = false;
227 absl::Condition false_cond(&kFalse);
228 absl::Condition g0ge2(G0GE2, cxt);
229 if (c == 0) {
230 absl::MutexLock l(&cxt->mu);
231
232 absl::Time start = absl::Now();
233 if (use_cv) {
234 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
235 } else {
236 ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
237 "TestTime failed");
238 }
239 absl::Duration elapsed = absl::Now() - start;
240 ABSL_RAW_CHECK(
241 absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
242 "TestTime failed");
243 ABSL_RAW_CHECK(cxt->g0 == 1, "TestTime failed");
244
245 start = absl::Now();
246 if (use_cv) {
247 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
248 } else {
249 ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
250 "TestTime failed");
251 }
252 elapsed = absl::Now() - start;
253 ABSL_RAW_CHECK(
254 absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
255 "TestTime failed");
256 cxt->g0++;
257 if (use_cv) {
258 cxt->cv.Signal();
259 }
260
261 start = absl::Now();
262 if (use_cv) {
263 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(4));
264 } else {
265 ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4)),
266 "TestTime failed");
267 }
268 elapsed = absl::Now() - start;
269 ABSL_RAW_CHECK(
270 absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0),
271 "TestTime failed");
272 ABSL_RAW_CHECK(cxt->g0 >= 3, "TestTime failed");
273
274 start = absl::Now();
275 if (use_cv) {
276 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
277 } else {
278 ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
279 "TestTime failed");
280 }
281 elapsed = absl::Now() - start;
282 ABSL_RAW_CHECK(
283 absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
284 "TestTime failed");
285 if (use_cv) {
286 cxt->cv.SignalAll();
287 }
288
289 start = absl::Now();
290 if (use_cv) {
291 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
292 } else {
293 ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
294 "TestTime failed");
295 }
296 elapsed = absl::Now() - start;
297 ABSL_RAW_CHECK(absl::Seconds(0.9) <= elapsed &&
298 elapsed <= absl::Seconds(2.0), "TestTime failed");
299 ABSL_RAW_CHECK(cxt->g0 == cxt->threads, "TestTime failed");
300
301 } else if (c == 1) {
302 absl::MutexLock l(&cxt->mu);
303 const absl::Time start = absl::Now();
304 if (use_cv) {
305 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500));
306 } else {
307 ABSL_RAW_CHECK(
308 !cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500)),
309 "TestTime failed");
310 }
311 const absl::Duration elapsed = absl::Now() - start;
312 ABSL_RAW_CHECK(
313 absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9),
314 "TestTime failed");
315 cxt->g0++;
316 } else if (c == 2) {
317 absl::MutexLock l(&cxt->mu);
318 if (use_cv) {
319 while (cxt->g0 < 2) {
320 cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
321 }
322 } else {
323 ABSL_RAW_CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100)),
324 "TestTime failed");
325 }
326 cxt->g0++;
327 } else {
328 absl::MutexLock l(&cxt->mu);
329 if (use_cv) {
330 while (cxt->g0 < 2) {
331 cxt->cv.Wait(&cxt->mu);
332 }
333 } else {
334 cxt->mu.Await(g0ge2);
335 }
336 cxt->g0++;
337 }
338 }
339
TestMuTime(TestContext * cxt,int c)340 static void TestMuTime(TestContext *cxt, int c) { TestTime(cxt, c, false); }
341
TestCVTime(TestContext * cxt,int c)342 static void TestCVTime(TestContext *cxt, int c) { TestTime(cxt, c, true); }
343
EndTest(int * c0,int * c1,absl::Mutex * mu,absl::CondVar * cv,const std::function<void (int)> & cb)344 static void EndTest(int *c0, int *c1, absl::Mutex *mu, absl::CondVar *cv,
345 const std::function<void(int)>& cb) {
346 mu->Lock();
347 int c = (*c0)++;
348 mu->Unlock();
349 cb(c);
350 absl::MutexLock l(mu);
351 (*c1)++;
352 cv->Signal();
353 }
354
355 // Code common to RunTest() and RunTestWithInvariantDebugging().
RunTestCommon(TestContext * cxt,void (* test)(TestContext * cxt,int),int threads,int iterations,int operations)356 static int RunTestCommon(TestContext *cxt, void (*test)(TestContext *cxt, int),
357 int threads, int iterations, int operations) {
358 absl::Mutex mu2;
359 absl::CondVar cv2;
360 int c0 = 0;
361 int c1 = 0;
362 cxt->g0 = 0;
363 cxt->g1 = 0;
364 cxt->iterations = iterations;
365 cxt->threads = threads;
366 absl::synchronization_internal::ThreadPool tp(threads);
367 for (int i = 0; i != threads; i++) {
368 tp.Schedule(std::bind(&EndTest, &c0, &c1, &mu2, &cv2,
369 std::function<void(int)>(
370 std::bind(test, cxt, std::placeholders::_1))));
371 }
372 mu2.Lock();
373 while (c1 != threads) {
374 cv2.Wait(&mu2);
375 }
376 mu2.Unlock();
377 return cxt->g0;
378 }
379
380 // Basis for the parameterized tests configured below.
RunTest(void (* test)(TestContext * cxt,int),int threads,int iterations,int operations)381 static int RunTest(void (*test)(TestContext *cxt, int), int threads,
382 int iterations, int operations) {
383 TestContext cxt;
384 return RunTestCommon(&cxt, test, threads, iterations, operations);
385 }
386
387 // Like RunTest(), but sets an invariant on the tested Mutex and
388 // verifies that the invariant check happened. The invariant function
389 // will be passed the TestContext* as its arg and must call
390 // SetInvariantChecked(true);
391 #if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
RunTestWithInvariantDebugging(void (* test)(TestContext * cxt,int),int threads,int iterations,int operations,void (* invariant)(void *))392 static int RunTestWithInvariantDebugging(void (*test)(TestContext *cxt, int),
393 int threads, int iterations,
394 int operations,
395 void (*invariant)(void *)) {
396 absl::EnableMutexInvariantDebugging(true);
397 SetInvariantChecked(false);
398 TestContext cxt;
399 cxt.mu.EnableInvariantDebugging(invariant, &cxt);
400 int ret = RunTestCommon(&cxt, test, threads, iterations, operations);
401 ABSL_RAW_CHECK(GetInvariantChecked(), "Invariant not checked");
402 absl::EnableMutexInvariantDebugging(false); // Restore.
403 return ret;
404 }
405 #endif
406
407 // --------------------------------------------------------
408 // Test for fix of bug in TryRemove()
409 struct TimeoutBugStruct {
410 absl::Mutex mu;
411 bool a;
412 int a_waiter_count;
413 };
414
WaitForA(TimeoutBugStruct * x)415 static void WaitForA(TimeoutBugStruct *x) {
416 x->mu.LockWhen(absl::Condition(&x->a));
417 x->a_waiter_count--;
418 x->mu.Unlock();
419 }
420
NoAWaiters(TimeoutBugStruct * x)421 static bool NoAWaiters(TimeoutBugStruct *x) { return x->a_waiter_count == 0; }
422
423 // Test that a CondVar.Wait(&mutex) can un-block a call to mutex.Await() in
424 // another thread.
TEST(Mutex,CondVarWaitSignalsAwait)425 TEST(Mutex, CondVarWaitSignalsAwait) {
426 // Use a struct so the lock annotations apply.
427 struct {
428 absl::Mutex barrier_mu;
429 bool barrier ABSL_GUARDED_BY(barrier_mu) = false;
430
431 absl::Mutex release_mu;
432 bool release ABSL_GUARDED_BY(release_mu) = false;
433 absl::CondVar released_cv;
434 } state;
435
436 auto pool = CreateDefaultPool();
437
438 // Thread A. Sets barrier, waits for release using Mutex::Await, then
439 // signals released_cv.
440 pool->Schedule([&state] {
441 state.release_mu.Lock();
442
443 state.barrier_mu.Lock();
444 state.barrier = true;
445 state.barrier_mu.Unlock();
446
447 state.release_mu.Await(absl::Condition(&state.release));
448 state.released_cv.Signal();
449 state.release_mu.Unlock();
450 });
451
452 state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
453 state.barrier_mu.Unlock();
454 state.release_mu.Lock();
455 // Thread A is now blocked on release by way of Mutex::Await().
456
457 // Set release. Calling released_cv.Wait() should un-block thread A,
458 // which will signal released_cv. If not, the test will hang.
459 state.release = true;
460 state.released_cv.Wait(&state.release_mu);
461 state.release_mu.Unlock();
462 }
463
464 // Test that a CondVar.WaitWithTimeout(&mutex) can un-block a call to
465 // mutex.Await() in another thread.
TEST(Mutex,CondVarWaitWithTimeoutSignalsAwait)466 TEST(Mutex, CondVarWaitWithTimeoutSignalsAwait) {
467 // Use a struct so the lock annotations apply.
468 struct {
469 absl::Mutex barrier_mu;
470 bool barrier ABSL_GUARDED_BY(barrier_mu) = false;
471
472 absl::Mutex release_mu;
473 bool release ABSL_GUARDED_BY(release_mu) = false;
474 absl::CondVar released_cv;
475 } state;
476
477 auto pool = CreateDefaultPool();
478
479 // Thread A. Sets barrier, waits for release using Mutex::Await, then
480 // signals released_cv.
481 pool->Schedule([&state] {
482 state.release_mu.Lock();
483
484 state.barrier_mu.Lock();
485 state.barrier = true;
486 state.barrier_mu.Unlock();
487
488 state.release_mu.Await(absl::Condition(&state.release));
489 state.released_cv.Signal();
490 state.release_mu.Unlock();
491 });
492
493 state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
494 state.barrier_mu.Unlock();
495 state.release_mu.Lock();
496 // Thread A is now blocked on release by way of Mutex::Await().
497
498 // Set release. Calling released_cv.Wait() should un-block thread A,
499 // which will signal released_cv. If not, the test will hang.
500 state.release = true;
501 EXPECT_TRUE(
502 !state.released_cv.WaitWithTimeout(&state.release_mu, absl::Seconds(10)))
503 << "; Unrecoverable test failure: CondVar::WaitWithTimeout did not "
504 "unblock the absl::Mutex::Await call in another thread.";
505
506 state.release_mu.Unlock();
507 }
508
509 // Test for regression of a bug in loop of TryRemove()
TEST(Mutex,MutexTimeoutBug)510 TEST(Mutex, MutexTimeoutBug) {
511 auto tp = CreateDefaultPool();
512
513 TimeoutBugStruct x;
514 x.a = false;
515 x.a_waiter_count = 2;
516 tp->Schedule(std::bind(&WaitForA, &x));
517 tp->Schedule(std::bind(&WaitForA, &x));
518 absl::SleepFor(absl::Seconds(1)); // Allow first two threads to hang.
519 // The skip field of the second will point to the first because there are
520 // only two.
521
522 // Now cause a thread waiting on an always-false to time out
523 // This would deadlock when the bug was present.
524 bool always_false = false;
525 x.mu.LockWhenWithTimeout(absl::Condition(&always_false),
526 absl::Milliseconds(500));
527
528 // if we get here, the bug is not present. Cleanup the state.
529
530 x.a = true; // wakeup the two waiters on A
531 x.mu.Await(absl::Condition(&NoAWaiters, &x)); // wait for them to exit
532 x.mu.Unlock();
533 }
534
535 struct CondVarWaitDeadlock : testing::TestWithParam<int> {
536 absl::Mutex mu;
537 absl::CondVar cv;
538 bool cond1 = false;
539 bool cond2 = false;
540 bool read_lock1;
541 bool read_lock2;
542 bool signal_unlocked;
543
CondVarWaitDeadlock__anon2f9e3b4b0111::CondVarWaitDeadlock544 CondVarWaitDeadlock() {
545 read_lock1 = GetParam() & (1 << 0);
546 read_lock2 = GetParam() & (1 << 1);
547 signal_unlocked = GetParam() & (1 << 2);
548 }
549
Waiter1__anon2f9e3b4b0111::CondVarWaitDeadlock550 void Waiter1() {
551 if (read_lock1) {
552 mu.ReaderLock();
553 while (!cond1) {
554 cv.Wait(&mu);
555 }
556 mu.ReaderUnlock();
557 } else {
558 mu.Lock();
559 while (!cond1) {
560 cv.Wait(&mu);
561 }
562 mu.Unlock();
563 }
564 }
565
Waiter2__anon2f9e3b4b0111::CondVarWaitDeadlock566 void Waiter2() {
567 if (read_lock2) {
568 mu.ReaderLockWhen(absl::Condition(&cond2));
569 mu.ReaderUnlock();
570 } else {
571 mu.LockWhen(absl::Condition(&cond2));
572 mu.Unlock();
573 }
574 }
575 };
576
577 // Test for a deadlock bug in Mutex::Fer().
578 // The sequence of events that lead to the deadlock is:
579 // 1. waiter1 blocks on cv in read mode (mu bits = 0).
580 // 2. waiter2 blocks on mu in either mode (mu bits = kMuWait).
581 // 3. main thread locks mu, sets cond1, unlocks mu (mu bits = kMuWait).
582 // 4. main thread signals on cv and this eventually calls Mutex::Fer().
583 // Currently Fer wakes waiter1 since mu bits = kMuWait (mutex is unlocked).
584 // Before the bug fix Fer neither woke waiter1 nor queued it on mutex,
585 // which resulted in deadlock.
TEST_P(CondVarWaitDeadlock,Test)586 TEST_P(CondVarWaitDeadlock, Test) {
587 auto waiter1 = CreatePool(1);
588 auto waiter2 = CreatePool(1);
589 waiter1->Schedule([this] { this->Waiter1(); });
590 waiter2->Schedule([this] { this->Waiter2(); });
591
592 // Wait while threads block (best-effort is fine).
593 absl::SleepFor(absl::Milliseconds(100));
594
595 // Wake condwaiter.
596 mu.Lock();
597 cond1 = true;
598 if (signal_unlocked) {
599 mu.Unlock();
600 cv.Signal();
601 } else {
602 cv.Signal();
603 mu.Unlock();
604 }
605 waiter1.reset(); // "join" waiter1
606
607 // Wake waiter.
608 mu.Lock();
609 cond2 = true;
610 mu.Unlock();
611 waiter2.reset(); // "join" waiter2
612 }
613
614 INSTANTIATE_TEST_SUITE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
615 ::testing::Range(0, 8),
616 ::testing::PrintToStringParamName());
617
618 // --------------------------------------------------------
619 // Test for fix of bug in DequeueAllWakeable()
620 // Bug was that if there was more than one waiting reader
621 // and all should be woken, the most recently blocked one
622 // would not be.
623
624 struct DequeueAllWakeableBugStruct {
625 absl::Mutex mu;
626 absl::Mutex mu2; // protects all fields below
627 int unfinished_count; // count of unfinished readers; under mu2
628 bool done1; // unfinished_count == 0; under mu2
629 int finished_count; // count of finished readers, under mu2
630 bool done2; // finished_count == 0; under mu2
631 };
632
633 // Test for regression of a bug in loop of DequeueAllWakeable()
AcquireAsReader(DequeueAllWakeableBugStruct * x)634 static void AcquireAsReader(DequeueAllWakeableBugStruct *x) {
635 x->mu.ReaderLock();
636 x->mu2.Lock();
637 x->unfinished_count--;
638 x->done1 = (x->unfinished_count == 0);
639 x->mu2.Unlock();
640 // make sure that both readers acquired mu before we release it.
641 absl::SleepFor(absl::Seconds(2));
642 x->mu.ReaderUnlock();
643
644 x->mu2.Lock();
645 x->finished_count--;
646 x->done2 = (x->finished_count == 0);
647 x->mu2.Unlock();
648 }
649
650 // Test for regression of a bug in loop of DequeueAllWakeable()
TEST(Mutex,MutexReaderWakeupBug)651 TEST(Mutex, MutexReaderWakeupBug) {
652 auto tp = CreateDefaultPool();
653
654 DequeueAllWakeableBugStruct x;
655 x.unfinished_count = 2;
656 x.done1 = false;
657 x.finished_count = 2;
658 x.done2 = false;
659 x.mu.Lock(); // acquire mu exclusively
660 // queue two thread that will block on reader locks on x.mu
661 tp->Schedule(std::bind(&AcquireAsReader, &x));
662 tp->Schedule(std::bind(&AcquireAsReader, &x));
663 absl::SleepFor(absl::Seconds(1)); // give time for reader threads to block
664 x.mu.Unlock(); // wake them up
665
666 // both readers should finish promptly
667 EXPECT_TRUE(
668 x.mu2.LockWhenWithTimeout(absl::Condition(&x.done1), absl::Seconds(10)));
669 x.mu2.Unlock();
670
671 EXPECT_TRUE(
672 x.mu2.LockWhenWithTimeout(absl::Condition(&x.done2), absl::Seconds(10)));
673 x.mu2.Unlock();
674 }
675
676 struct LockWhenTestStruct {
677 absl::Mutex mu1;
678 bool cond = false;
679
680 absl::Mutex mu2;
681 bool waiting = false;
682 };
683
LockWhenTestIsCond(LockWhenTestStruct * s)684 static bool LockWhenTestIsCond(LockWhenTestStruct* s) {
685 s->mu2.Lock();
686 s->waiting = true;
687 s->mu2.Unlock();
688 return s->cond;
689 }
690
LockWhenTestWaitForIsCond(LockWhenTestStruct * s)691 static void LockWhenTestWaitForIsCond(LockWhenTestStruct* s) {
692 s->mu1.LockWhen(absl::Condition(&LockWhenTestIsCond, s));
693 s->mu1.Unlock();
694 }
695
TEST(Mutex,LockWhen)696 TEST(Mutex, LockWhen) {
697 LockWhenTestStruct s;
698
699 std::thread t(LockWhenTestWaitForIsCond, &s);
700 s.mu2.LockWhen(absl::Condition(&s.waiting));
701 s.mu2.Unlock();
702
703 s.mu1.Lock();
704 s.cond = true;
705 s.mu1.Unlock();
706
707 t.join();
708 }
709
TEST(Mutex,LockWhenGuard)710 TEST(Mutex, LockWhenGuard) {
711 absl::Mutex mu;
712 int n = 30;
713 bool done = false;
714
715 // We don't inline the lambda because the conversion is ambiguous in MSVC.
716 bool (*cond_eq_10)(int *) = [](int *p) { return *p == 10; };
717 bool (*cond_lt_10)(int *) = [](int *p) { return *p < 10; };
718
719 std::thread t1([&mu, &n, &done, cond_eq_10]() {
720 absl::ReaderMutexLock lock(&mu, absl::Condition(cond_eq_10, &n));
721 done = true;
722 });
723
724 std::thread t2[10];
725 for (std::thread &t : t2) {
726 t = std::thread([&mu, &n, cond_lt_10]() {
727 absl::WriterMutexLock lock(&mu, absl::Condition(cond_lt_10, &n));
728 ++n;
729 });
730 }
731
732 {
733 absl::MutexLock lock(&mu);
734 n = 0;
735 }
736
737 for (std::thread &t : t2) t.join();
738 t1.join();
739
740 EXPECT_TRUE(done);
741 EXPECT_EQ(n, 10);
742 }
743
744 // --------------------------------------------------------
745 // The following test requires Mutex::ReaderLock to be a real shared
746 // lock, which is not the case in all builds.
747 #if !defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
748
749 // Test for fix of bug in UnlockSlow() that incorrectly decremented the reader
750 // count when putting a thread to sleep waiting for a false condition when the
751 // lock was not held.
752
753 // For this bug to strike, we make a thread wait on a free mutex with no
754 // waiters by causing its wakeup condition to be false. Then the
755 // next two acquirers must be readers. The bug causes the lock
756 // to be released when one reader unlocks, rather than both.
757
758 struct ReaderDecrementBugStruct {
759 bool cond; // to delay first thread (under mu)
760 int done; // reference count (under mu)
761 absl::Mutex mu;
762
763 bool waiting_on_cond; // under mu2
764 bool have_reader_lock; // under mu2
765 bool complete; // under mu2
766 absl::Mutex mu2; // > mu
767 };
768
769 // L >= mu, L < mu_waiting_on_cond
IsCond(void * v)770 static bool IsCond(void *v) {
771 ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
772 x->mu2.Lock();
773 x->waiting_on_cond = true;
774 x->mu2.Unlock();
775 return x->cond;
776 }
777
778 // L >= mu
AllDone(void * v)779 static bool AllDone(void *v) {
780 ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
781 return x->done == 0;
782 }
783
784 // L={}
WaitForCond(ReaderDecrementBugStruct * x)785 static void WaitForCond(ReaderDecrementBugStruct *x) {
786 absl::Mutex dummy;
787 absl::MutexLock l(&dummy);
788 x->mu.LockWhen(absl::Condition(&IsCond, x));
789 x->done--;
790 x->mu.Unlock();
791 }
792
793 // L={}
GetReadLock(ReaderDecrementBugStruct * x)794 static void GetReadLock(ReaderDecrementBugStruct *x) {
795 x->mu.ReaderLock();
796 x->mu2.Lock();
797 x->have_reader_lock = true;
798 x->mu2.Await(absl::Condition(&x->complete));
799 x->mu2.Unlock();
800 x->mu.ReaderUnlock();
801 x->mu.Lock();
802 x->done--;
803 x->mu.Unlock();
804 }
805
806 // Test for reader counter being decremented incorrectly by waiter
807 // with false condition.
TEST(Mutex,MutexReaderDecrementBug)808 TEST(Mutex, MutexReaderDecrementBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
809 ReaderDecrementBugStruct x;
810 x.cond = false;
811 x.waiting_on_cond = false;
812 x.have_reader_lock = false;
813 x.complete = false;
814 x.done = 2; // initial ref count
815
816 // Run WaitForCond() and wait for it to sleep
817 std::thread thread1(WaitForCond, &x);
818 x.mu2.LockWhen(absl::Condition(&x.waiting_on_cond));
819 x.mu2.Unlock();
820
821 // Run GetReadLock(), and wait for it to get the read lock
822 std::thread thread2(GetReadLock, &x);
823 x.mu2.LockWhen(absl::Condition(&x.have_reader_lock));
824 x.mu2.Unlock();
825
826 // Get the reader lock ourselves, and release it.
827 x.mu.ReaderLock();
828 x.mu.ReaderUnlock();
829
830 // The lock should be held in read mode by GetReadLock().
831 // If we have the bug, the lock will be free.
832 x.mu.AssertReaderHeld();
833
834 // Wake up all the threads.
835 x.mu2.Lock();
836 x.complete = true;
837 x.mu2.Unlock();
838
839 // TODO(delesley): turn on analysis once lock upgrading is supported.
840 // (This call upgrades the lock from shared to exclusive.)
841 x.mu.Lock();
842 x.cond = true;
843 x.mu.Await(absl::Condition(&AllDone, &x));
844 x.mu.Unlock();
845
846 thread1.join();
847 thread2.join();
848 }
849 #endif // !ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
850
851 // Test that we correctly handle the situation when a lock is
852 // held and then destroyed (w/o unlocking).
853 #ifdef ABSL_HAVE_THREAD_SANITIZER
854 // TSAN reports errors when locked Mutexes are destroyed.
TEST(Mutex,DISABLED_LockedMutexDestructionBug)855 TEST(Mutex, DISABLED_LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
856 #else
857 TEST(Mutex, LockedMutexDestructionBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
858 #endif
859 for (int i = 0; i != 10; i++) {
860 // Create, lock and destroy 10 locks.
861 const int kNumLocks = 10;
862 auto mu = absl::make_unique<absl::Mutex[]>(kNumLocks);
863 for (int j = 0; j != kNumLocks; j++) {
864 if ((j % 2) == 0) {
865 mu[j].WriterLock();
866 } else {
867 mu[j].ReaderLock();
868 }
869 }
870 }
871 }
872
873 // --------------------------------------------------------
874 // Test for bug with pattern of readers using a condvar. The bug was that if a
875 // reader went to sleep on a condition variable while one or more other readers
876 // held the lock, but there were no waiters, the reader count (held in the
877 // mutex word) would be lost. (This is because Enqueue() had at one time
878 // always placed the thread on the Mutex queue. Later (CL 4075610), to
879 // tolerate re-entry into Mutex from a Condition predicate, Enqueue() was
880 // changed so that it could also place a thread on a condition-variable. This
881 // introduced the case where Enqueue() returned with an empty queue, and this
882 // case was handled incorrectly in one place.)
883
884 static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv,
885 int *running) {
886 std::random_device dev;
887 std::mt19937 gen(dev());
888 std::uniform_int_distribution<int> random_millis(0, 15);
889 mu->ReaderLock();
890 while (*running == 3) {
891 absl::SleepFor(absl::Milliseconds(random_millis(gen)));
892 cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen)));
893 }
894 mu->ReaderUnlock();
895 mu->Lock();
896 (*running)--;
897 mu->Unlock();
898 }
899
900 struct True {
901 template <class... Args>
902 bool operator()(Args...) const {
903 return true;
904 }
905 };
906
907 struct DerivedTrue : True {};
908
909 TEST(Mutex, FunctorCondition) {
910 { // Variadic
911 True f;
912 EXPECT_TRUE(absl::Condition(&f).Eval());
913 }
914
915 { // Inherited
916 DerivedTrue g;
917 EXPECT_TRUE(absl::Condition(&g).Eval());
918 }
919
920 { // lambda
921 int value = 3;
922 auto is_zero = [&value] { return value == 0; };
923 absl::Condition c(&is_zero);
924 EXPECT_FALSE(c.Eval());
925 value = 0;
926 EXPECT_TRUE(c.Eval());
927 }
928
929 { // bind
930 int value = 0;
931 auto is_positive = std::bind(std::less<int>(), 0, std::cref(value));
932 absl::Condition c(&is_positive);
933 EXPECT_FALSE(c.Eval());
934 value = 1;
935 EXPECT_TRUE(c.Eval());
936 }
937
938 { // std::function
939 int value = 3;
940 std::function<bool()> is_zero = [&value] { return value == 0; };
941 absl::Condition c(&is_zero);
942 EXPECT_FALSE(c.Eval());
943 value = 0;
944 EXPECT_TRUE(c.Eval());
945 }
946 }
947
948 static bool IntIsZero(int *x) { return *x == 0; }
949
950 // Test for reader waiting condition variable when there are other readers
951 // but no waiters.
952 TEST(Mutex, TestReaderOnCondVar) {
953 auto tp = CreateDefaultPool();
954 absl::Mutex mu;
955 absl::CondVar cv;
956 int running = 3;
957 tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
958 tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
959 absl::SleepFor(absl::Seconds(2));
960 mu.Lock();
961 running--;
962 mu.Await(absl::Condition(&IntIsZero, &running));
963 mu.Unlock();
964 }
965
966 // --------------------------------------------------------
967 struct AcquireFromConditionStruct {
968 absl::Mutex mu0; // protects value, done
969 int value; // times condition function is called; under mu0,
970 bool done; // done with test? under mu0
971 absl::Mutex mu1; // used to attempt to mess up state of mu0
972 absl::CondVar cv; // so the condition function can be invoked from
973 // CondVar::Wait().
974 };
975
976 static bool ConditionWithAcquire(AcquireFromConditionStruct *x) {
977 x->value++; // count times this function is called
978
979 if (x->value == 2 || x->value == 3) {
980 // On the second and third invocation of this function, sleep for 100ms,
981 // but with the side-effect of altering the state of a Mutex other than
982 // than one for which this is a condition. The spec now explicitly allows
983 // this side effect; previously it did not. it was illegal.
984 bool always_false = false;
985 x->mu1.LockWhenWithTimeout(absl::Condition(&always_false),
986 absl::Milliseconds(100));
987 x->mu1.Unlock();
988 }
989 ABSL_RAW_CHECK(x->value < 4, "should not be invoked a fourth time");
990
991 // We arrange for the condition to return true on only the 2nd and 3rd calls.
992 return x->value == 2 || x->value == 3;
993 }
994
995 static void WaitForCond2(AcquireFromConditionStruct *x) {
996 // wait for cond0 to become true
997 x->mu0.LockWhen(absl::Condition(&ConditionWithAcquire, x));
998 x->done = true;
999 x->mu0.Unlock();
1000 }
1001
1002 // Test for Condition whose function acquires other Mutexes
1003 TEST(Mutex, AcquireFromCondition) {
1004 auto tp = CreateDefaultPool();
1005
1006 AcquireFromConditionStruct x;
1007 x.value = 0;
1008 x.done = false;
1009 tp->Schedule(
1010 std::bind(&WaitForCond2, &x)); // run WaitForCond2() in a thread T
1011 // T will hang because the first invocation of ConditionWithAcquire() will
1012 // return false.
1013 absl::SleepFor(absl::Milliseconds(500)); // allow T time to hang
1014
1015 x.mu0.Lock();
1016 x.cv.WaitWithTimeout(&x.mu0, absl::Milliseconds(500)); // wake T
1017 // T will be woken because the Wait() will call ConditionWithAcquire()
1018 // for the second time, and it will return true.
1019
1020 x.mu0.Unlock();
1021
1022 // T will then acquire the lock and recheck its own condition.
1023 // It will find the condition true, as this is the third invocation,
1024 // but the use of another Mutex by the calling function will
1025 // cause the old mutex implementation to think that the outer
1026 // LockWhen() has timed out because the inner LockWhenWithTimeout() did.
1027 // T will then check the condition a fourth time because it finds a
1028 // timeout occurred. This should not happen in the new
1029 // implementation that allows the Condition function to use Mutexes.
1030
1031 // It should also succeed, even though the Condition function
1032 // is being invoked from CondVar::Wait, and thus this thread
1033 // is conceptually waiting both on the condition variable, and on mu2.
1034
1035 x.mu0.LockWhen(absl::Condition(&x.done));
1036 x.mu0.Unlock();
1037 }
1038
1039 TEST(Mutex, DeadlockDetector) {
1040 absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
1041
1042 // check that we can call ForgetDeadlockInfo() on a lock with the lock held
1043 absl::Mutex m1;
1044 absl::Mutex m2;
1045 absl::Mutex m3;
1046 absl::Mutex m4;
1047
1048 m1.Lock(); // m1 gets ID1
1049 m2.Lock(); // m2 gets ID2
1050 m3.Lock(); // m3 gets ID3
1051 m3.Unlock();
1052 m2.Unlock();
1053 // m1 still held
1054 m1.ForgetDeadlockInfo(); // m1 loses ID
1055 m2.Lock(); // m2 gets ID2
1056 m3.Lock(); // m3 gets ID3
1057 m4.Lock(); // m4 gets ID4
1058 m3.Unlock();
1059 m2.Unlock();
1060 m4.Unlock();
1061 m1.Unlock();
1062 }
1063
1064 // Bazel has a test "warning" file that programs can write to if the
1065 // test should pass with a warning. This class disables the warning
1066 // file until it goes out of scope.
1067 class ScopedDisableBazelTestWarnings {
1068 public:
1069 ScopedDisableBazelTestWarnings() {
1070 #ifdef _WIN32
1071 char file[MAX_PATH];
1072 if (GetEnvironmentVariableA(kVarName, file, sizeof(file)) < sizeof(file)) {
1073 warnings_output_file_ = file;
1074 SetEnvironmentVariableA(kVarName, nullptr);
1075 }
1076 #else
1077 const char *file = getenv(kVarName);
1078 if (file != nullptr) {
1079 warnings_output_file_ = file;
1080 unsetenv(kVarName);
1081 }
1082 #endif
1083 }
1084
1085 ~ScopedDisableBazelTestWarnings() {
1086 if (!warnings_output_file_.empty()) {
1087 #ifdef _WIN32
1088 SetEnvironmentVariableA(kVarName, warnings_output_file_.c_str());
1089 #else
1090 setenv(kVarName, warnings_output_file_.c_str(), 0);
1091 #endif
1092 }
1093 }
1094
1095 private:
1096 static const char kVarName[];
1097 std::string warnings_output_file_;
1098 };
1099 const char ScopedDisableBazelTestWarnings::kVarName[] =
1100 "TEST_WARNINGS_OUTPUT_FILE";
1101
1102 #ifdef ABSL_HAVE_THREAD_SANITIZER
1103 // This test intentionally creates deadlocks to test the deadlock detector.
1104 TEST(Mutex, DISABLED_DeadlockDetectorBazelWarning) {
1105 #else
1106 TEST(Mutex, DeadlockDetectorBazelWarning) {
1107 #endif
1108 absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport);
1109
1110 // Cause deadlock detection to detect something, if it's
1111 // compiled in and enabled. But turn off the bazel warning.
1112 ScopedDisableBazelTestWarnings disable_bazel_test_warnings;
1113
1114 absl::Mutex mu0;
1115 absl::Mutex mu1;
1116 bool got_mu0 = mu0.TryLock();
1117 mu1.Lock(); // acquire mu1 while holding mu0
1118 if (got_mu0) {
1119 mu0.Unlock();
1120 }
1121 if (mu0.TryLock()) { // try lock shouldn't cause deadlock detector to fire
1122 mu0.Unlock();
1123 }
1124 mu0.Lock(); // acquire mu0 while holding mu1; should get one deadlock
1125 // report here
1126 mu0.Unlock();
1127 mu1.Unlock();
1128
1129 absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
1130 }
1131
1132 // This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the
1133 // annotation-based static thread-safety analysis is not currently
1134 // predicate-aware and cannot tell if the two for-loops that acquire and
1135 // release the locks have the same predicates.
1136 TEST(Mutex, DeadlockDetectorStressTest) ABSL_NO_THREAD_SAFETY_ANALYSIS {
1137 // Stress test: Here we create a large number of locks and use all of them.
1138 // If a deadlock detector keeps a full graph of lock acquisition order,
1139 // it will likely be too slow for this test to pass.
1140 const int n_locks = 1 << 17;
1141 auto array_of_locks = absl::make_unique<absl::Mutex[]>(n_locks);
1142 for (int i = 0; i < n_locks; i++) {
1143 int end = std::min(n_locks, i + 5);
1144 // acquire and then release locks i, i+1, ..., i+4
1145 for (int j = i; j < end; j++) {
1146 array_of_locks[j].Lock();
1147 }
1148 for (int j = i; j < end; j++) {
1149 array_of_locks[j].Unlock();
1150 }
1151 }
1152 }
1153
1154 #ifdef ABSL_HAVE_THREAD_SANITIZER
1155 // TSAN reports errors when locked Mutexes are destroyed.
1156 TEST(Mutex, DISABLED_DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
1157 #else
1158 TEST(Mutex, DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS {
1159 #endif
1160 // Test a scenario where a cached deadlock graph node id in the
1161 // list of held locks is not invalidated when the corresponding
1162 // mutex is deleted.
1163 absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
1164 // Mutex that will be destroyed while being held
1165 absl::Mutex *a = new absl::Mutex;
1166 // Other mutexes needed by test
1167 absl::Mutex b, c;
1168
1169 // Hold mutex.
1170 a->Lock();
1171
1172 // Force deadlock id assignment by acquiring another lock.
1173 b.Lock();
1174 b.Unlock();
1175
1176 // Delete the mutex. The Mutex destructor tries to remove held locks,
1177 // but the attempt isn't foolproof. It can fail if:
1178 // (a) Deadlock detection is currently disabled.
1179 // (b) The destruction is from another thread.
1180 // We exploit (a) by temporarily disabling deadlock detection.
1181 absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore);
1182 delete a;
1183 absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
1184
1185 // Now acquire another lock which will force a deadlock id assignment.
1186 // We should end up getting assigned the same deadlock id that was
1187 // freed up when "a" was deleted, which will cause a spurious deadlock
1188 // report if the held lock entry for "a" was not invalidated.
1189 c.Lock();
1190 c.Unlock();
1191 }
1192
1193 // --------------------------------------------------------
1194 // Test for timeouts/deadlines on condition waits that are specified using
1195 // absl::Duration and absl::Time. For each waiting function we test with
1196 // a timeout/deadline that has already expired/passed, one that is infinite
1197 // and so never expires/passes, and one that will expire/pass in the near
1198 // future.
1199
1200 static absl::Duration TimeoutTestAllowedSchedulingDelay() {
1201 // Note: we use a function here because Microsoft Visual Studio fails to
1202 // properly initialize constexpr static absl::Duration variables.
1203 return absl::Milliseconds(150);
1204 }
1205
1206 // Returns true if `actual_delay` is close enough to `expected_delay` to pass
1207 // the timeouts/deadlines test. Otherwise, logs warnings and returns false.
1208 ABSL_MUST_USE_RESULT
1209 static bool DelayIsWithinBounds(absl::Duration expected_delay,
1210 absl::Duration actual_delay) {
1211 bool pass = true;
1212 // Do not allow the observed delay to be less than expected. This may occur
1213 // in practice due to clock skew or when the synchronization primitives use a
1214 // different clock than absl::Now(), but these cases should be handled by the
1215 // the retry mechanism in each TimeoutTest.
1216 if (actual_delay < expected_delay) {
1217 ABSL_RAW_LOG(WARNING,
1218 "Actual delay %s was too short, expected %s (difference %s)",
1219 absl::FormatDuration(actual_delay).c_str(),
1220 absl::FormatDuration(expected_delay).c_str(),
1221 absl::FormatDuration(actual_delay - expected_delay).c_str());
1222 pass = false;
1223 }
1224 // If the expected delay is <= zero then allow a small error tolerance, since
1225 // we do not expect context switches to occur during test execution.
1226 // Otherwise, thread scheduling delays may be substantial in rare cases, so
1227 // tolerate up to kTimeoutTestAllowedSchedulingDelay of error.
1228 absl::Duration tolerance = expected_delay <= absl::ZeroDuration()
1229 ? absl::Milliseconds(10)
1230 : TimeoutTestAllowedSchedulingDelay();
1231 if (actual_delay > expected_delay + tolerance) {
1232 ABSL_RAW_LOG(WARNING,
1233 "Actual delay %s was too long, expected %s (difference %s)",
1234 absl::FormatDuration(actual_delay).c_str(),
1235 absl::FormatDuration(expected_delay).c_str(),
1236 absl::FormatDuration(actual_delay - expected_delay).c_str());
1237 pass = false;
1238 }
1239 return pass;
1240 }
1241
1242 // Parameters for TimeoutTest, below.
1243 struct TimeoutTestParam {
1244 // The file and line number (used for logging purposes only).
1245 const char *from_file;
1246 int from_line;
1247
1248 // Should the absolute deadline API based on absl::Time be tested? If false,
1249 // the relative deadline API based on absl::Duration is tested.
1250 bool use_absolute_deadline;
1251
1252 // The deadline/timeout used when calling the API being tested
1253 // (e.g. Mutex::LockWhenWithDeadline).
1254 absl::Duration wait_timeout;
1255
1256 // The delay before the condition will be set true by the test code. If zero
1257 // or negative, the condition is set true immediately (before calling the API
1258 // being tested). Otherwise, if infinite, the condition is never set true.
1259 // Otherwise a closure is scheduled for the future that sets the condition
1260 // true.
1261 absl::Duration satisfy_condition_delay;
1262
1263 // The expected result of the condition after the call to the API being
1264 // tested. Generally `true` means the condition was true when the API returns,
1265 // `false` indicates an expected timeout.
1266 bool expected_result;
1267
1268 // The expected delay before the API under test returns. This is inherently
1269 // flaky, so some slop is allowed (see `DelayIsWithinBounds` above), and the
1270 // test keeps trying indefinitely until this constraint passes.
1271 absl::Duration expected_delay;
1272 };
1273
1274 // Print a `TimeoutTestParam` to a debug log.
1275 std::ostream &operator<<(std::ostream &os, const TimeoutTestParam ¶m) {
1276 return os << "from: " << param.from_file << ":" << param.from_line
1277 << " use_absolute_deadline: "
1278 << (param.use_absolute_deadline ? "true" : "false")
1279 << " wait_timeout: " << param.wait_timeout
1280 << " satisfy_condition_delay: " << param.satisfy_condition_delay
1281 << " expected_result: "
1282 << (param.expected_result ? "true" : "false")
1283 << " expected_delay: " << param.expected_delay;
1284 }
1285
1286 std::string FormatString(const TimeoutTestParam ¶m) {
1287 std::ostringstream os;
1288 os << param;
1289 return os.str();
1290 }
1291
1292 // Like `thread::Executor::ScheduleAt` except:
1293 // a) Delays zero or negative are executed immediately in the current thread.
1294 // b) Infinite delays are never scheduled.
1295 // c) Calls this test's `ScheduleAt` helper instead of using `pool` directly.
1296 static void RunAfterDelay(absl::Duration delay,
1297 absl::synchronization_internal::ThreadPool *pool,
1298 const std::function<void()> &callback) {
1299 if (delay <= absl::ZeroDuration()) {
1300 callback(); // immediate
1301 } else if (delay != absl::InfiniteDuration()) {
1302 ScheduleAfter(pool, delay, callback);
1303 }
1304 }
1305
1306 class TimeoutTest : public ::testing::Test,
1307 public ::testing::WithParamInterface<TimeoutTestParam> {};
1308
1309 std::vector<TimeoutTestParam> MakeTimeoutTestParamValues() {
1310 // The `finite` delay is a finite, relatively short, delay. We make it larger
1311 // than our allowed scheduling delay (slop factor) to avoid confusion when
1312 // diagnosing test failures. The other constants here have clear meanings.
1313 const absl::Duration finite = 3 * TimeoutTestAllowedSchedulingDelay();
1314 const absl::Duration never = absl::InfiniteDuration();
1315 const absl::Duration negative = -absl::InfiniteDuration();
1316 const absl::Duration immediate = absl::ZeroDuration();
1317
1318 // Every test case is run twice; once using the absolute deadline API and once
1319 // using the relative timeout API.
1320 std::vector<TimeoutTestParam> values;
1321 for (bool use_absolute_deadline : {false, true}) {
1322 // Tests with a negative timeout (deadline in the past), which should
1323 // immediately return current state of the condition.
1324
1325 // The condition is already true:
1326 values.push_back(TimeoutTestParam{
1327 __FILE__, __LINE__, use_absolute_deadline,
1328 negative, // wait_timeout
1329 immediate, // satisfy_condition_delay
1330 true, // expected_result
1331 immediate, // expected_delay
1332 });
1333
1334 // The condition becomes true, but the timeout has already expired:
1335 values.push_back(TimeoutTestParam{
1336 __FILE__, __LINE__, use_absolute_deadline,
1337 negative, // wait_timeout
1338 finite, // satisfy_condition_delay
1339 false, // expected_result
1340 immediate // expected_delay
1341 });
1342
1343 // The condition never becomes true:
1344 values.push_back(TimeoutTestParam{
1345 __FILE__, __LINE__, use_absolute_deadline,
1346 negative, // wait_timeout
1347 never, // satisfy_condition_delay
1348 false, // expected_result
1349 immediate // expected_delay
1350 });
1351
1352 // Tests with an infinite timeout (deadline in the infinite future), which
1353 // should only return when the condition becomes true.
1354
1355 // The condition is already true:
1356 values.push_back(TimeoutTestParam{
1357 __FILE__, __LINE__, use_absolute_deadline,
1358 never, // wait_timeout
1359 immediate, // satisfy_condition_delay
1360 true, // expected_result
1361 immediate // expected_delay
1362 });
1363
1364 // The condition becomes true before the (infinite) expiry:
1365 values.push_back(TimeoutTestParam{
1366 __FILE__, __LINE__, use_absolute_deadline,
1367 never, // wait_timeout
1368 finite, // satisfy_condition_delay
1369 true, // expected_result
1370 finite, // expected_delay
1371 });
1372
1373 // Tests with a (small) finite timeout (deadline soon), with the condition
1374 // becoming true both before and after its expiry.
1375
1376 // The condition is already true:
1377 values.push_back(TimeoutTestParam{
1378 __FILE__, __LINE__, use_absolute_deadline,
1379 never, // wait_timeout
1380 immediate, // satisfy_condition_delay
1381 true, // expected_result
1382 immediate // expected_delay
1383 });
1384
1385 // The condition becomes true before the expiry:
1386 values.push_back(TimeoutTestParam{
1387 __FILE__, __LINE__, use_absolute_deadline,
1388 finite * 2, // wait_timeout
1389 finite, // satisfy_condition_delay
1390 true, // expected_result
1391 finite // expected_delay
1392 });
1393
1394 // The condition becomes true, but the timeout has already expired:
1395 values.push_back(TimeoutTestParam{
1396 __FILE__, __LINE__, use_absolute_deadline,
1397 finite, // wait_timeout
1398 finite * 2, // satisfy_condition_delay
1399 false, // expected_result
1400 finite // expected_delay
1401 });
1402
1403 // The condition never becomes true:
1404 values.push_back(TimeoutTestParam{
1405 __FILE__, __LINE__, use_absolute_deadline,
1406 finite, // wait_timeout
1407 never, // satisfy_condition_delay
1408 false, // expected_result
1409 finite // expected_delay
1410 });
1411 }
1412 return values;
1413 }
1414
1415 // Instantiate `TimeoutTest` with `MakeTimeoutTestParamValues()`.
1416 INSTANTIATE_TEST_SUITE_P(All, TimeoutTest,
1417 testing::ValuesIn(MakeTimeoutTestParamValues()));
1418
1419 TEST_P(TimeoutTest, Await) {
1420 const TimeoutTestParam params = GetParam();
1421 ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
1422
1423 // Because this test asserts bounds on scheduling delays it is flaky. To
1424 // compensate it loops forever until it passes. Failures express as test
1425 // timeouts, in which case the test log can be used to diagnose the issue.
1426 for (int attempt = 1;; ++attempt) {
1427 ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
1428
1429 absl::Mutex mu;
1430 bool value = false; // condition value (under mu)
1431
1432 std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
1433 CreateDefaultPool();
1434 RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
1435 absl::MutexLock l(&mu);
1436 value = true;
1437 });
1438
1439 absl::MutexLock lock(&mu);
1440 absl::Time start_time = absl::Now();
1441 absl::Condition cond(&value);
1442 bool result =
1443 params.use_absolute_deadline
1444 ? mu.AwaitWithDeadline(cond, start_time + params.wait_timeout)
1445 : mu.AwaitWithTimeout(cond, params.wait_timeout);
1446 if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
1447 EXPECT_EQ(params.expected_result, result);
1448 break;
1449 }
1450 }
1451 }
1452
1453 TEST_P(TimeoutTest, LockWhen) {
1454 const TimeoutTestParam params = GetParam();
1455 ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
1456
1457 // Because this test asserts bounds on scheduling delays it is flaky. To
1458 // compensate it loops forever until it passes. Failures express as test
1459 // timeouts, in which case the test log can be used to diagnose the issue.
1460 for (int attempt = 1;; ++attempt) {
1461 ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
1462
1463 absl::Mutex mu;
1464 bool value = false; // condition value (under mu)
1465
1466 std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
1467 CreateDefaultPool();
1468 RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
1469 absl::MutexLock l(&mu);
1470 value = true;
1471 });
1472
1473 absl::Time start_time = absl::Now();
1474 absl::Condition cond(&value);
1475 bool result =
1476 params.use_absolute_deadline
1477 ? mu.LockWhenWithDeadline(cond, start_time + params.wait_timeout)
1478 : mu.LockWhenWithTimeout(cond, params.wait_timeout);
1479 mu.Unlock();
1480
1481 if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
1482 EXPECT_EQ(params.expected_result, result);
1483 break;
1484 }
1485 }
1486 }
1487
1488 TEST_P(TimeoutTest, ReaderLockWhen) {
1489 const TimeoutTestParam params = GetParam();
1490 ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
1491
1492 // Because this test asserts bounds on scheduling delays it is flaky. To
1493 // compensate it loops forever until it passes. Failures express as test
1494 // timeouts, in which case the test log can be used to diagnose the issue.
1495 for (int attempt = 0;; ++attempt) {
1496 ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
1497
1498 absl::Mutex mu;
1499 bool value = false; // condition value (under mu)
1500
1501 std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
1502 CreateDefaultPool();
1503 RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
1504 absl::MutexLock l(&mu);
1505 value = true;
1506 });
1507
1508 absl::Time start_time = absl::Now();
1509 bool result =
1510 params.use_absolute_deadline
1511 ? mu.ReaderLockWhenWithDeadline(absl::Condition(&value),
1512 start_time + params.wait_timeout)
1513 : mu.ReaderLockWhenWithTimeout(absl::Condition(&value),
1514 params.wait_timeout);
1515 mu.ReaderUnlock();
1516
1517 if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
1518 EXPECT_EQ(params.expected_result, result);
1519 break;
1520 }
1521 }
1522 }
1523
1524 TEST_P(TimeoutTest, Wait) {
1525 const TimeoutTestParam params = GetParam();
1526 ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str());
1527
1528 // Because this test asserts bounds on scheduling delays it is flaky. To
1529 // compensate it loops forever until it passes. Failures express as test
1530 // timeouts, in which case the test log can be used to diagnose the issue.
1531 for (int attempt = 0;; ++attempt) {
1532 ABSL_RAW_LOG(INFO, "Attempt %d", attempt);
1533
1534 absl::Mutex mu;
1535 bool value = false; // condition value (under mu)
1536 absl::CondVar cv; // signals a change of `value`
1537
1538 std::unique_ptr<absl::synchronization_internal::ThreadPool> pool =
1539 CreateDefaultPool();
1540 RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] {
1541 absl::MutexLock l(&mu);
1542 value = true;
1543 cv.Signal();
1544 });
1545
1546 absl::MutexLock lock(&mu);
1547 absl::Time start_time = absl::Now();
1548 absl::Duration timeout = params.wait_timeout;
1549 absl::Time deadline = start_time + timeout;
1550 while (!value) {
1551 if (params.use_absolute_deadline ? cv.WaitWithDeadline(&mu, deadline)
1552 : cv.WaitWithTimeout(&mu, timeout)) {
1553 break; // deadline/timeout exceeded
1554 }
1555 timeout = deadline - absl::Now(); // recompute
1556 }
1557 bool result = value; // note: `mu` is still held
1558
1559 if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) {
1560 EXPECT_EQ(params.expected_result, result);
1561 break;
1562 }
1563 }
1564 }
1565
1566 TEST(Mutex, Logging) {
1567 // Allow user to look at logging output
1568 absl::Mutex logged_mutex;
1569 logged_mutex.EnableDebugLog("fido_mutex");
1570 absl::CondVar logged_cv;
1571 logged_cv.EnableDebugLog("rover_cv");
1572 logged_mutex.Lock();
1573 logged_cv.WaitWithTimeout(&logged_mutex, absl::Milliseconds(20));
1574 logged_mutex.Unlock();
1575 logged_mutex.ReaderLock();
1576 logged_mutex.ReaderUnlock();
1577 logged_mutex.Lock();
1578 logged_mutex.Unlock();
1579 logged_cv.Signal();
1580 logged_cv.SignalAll();
1581 }
1582
1583 // --------------------------------------------------------
1584
1585 // Generate the vector of thread counts for tests parameterized on thread count.
1586 static std::vector<int> AllThreadCountValues() {
1587 if (kExtendedTest) {
1588 return {2, 4, 8, 10, 16, 20, 24, 30, 32};
1589 }
1590 return {2, 4, 10};
1591 }
1592
1593 // A test fixture parameterized by thread count.
1594 class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {};
1595
1596 // Instantiate the above with AllThreadCountOptions().
1597 INSTANTIATE_TEST_SUITE_P(ThreadCounts, MutexVariableThreadCountTest,
1598 ::testing::ValuesIn(AllThreadCountValues()),
1599 ::testing::PrintToStringParamName());
1600
1601 // Reduces iterations by some factor for slow platforms
1602 // (determined empirically).
1603 static int ScaleIterations(int x) {
1604 // ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE is set in the implementation
1605 // of Mutex that uses either std::mutex or pthread_mutex_t. Use
1606 // these as keys to determine the slow implementation.
1607 #if defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
1608 return x / 10;
1609 #else
1610 return x;
1611 #endif
1612 }
1613
1614 TEST_P(MutexVariableThreadCountTest, Mutex) {
1615 int threads = GetParam();
1616 int iterations = ScaleIterations(10000000) / threads;
1617 int operations = threads * iterations;
1618 EXPECT_EQ(RunTest(&TestMu, threads, iterations, operations), operations);
1619 #if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
1620 iterations = std::min(iterations, 10);
1621 operations = threads * iterations;
1622 EXPECT_EQ(RunTestWithInvariantDebugging(&TestMu, threads, iterations,
1623 operations, CheckSumG0G1),
1624 operations);
1625 #endif
1626 }
1627
1628 TEST_P(MutexVariableThreadCountTest, Try) {
1629 int threads = GetParam();
1630 int iterations = 1000000 / threads;
1631 int operations = iterations * threads;
1632 EXPECT_EQ(RunTest(&TestTry, threads, iterations, operations), operations);
1633 #if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
1634 iterations = std::min(iterations, 10);
1635 operations = threads * iterations;
1636 EXPECT_EQ(RunTestWithInvariantDebugging(&TestTry, threads, iterations,
1637 operations, CheckSumG0G1),
1638 operations);
1639 #endif
1640 }
1641
1642 TEST_P(MutexVariableThreadCountTest, R20ms) {
1643 int threads = GetParam();
1644 int iterations = 100;
1645 int operations = iterations * threads;
1646 EXPECT_EQ(RunTest(&TestR20ms, threads, iterations, operations), 0);
1647 }
1648
1649 TEST_P(MutexVariableThreadCountTest, RW) {
1650 int threads = GetParam();
1651 int iterations = ScaleIterations(20000000) / threads;
1652 int operations = iterations * threads;
1653 EXPECT_EQ(RunTest(&TestRW, threads, iterations, operations), operations / 2);
1654 #if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
1655 iterations = std::min(iterations, 10);
1656 operations = threads * iterations;
1657 EXPECT_EQ(RunTestWithInvariantDebugging(&TestRW, threads, iterations,
1658 operations, CheckSumG0G1),
1659 operations / 2);
1660 #endif
1661 }
1662
1663 TEST_P(MutexVariableThreadCountTest, Await) {
1664 int threads = GetParam();
1665 int iterations = ScaleIterations(500000);
1666 int operations = iterations;
1667 EXPECT_EQ(RunTest(&TestAwait, threads, iterations, operations), operations);
1668 }
1669
1670 TEST_P(MutexVariableThreadCountTest, SignalAll) {
1671 int threads = GetParam();
1672 int iterations = 200000 / threads;
1673 int operations = iterations;
1674 EXPECT_EQ(RunTest(&TestSignalAll, threads, iterations, operations),
1675 operations);
1676 }
1677
1678 TEST(Mutex, Signal) {
1679 int threads = 2; // TestSignal must use two threads
1680 int iterations = 200000;
1681 int operations = iterations;
1682 EXPECT_EQ(RunTest(&TestSignal, threads, iterations, operations), operations);
1683 }
1684
1685 TEST(Mutex, Timed) {
1686 int threads = 10; // Use a fixed thread count of 10
1687 int iterations = 1000;
1688 int operations = iterations;
1689 EXPECT_EQ(RunTest(&TestCVTimeout, threads, iterations, operations),
1690 operations);
1691 }
1692
1693 TEST(Mutex, CVTime) {
1694 int threads = 10; // Use a fixed thread count of 10
1695 int iterations = 1;
1696 EXPECT_EQ(RunTest(&TestCVTime, threads, iterations, 1),
1697 threads * iterations);
1698 }
1699
1700 TEST(Mutex, MuTime) {
1701 int threads = 10; // Use a fixed thread count of 10
1702 int iterations = 1;
1703 EXPECT_EQ(RunTest(&TestMuTime, threads, iterations, 1), threads * iterations);
1704 }
1705
1706 } // namespace
1707