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