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