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