| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539 | // Copyright 2017 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.#include "absl/synchronization/mutex.h"#ifdef WIN32#include <windows.h>#endif#include <algorithm>#include <atomic>#include <cstdlib>#include <functional>#include <memory>#include <random>#include <string>#include <thread>  // NOLINT(build/c++11)#include <vector>#include "gtest/gtest.h"#include "absl/base/internal/raw_logging.h"#include "absl/base/internal/sysinfo.h"#include "absl/memory/memory.h"#include "absl/synchronization/internal/thread_pool.h"#include "absl/time/clock.h"#include "absl/time/time.h"namespace {// TODO(dmauro): Replace with a commandline flag.static constexpr bool kExtendedTest = false;std::unique_ptr<absl::synchronization_internal::ThreadPool> CreatePool(    int threads) {  return absl::make_unique<absl::synchronization_internal::ThreadPool>(threads);}std::unique_ptr<absl::synchronization_internal::ThreadPool>CreateDefaultPool() {  return CreatePool(kExtendedTest ? 32 : 10);}// Hack to schedule a function to run on a thread pool thread after a// duration has elapsed.static void ScheduleAfter(absl::synchronization_internal::ThreadPool *tp,                          const std::function<void()> &func,                          absl::Duration after) {  tp->Schedule([func, after] {    absl::SleepFor(after);    func();  });}struct TestContext {  int iterations;  int threads;  int g0;  // global 0  int g1;  // global 1  absl::Mutex mu;  absl::CondVar cv;};// To test whether the invariant check call occursstatic std::atomic<bool> invariant_checked;static bool GetInvariantChecked() {  return invariant_checked.load(std::memory_order_relaxed);}static void SetInvariantChecked(bool new_value) {  invariant_checked.store(new_value, std::memory_order_relaxed);}static void CheckSumG0G1(void *v) {  TestContext *cxt = static_cast<TestContext *>(v);  ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in CheckSumG0G1");  SetInvariantChecked(true);}static void TestMu(TestContext *cxt, int c) {  for (int i = 0; i != cxt->iterations; i++) {    absl::MutexLock l(&cxt->mu);    int a = cxt->g0 + 1;    cxt->g0 = a;    cxt->g1--;  }}static void TestTry(TestContext *cxt, int c) {  for (int i = 0; i != cxt->iterations; i++) {    do {      std::this_thread::yield();    } while (!cxt->mu.TryLock());    int a = cxt->g0 + 1;    cxt->g0 = a;    cxt->g1--;    cxt->mu.Unlock();  }}static void TestR20ms(TestContext *cxt, int c) {  for (int i = 0; i != cxt->iterations; i++) {    absl::ReaderMutexLock l(&cxt->mu);    absl::SleepFor(absl::Milliseconds(20));    cxt->mu.AssertReaderHeld();  }}static void TestRW(TestContext *cxt, int c) {  if ((c & 1) == 0) {    for (int i = 0; i != cxt->iterations; i++) {      absl::WriterMutexLock l(&cxt->mu);      cxt->g0++;      cxt->g1--;      cxt->mu.AssertHeld();      cxt->mu.AssertReaderHeld();    }  } else {    for (int i = 0; i != cxt->iterations; i++) {      absl::ReaderMutexLock l(&cxt->mu);      ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in TestRW");      cxt->mu.AssertReaderHeld();    }  }}struct MyContext {  int target;  TestContext *cxt;  bool MyTurn();};bool MyContext::MyTurn() {  TestContext *cxt = this->cxt;  return cxt->g0 == this->target || cxt->g0 == cxt->iterations;}static void TestAwait(TestContext *cxt, int c) {  MyContext mc;  mc.target = c;  mc.cxt = cxt;  absl::MutexLock l(&cxt->mu);  cxt->mu.AssertHeld();  while (cxt->g0 < cxt->iterations) {    cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn));    ABSL_RAW_CHECK(mc.MyTurn(), "Error in TestAwait");    cxt->mu.AssertHeld();    if (cxt->g0 < cxt->iterations) {      int a = cxt->g0 + 1;      cxt->g0 = a;      mc.target += cxt->threads;    }  }}static void TestSignalAll(TestContext *cxt, int c) {  int target = c;  absl::MutexLock l(&cxt->mu);  cxt->mu.AssertHeld();  while (cxt->g0 < cxt->iterations) {    while (cxt->g0 != target && cxt->g0 != cxt->iterations) {      cxt->cv.Wait(&cxt->mu);    }    if (cxt->g0 < cxt->iterations) {      int a = cxt->g0 + 1;      cxt->g0 = a;      cxt->cv.SignalAll();      target += cxt->threads;    }  }}static void TestSignal(TestContext *cxt, int c) {  ABSL_RAW_CHECK(cxt->threads == 2, "TestSignal should use 2 threads");  int target = c;  absl::MutexLock l(&cxt->mu);  cxt->mu.AssertHeld();  while (cxt->g0 < cxt->iterations) {    while (cxt->g0 != target && cxt->g0 != cxt->iterations) {      cxt->cv.Wait(&cxt->mu);    }    if (cxt->g0 < cxt->iterations) {      int a = cxt->g0 + 1;      cxt->g0 = a;      cxt->cv.Signal();      target += cxt->threads;    }  }}static void TestCVTimeout(TestContext *cxt, int c) {  int target = c;  absl::MutexLock l(&cxt->mu);  cxt->mu.AssertHeld();  while (cxt->g0 < cxt->iterations) {    while (cxt->g0 != target && cxt->g0 != cxt->iterations) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));    }    if (cxt->g0 < cxt->iterations) {      int a = cxt->g0 + 1;      cxt->g0 = a;      cxt->cv.SignalAll();      target += cxt->threads;    }  }}static bool G0GE2(TestContext *cxt) { return cxt->g0 >= 2; }static void TestTime(TestContext *cxt, int c, bool use_cv) {  ABSL_RAW_CHECK(cxt->iterations == 1, "TestTime should only use 1 iteration");  ABSL_RAW_CHECK(cxt->threads > 2, "TestTime should use more than 2 threads");  const bool kFalse = false;  absl::Condition false_cond(&kFalse);  absl::Condition g0ge2(G0GE2, cxt);  if (c == 0) {    absl::MutexLock l(&cxt->mu);    absl::Time start = absl::Now();    if (use_cv) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));    } else {      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),                     "TestTime failed");    }    absl::Duration elapsed = absl::Now() - start;    ABSL_RAW_CHECK(        absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),        "TestTime failed");    ABSL_RAW_CHECK(cxt->g0 == 1, "TestTime failed");    start = absl::Now();    if (use_cv) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));    } else {      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),                     "TestTime failed");    }    elapsed = absl::Now() - start;    ABSL_RAW_CHECK(        absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),        "TestTime failed");    cxt->g0++;    if (use_cv) {      cxt->cv.Signal();    }    start = absl::Now();    if (use_cv) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(4));    } else {      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4)),                     "TestTime failed");    }    elapsed = absl::Now() - start;    ABSL_RAW_CHECK(        absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0),        "TestTime failed");    ABSL_RAW_CHECK(cxt->g0 >= 3, "TestTime failed");    start = absl::Now();    if (use_cv) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));    } else {      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),                     "TestTime failed");    }    elapsed = absl::Now() - start;    ABSL_RAW_CHECK(        absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),        "TestTime failed");    if (use_cv) {      cxt->cv.SignalAll();    }    start = absl::Now();    if (use_cv) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));    } else {      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),                     "TestTime failed");    }    elapsed = absl::Now() - start;    ABSL_RAW_CHECK(absl::Seconds(0.9) <= elapsed &&                   elapsed <= absl::Seconds(2.0), "TestTime failed");    ABSL_RAW_CHECK(cxt->g0 == cxt->threads, "TestTime failed");  } else if (c == 1) {    absl::MutexLock l(&cxt->mu);    const absl::Time start = absl::Now();    if (use_cv) {      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500));    } else {      ABSL_RAW_CHECK(          !cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500)),          "TestTime failed");    }    const absl::Duration elapsed = absl::Now() - start;    ABSL_RAW_CHECK(        absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9),        "TestTime failed");    cxt->g0++;  } else if (c == 2) {    absl::MutexLock l(&cxt->mu);    if (use_cv) {      while (cxt->g0 < 2) {        cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));      }    } else {      ABSL_RAW_CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100)),                     "TestTime failed");    }    cxt->g0++;  } else {    absl::MutexLock l(&cxt->mu);    if (use_cv) {      while (cxt->g0 < 2) {        cxt->cv.Wait(&cxt->mu);      }    } else {      cxt->mu.Await(g0ge2);    }    cxt->g0++;  }}static void TestMuTime(TestContext *cxt, int c) { TestTime(cxt, c, false); }static void TestCVTime(TestContext *cxt, int c) { TestTime(cxt, c, true); }static void EndTest(int *c0, int *c1, absl::Mutex *mu, absl::CondVar *cv,                    const std::function<void(int)>& cb) {  mu->Lock();  int c = (*c0)++;  mu->Unlock();  cb(c);  absl::MutexLock l(mu);  (*c1)++;  cv->Signal();}// Code common to RunTest() and RunTestWithInvariantDebugging().static int RunTestCommon(TestContext *cxt, void (*test)(TestContext *cxt, int),                         int threads, int iterations, int operations) {  absl::Mutex mu2;  absl::CondVar cv2;  int c0 = 0;  int c1 = 0;  cxt->g0 = 0;  cxt->g1 = 0;  cxt->iterations = iterations;  cxt->threads = threads;  absl::synchronization_internal::ThreadPool tp(threads);  for (int i = 0; i != threads; i++) {    tp.Schedule(std::bind(&EndTest, &c0, &c1, &mu2, &cv2,                          std::function<void(int)>(                              std::bind(test, cxt, std::placeholders::_1))));  }  mu2.Lock();  while (c1 != threads) {    cv2.Wait(&mu2);  }  mu2.Unlock();  return cxt->g0;}// Basis for the parameterized tests configured below.static int RunTest(void (*test)(TestContext *cxt, int), int threads,                   int iterations, int operations) {  TestContext cxt;  return RunTestCommon(&cxt, test, threads, iterations, operations);}// Like RunTest(), but sets an invariant on the tested Mutex and// verifies that the invariant check happened. The invariant function// will be passed the TestContext* as its arg and must call// SetInvariantChecked(true);#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)static int RunTestWithInvariantDebugging(void (*test)(TestContext *cxt, int),                                         int threads, int iterations,                                         int operations,                                         void (*invariant)(void *)) {  absl::EnableMutexInvariantDebugging(true);  SetInvariantChecked(false);  TestContext cxt;  cxt.mu.EnableInvariantDebugging(invariant, &cxt);  int ret = RunTestCommon(&cxt, test, threads, iterations, operations);  ABSL_RAW_CHECK(GetInvariantChecked(), "Invariant not checked");  absl::EnableMutexInvariantDebugging(false);  // Restore.  return ret;}#endif// --------------------------------------------------------// Test for fix of bug in TryRemove()struct TimeoutBugStruct {  absl::Mutex mu;  bool a;  int a_waiter_count;};static void WaitForA(TimeoutBugStruct *x) {  x->mu.LockWhen(absl::Condition(&x->a));  x->a_waiter_count--;  x->mu.Unlock();}static bool NoAWaiters(TimeoutBugStruct *x) { return x->a_waiter_count == 0; }// Test that a CondVar.Wait(&mutex) can un-block a call to mutex.Await() in// another thread.TEST(Mutex, CondVarWaitSignalsAwait) {  // Use a struct so the lock annotations apply.  struct {    absl::Mutex barrier_mu;    bool barrier GUARDED_BY(barrier_mu) = false;    absl::Mutex release_mu;    bool release GUARDED_BY(release_mu) = false;    absl::CondVar released_cv;  } state;  auto pool = CreateDefaultPool();  // Thread A.  Sets barrier, waits for release using Mutex::Await, then  // signals released_cv.  pool->Schedule([&state] {    state.release_mu.Lock();    state.barrier_mu.Lock();    state.barrier = true;    state.barrier_mu.Unlock();    state.release_mu.Await(absl::Condition(&state.release));    state.released_cv.Signal();    state.release_mu.Unlock();  });  state.barrier_mu.LockWhen(absl::Condition(&state.barrier));  state.barrier_mu.Unlock();  state.release_mu.Lock();  // Thread A is now blocked on release by way of Mutex::Await().  // Set release.  Calling released_cv.Wait() should un-block thread A,  // which will signal released_cv.  If not, the test will hang.  state.release = true;  state.released_cv.Wait(&state.release_mu);  state.release_mu.Unlock();}// Test that a CondVar.WaitWithTimeout(&mutex) can un-block a call to// mutex.Await() in another thread.TEST(Mutex, CondVarWaitWithTimeoutSignalsAwait) {  // Use a struct so the lock annotations apply.  struct {    absl::Mutex barrier_mu;    bool barrier GUARDED_BY(barrier_mu) = false;    absl::Mutex release_mu;    bool release GUARDED_BY(release_mu) = false;    absl::CondVar released_cv;  } state;  auto pool = CreateDefaultPool();  // Thread A.  Sets barrier, waits for release using Mutex::Await, then  // signals released_cv.  pool->Schedule([&state] {    state.release_mu.Lock();    state.barrier_mu.Lock();    state.barrier = true;    state.barrier_mu.Unlock();    state.release_mu.Await(absl::Condition(&state.release));    state.released_cv.Signal();    state.release_mu.Unlock();  });  state.barrier_mu.LockWhen(absl::Condition(&state.barrier));  state.barrier_mu.Unlock();  state.release_mu.Lock();  // Thread A is now blocked on release by way of Mutex::Await().  // Set release.  Calling released_cv.Wait() should un-block thread A,  // which will signal released_cv.  If not, the test will hang.  state.release = true;  EXPECT_TRUE(      !state.released_cv.WaitWithTimeout(&state.release_mu, absl::Seconds(10)))      << "; Unrecoverable test failure: CondVar::WaitWithTimeout did not "         "unblock the absl::Mutex::Await call in another thread.";  state.release_mu.Unlock();}// Test for regression of a bug in loop of TryRemove()TEST(Mutex, MutexTimeoutBug) {  auto tp = CreateDefaultPool();  TimeoutBugStruct x;  x.a = false;  x.a_waiter_count = 2;  tp->Schedule(std::bind(&WaitForA, &x));  tp->Schedule(std::bind(&WaitForA, &x));  absl::SleepFor(absl::Seconds(1));  // Allow first two threads to hang.  // The skip field of the second will point to the first because there are  // only two.  // Now cause a thread waiting on an always-false to time out  // This would deadlock when the bug was present.  bool always_false = false;  x.mu.LockWhenWithTimeout(absl::Condition(&always_false),                           absl::Milliseconds(500));  // if we get here, the bug is not present.   Cleanup the state.  x.a = true;                                    // wakeup the two waiters on A  x.mu.Await(absl::Condition(&NoAWaiters, &x));  // wait for them to exit  x.mu.Unlock();}struct CondVarWaitDeadlock : testing::TestWithParam<int> {  absl::Mutex mu;  absl::CondVar cv;  bool cond1 = false;  bool cond2 = false;  bool read_lock1;  bool read_lock2;  bool signal_unlocked;  CondVarWaitDeadlock() {    read_lock1 = GetParam() & (1 << 0);    read_lock2 = GetParam() & (1 << 1);    signal_unlocked = GetParam() & (1 << 2);  }  void Waiter1() {    if (read_lock1) {      mu.ReaderLock();      while (!cond1) {        cv.Wait(&mu);      }      mu.ReaderUnlock();    } else {      mu.Lock();      while (!cond1) {        cv.Wait(&mu);      }      mu.Unlock();    }  }  void Waiter2() {    if (read_lock2) {      mu.ReaderLockWhen(absl::Condition(&cond2));      mu.ReaderUnlock();    } else {      mu.LockWhen(absl::Condition(&cond2));      mu.Unlock();    }  }};// Test for a deadlock bug in Mutex::Fer().// The sequence of events that lead to the deadlock is:// 1. waiter1 blocks on cv in read mode (mu bits = 0).// 2. waiter2 blocks on mu in either mode (mu bits = kMuWait).// 3. main thread locks mu, sets cond1, unlocks mu (mu bits = kMuWait).// 4. main thread signals on cv and this eventually calls Mutex::Fer().// Currently Fer wakes waiter1 since mu bits = kMuWait (mutex is unlocked).// Before the bug fix Fer neither woke waiter1 nor queued it on mutex,// which resulted in deadlock.TEST_P(CondVarWaitDeadlock, Test) {  auto waiter1 = CreatePool(1);  auto waiter2 = CreatePool(1);  waiter1->Schedule([this] { this->Waiter1(); });  waiter2->Schedule([this] { this->Waiter2(); });  // Wait while threads block (best-effort is fine).  absl::SleepFor(absl::Milliseconds(100));  // Wake condwaiter.  mu.Lock();  cond1 = true;  if (signal_unlocked) {    mu.Unlock();    cv.Signal();  } else {    cv.Signal();    mu.Unlock();  }  waiter1.reset();  // "join" waiter1  // Wake waiter.  mu.Lock();  cond2 = true;  mu.Unlock();  waiter2.reset();  // "join" waiter2}INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,                        ::testing::Range(0, 8),                        ::testing::PrintToStringParamName());// --------------------------------------------------------// Test for fix of bug in DequeueAllWakeable()// Bug was that if there was more than one waiting reader// and all should be woken, the most recently blocked one// would not be.struct DequeueAllWakeableBugStruct {  absl::Mutex mu;  absl::Mutex mu2;       // protects all fields below  int unfinished_count;  // count of unfinished readers; under mu2  bool done1;            // unfinished_count == 0; under mu2  int finished_count;    // count of finished readers, under mu2  bool done2;            // finished_count == 0; under mu2};// Test for regression of a bug in loop of DequeueAllWakeable()static void AcquireAsReader(DequeueAllWakeableBugStruct *x) {  x->mu.ReaderLock();  x->mu2.Lock();  x->unfinished_count--;  x->done1 = (x->unfinished_count == 0);  x->mu2.Unlock();  // make sure that both readers acquired mu before we release it.  absl::SleepFor(absl::Seconds(2));  x->mu.ReaderUnlock();  x->mu2.Lock();  x->finished_count--;  x->done2 = (x->finished_count == 0);  x->mu2.Unlock();}// Test for regression of a bug in loop of DequeueAllWakeable()TEST(Mutex, MutexReaderWakeupBug) {  auto tp = CreateDefaultPool();  DequeueAllWakeableBugStruct x;  x.unfinished_count = 2;  x.done1 = false;  x.finished_count = 2;  x.done2 = false;  x.mu.Lock();  // acquire mu exclusively  // queue two thread that will block on reader locks on x.mu  tp->Schedule(std::bind(&AcquireAsReader, &x));  tp->Schedule(std::bind(&AcquireAsReader, &x));  absl::SleepFor(absl::Seconds(1));  // give time for reader threads to block  x.mu.Unlock();                     // wake them up  // both readers should finish promptly  EXPECT_TRUE(      x.mu2.LockWhenWithTimeout(absl::Condition(&x.done1), absl::Seconds(10)));  x.mu2.Unlock();  EXPECT_TRUE(      x.mu2.LockWhenWithTimeout(absl::Condition(&x.done2), absl::Seconds(10)));  x.mu2.Unlock();}struct LockWhenTestStruct {  absl::Mutex mu1;  bool cond = false;  absl::Mutex mu2;  bool waiting = false;};static bool LockWhenTestIsCond(LockWhenTestStruct* s) {  s->mu2.Lock();  s->waiting = true;  s->mu2.Unlock();  return s->cond;}static void LockWhenTestWaitForIsCond(LockWhenTestStruct* s) {  s->mu1.LockWhen(absl::Condition(&LockWhenTestIsCond, s));  s->mu1.Unlock();}TEST(Mutex, LockWhen) {  LockWhenTestStruct s;  std::thread t(LockWhenTestWaitForIsCond, &s);  s.mu2.LockWhen(absl::Condition(&s.waiting));  s.mu2.Unlock();  s.mu1.Lock();  s.cond = true;  s.mu1.Unlock();  t.join();}// --------------------------------------------------------// The following test requires Mutex::ReaderLock to be a real shared// lock, which is not the case in all builds.#if !defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)// Test for fix of bug in UnlockSlow() that incorrectly decremented the reader// count when putting a thread to sleep waiting for a false condition when the// lock was not held.// For this bug to strike, we make a thread wait on a free mutex with no// waiters by causing its wakeup condition to be false.   Then the// next two acquirers must be readers.   The bug causes the lock// to be released when one reader unlocks, rather than both.struct ReaderDecrementBugStruct {  bool cond;  // to delay first thread (under mu)  int done;   // reference count (under mu)  absl::Mutex mu;  bool waiting_on_cond;   // under mu2  bool have_reader_lock;  // under mu2  bool complete;          // under mu2  absl::Mutex mu2;        // > mu};// L >= mu, L < mu_waiting_on_condstatic bool IsCond(void *v) {  ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);  x->mu2.Lock();  x->waiting_on_cond = true;  x->mu2.Unlock();  return x->cond;}// L >= mustatic bool AllDone(void *v) {  ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);  return x->done == 0;}// L={}static void WaitForCond(ReaderDecrementBugStruct *x) {  absl::Mutex dummy;  absl::MutexLock l(&dummy);  x->mu.LockWhen(absl::Condition(&IsCond, x));  x->done--;  x->mu.Unlock();}// L={}static void GetReadLock(ReaderDecrementBugStruct *x) {  x->mu.ReaderLock();  x->mu2.Lock();  x->have_reader_lock = true;  x->mu2.Await(absl::Condition(&x->complete));  x->mu2.Unlock();  x->mu.ReaderUnlock();  x->mu.Lock();  x->done--;  x->mu.Unlock();}// Test for reader counter being decremented incorrectly by waiter// with false condition.TEST(Mutex, MutexReaderDecrementBug) NO_THREAD_SAFETY_ANALYSIS {  ReaderDecrementBugStruct x;  x.cond = false;  x.waiting_on_cond = false;  x.have_reader_lock = false;  x.complete = false;  x.done = 2;  // initial ref count  // Run WaitForCond() and wait for it to sleep  std::thread thread1(WaitForCond, &x);  x.mu2.LockWhen(absl::Condition(&x.waiting_on_cond));  x.mu2.Unlock();  // Run GetReadLock(), and wait for it to get the read lock  std::thread thread2(GetReadLock, &x);  x.mu2.LockWhen(absl::Condition(&x.have_reader_lock));  x.mu2.Unlock();  // Get the reader lock ourselves, and release it.  x.mu.ReaderLock();  x.mu.ReaderUnlock();  // The lock should be held in read mode by GetReadLock().  // If we have the bug, the lock will be free.  x.mu.AssertReaderHeld();  // Wake up all the threads.  x.mu2.Lock();  x.complete = true;  x.mu2.Unlock();  // TODO(delesley): turn on analysis once lock upgrading is supported.  // (This call upgrades the lock from shared to exclusive.)  x.mu.Lock();  x.cond = true;  x.mu.Await(absl::Condition(&AllDone, &x));  x.mu.Unlock();  thread1.join();  thread2.join();}#endif  // !ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE// Test that we correctly handle the situation when a lock is// held and then destroyed (w/o unlocking).TEST(Mutex, LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {  for (int i = 0; i != 10; i++) {    // Create, lock and destroy 10 locks.    const int kNumLocks = 10;    auto mu = absl::make_unique<absl::Mutex[]>(kNumLocks);    for (int j = 0; j != kNumLocks; j++) {      if ((j % 2) == 0) {        mu[j].WriterLock();      } else {        mu[j].ReaderLock();      }    }  }}// --------------------------------------------------------// Test for bug with pattern of readers using a condvar.  The bug was that if a// reader went to sleep on a condition variable while one or more other readers// held the lock, but there were no waiters, the reader count (held in the// mutex word) would be lost.  (This is because Enqueue() had at one time// always placed the thread on the Mutex queue.  Later (CL 4075610), to// tolerate re-entry into Mutex from a Condition predicate, Enqueue() was// changed so that it could also place a thread on a condition-variable.  This// introduced the case where Enqueue() returned with an empty queue, and this// case was handled incorrectly in one place.)static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv,                                     int *running) {  std::random_device dev;  std::mt19937 gen(dev());  std::uniform_int_distribution<int> random_millis(0, 15);  mu->ReaderLock();  while (*running == 3) {    absl::SleepFor(absl::Milliseconds(random_millis(gen)));    cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen)));  }  mu->ReaderUnlock();  mu->Lock();  (*running)--;  mu->Unlock();}struct True {  template <class... Args>  bool operator()(Args...) const {    return true;  }};struct DerivedTrue : True {};TEST(Mutex, FunctorCondition) {  {  // Variadic    True f;    EXPECT_TRUE(absl::Condition(&f).Eval());  }  {  // Inherited    DerivedTrue g;    EXPECT_TRUE(absl::Condition(&g).Eval());  }  {  // lambda    int value = 3;    auto is_zero = [&value] { return value == 0; };    absl::Condition c(&is_zero);    EXPECT_FALSE(c.Eval());    value = 0;    EXPECT_TRUE(c.Eval());  }  {  // bind    int value = 0;    auto is_positive = std::bind(std::less<int>(), 0, std::cref(value));    absl::Condition c(&is_positive);    EXPECT_FALSE(c.Eval());    value = 1;    EXPECT_TRUE(c.Eval());  }  {  // std::function    int value = 3;    std::function<bool()> is_zero = [&value] { return value == 0; };    absl::Condition c(&is_zero);    EXPECT_FALSE(c.Eval());    value = 0;    EXPECT_TRUE(c.Eval());  }}static bool IntIsZero(int *x) { return *x == 0; }// Test for reader waiting condition variable when there are other readers// but no waiters.TEST(Mutex, TestReaderOnCondVar) {  auto tp = CreateDefaultPool();  absl::Mutex mu;  absl::CondVar cv;  int running = 3;  tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));  tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));  absl::SleepFor(absl::Seconds(2));  mu.Lock();  running--;  mu.Await(absl::Condition(&IntIsZero, &running));  mu.Unlock();}// --------------------------------------------------------struct AcquireFromConditionStruct {  absl::Mutex mu0;   // protects value, done  int value;         // times condition function is called; under mu0,  bool done;         // done with test?  under mu0  absl::Mutex mu1;   // used to attempt to mess up state of mu0  absl::CondVar cv;  // so the condition function can be invoked from                     // CondVar::Wait().};static bool ConditionWithAcquire(AcquireFromConditionStruct *x) {  x->value++;  // count times this function is called  if (x->value == 2 || x->value == 3) {    // On the second and third invocation of this function, sleep for 100ms,    // but with the side-effect of altering the state of a Mutex other than    // than one for which this is a condition.  The spec now explicitly allows    // this side effect; previously it did not.  it was illegal.    bool always_false = false;    x->mu1.LockWhenWithTimeout(absl::Condition(&always_false),                               absl::Milliseconds(100));    x->mu1.Unlock();  }  ABSL_RAW_CHECK(x->value < 4, "should not be invoked a fourth time");  // We arrange for the condition to return true on only the 2nd and 3rd calls.  return x->value == 2 || x->value == 3;}static void WaitForCond2(AcquireFromConditionStruct *x) {  // wait for cond0 to become true  x->mu0.LockWhen(absl::Condition(&ConditionWithAcquire, x));  x->done = true;  x->mu0.Unlock();}// Test for Condition whose function acquires other MutexesTEST(Mutex, AcquireFromCondition) {  auto tp = CreateDefaultPool();  AcquireFromConditionStruct x;  x.value = 0;  x.done = false;  tp->Schedule(      std::bind(&WaitForCond2, &x));  // run WaitForCond2() in a thread T  // T will hang because the first invocation of ConditionWithAcquire() will  // return false.  absl::SleepFor(absl::Milliseconds(500));  // allow T time to hang  x.mu0.Lock();  x.cv.WaitWithTimeout(&x.mu0, absl::Milliseconds(500));  // wake T  // T will be woken because the Wait() will call ConditionWithAcquire()  // for the second time, and it will return true.  x.mu0.Unlock();  // T will then acquire the lock and recheck its own condition.  // It will find the condition true, as this is the third invocation,  // but the use of another Mutex by the calling function will  // cause the old mutex implementation to think that the outer  // LockWhen() has timed out because the inner LockWhenWithTimeout() did.  // T will then check the condition a fourth time because it finds a  // timeout occurred.  This should not happen in the new  // implementation that allows the Condition function to use Mutexes.  // It should also succeed, even though the Condition function  // is being invoked from CondVar::Wait, and thus this thread  // is conceptually waiting both on the condition variable, and on mu2.  x.mu0.LockWhen(absl::Condition(&x.done));  x.mu0.Unlock();}// The deadlock detector is not part of non-prod builds, so do not test it.#if !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)TEST(Mutex, DeadlockDetector) {  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);  // check that we can call ForgetDeadlockInfo() on a lock with the lock held  absl::Mutex m1;  absl::Mutex m2;  absl::Mutex m3;  absl::Mutex m4;  m1.Lock();  // m1 gets ID1  m2.Lock();  // m2 gets ID2  m3.Lock();  // m3 gets ID3  m3.Unlock();  m2.Unlock();  // m1 still held  m1.ForgetDeadlockInfo();  // m1 loses ID  m2.Lock();                // m2 gets ID2  m3.Lock();                // m3 gets ID3  m4.Lock();                // m4 gets ID4  m3.Unlock();  m2.Unlock();  m4.Unlock();  m1.Unlock();}// Bazel has a test "warning" file that programs can write to if the// test should pass with a warning.  This class disables the warning// file until it goes out of scope.class ScopedDisableBazelTestWarnings { public:  ScopedDisableBazelTestWarnings() {#ifdef WIN32    char file[MAX_PATH];    if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) {      warnings_output_file_ = file;      SetEnvironmentVariable(kVarName, nullptr);    }#else    const char *file = getenv(kVarName);    if (file != nullptr) {      warnings_output_file_ = file;      unsetenv(kVarName);    }#endif  }  ~ScopedDisableBazelTestWarnings() {    if (!warnings_output_file_.empty()) {#ifdef WIN32      SetEnvironmentVariable(kVarName, warnings_output_file_.c_str());#else      setenv(kVarName, warnings_output_file_.c_str(), 0);#endif    }  } private:  static const char kVarName[];  std::string warnings_output_file_;};const char ScopedDisableBazelTestWarnings::kVarName[] =    "TEST_WARNINGS_OUTPUT_FILE";TEST(Mutex, DeadlockDetectorBazelWarning) {  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport);  // Cause deadlock detection to detect something, if it's  // compiled in and enabled.  But turn off the bazel warning.  ScopedDisableBazelTestWarnings disable_bazel_test_warnings;  absl::Mutex mu0;  absl::Mutex mu1;  bool got_mu0 = mu0.TryLock();  mu1.Lock();  // acquire mu1 while holding mu0  if (got_mu0) {    mu0.Unlock();  }  if (mu0.TryLock()) {  // try lock shouldn't cause deadlock detector to fire    mu0.Unlock();  }  mu0.Lock();  // acquire mu0 while holding mu1; should get one deadlock               // report here  mu0.Unlock();  mu1.Unlock();  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);}// This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the// annotation-based static thread-safety analysis is not currently// predicate-aware and cannot tell if the two for-loops that acquire and// release the locks have the same predicates.TEST(Mutex, DeadlockDetectorStessTest) NO_THREAD_SAFETY_ANALYSIS {  // Stress test: Here we create a large number of locks and use all of them.  // If a deadlock detector keeps a full graph of lock acquisition order,  // it will likely be too slow for this test to pass.  const int n_locks = 1 << 17;  auto array_of_locks = absl::make_unique<absl::Mutex[]>(n_locks);  for (int i = 0; i < n_locks; i++) {    int end = std::min(n_locks, i + 5);    // acquire and then release locks i, i+1, ..., i+4    for (int j = i; j < end; j++) {      array_of_locks[j].Lock();    }    for (int j = i; j < end; j++) {      array_of_locks[j].Unlock();    }  }}TEST(Mutex, DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {  // Test a scenario where a cached deadlock graph node id in the  // list of held locks is not invalidated when the corresponding  // mutex is deleted.  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);  // Mutex that will be destroyed while being held  absl::Mutex *a = new absl::Mutex;  // Other mutexes needed by test  absl::Mutex b, c;  // Hold mutex.  a->Lock();  // Force deadlock id assignment by acquiring another lock.  b.Lock();  b.Unlock();  // Delete the mutex. The Mutex destructor tries to remove held locks,  // but the attempt isn't foolproof.  It can fail if:  //   (a) Deadlock detection is currently disabled.  //   (b) The destruction is from another thread.  // We exploit (a) by temporarily disabling deadlock detection.  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore);  delete a;  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);  // Now acquire another lock which will force a deadlock id assignment.  // We should end up getting assigned the same deadlock id that was  // freed up when "a" was deleted, which will cause a spurious deadlock  // report if the held lock entry for "a" was not invalidated.  c.Lock();  c.Unlock();}#endif  // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)// --------------------------------------------------------// Test for timeouts/deadlines on condition waits that are specified using// absl::Duration and absl::Time.  For each waiting function we test with// a timeout/deadline that has already expired/passed, one that is infinite// and so never expires/passes, and one that will expire/pass in the near// future.// Encapsulate a Mutex-protected bool with its associated Condition/CondVar.class Cond { public:  explicit Cond(bool use_deadline) : use_deadline_(use_deadline), c_(&b_) {}  void Set(bool v) {    absl::MutexLock lock(&mu_);    b_ = v;  }  bool AwaitWithTimeout(absl::Duration timeout) {    absl::MutexLock lock(&mu_);    return use_deadline_ ? mu_.AwaitWithDeadline(c_, absl::Now() + timeout)                         : mu_.AwaitWithTimeout(c_, timeout);  }  bool LockWhenWithTimeout(absl::Duration timeout) {    bool b = use_deadline_ ? mu_.LockWhenWithDeadline(c_, absl::Now() + timeout)                           : mu_.LockWhenWithTimeout(c_, timeout);    mu_.Unlock();    return b;  }  bool ReaderLockWhenWithTimeout(absl::Duration timeout) {    bool b = use_deadline_                 ? mu_.ReaderLockWhenWithDeadline(c_, absl::Now() + timeout)                 : mu_.ReaderLockWhenWithTimeout(c_, timeout);    mu_.ReaderUnlock();    return b;  }  void Await() {    absl::MutexLock lock(&mu_);    mu_.Await(c_);  }  void Signal(bool v) {    absl::MutexLock lock(&mu_);    b_ = v;    cv_.Signal();  }  bool WaitWithTimeout(absl::Duration timeout) {    absl::MutexLock lock(&mu_);    absl::Time deadline = absl::Now() + timeout;    if (use_deadline_) {      while (!b_ && !cv_.WaitWithDeadline(&mu_, deadline)) {      }    } else {      while (!b_ && !cv_.WaitWithTimeout(&mu_, timeout)) {        timeout = deadline - absl::Now();  // recompute timeout      }    }    return b_;  }  void Wait() {    absl::MutexLock lock(&mu_);    while (!b_) cv_.Wait(&mu_);  } private:  const bool use_deadline_;  bool b_;  absl::Condition c_;  absl::CondVar cv_;  absl::Mutex mu_;};class OperationTimer { public:  OperationTimer() : start_(absl::Now()) {}  absl::Duration Get() const { return absl::Now() - start_; } private:  const absl::Time start_;};static void CheckResults(bool exp_result, bool act_result,                         absl::Duration exp_duration,                         absl::Duration act_duration) {  ABSL_RAW_CHECK(exp_result == act_result, "CheckResults failed");  // Allow for some worse-case scheduling delay and clock skew.  if ((exp_duration - absl::Milliseconds(40) > act_duration) ||      (exp_duration + absl::Milliseconds(150) < act_duration)) {    ABSL_RAW_LOG(FATAL, "CheckResults failed: operation took %s, expected %s",                 absl::FormatDuration(act_duration).c_str(),                 absl::FormatDuration(exp_duration).c_str());  }}static void TestAwaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,                             absl::Duration exp_duration) {  OperationTimer t;  bool act_result = cp->AwaitWithTimeout(timeout);  CheckResults(exp_result, act_result, exp_duration, t.Get());}static void TestLockWhenTimeout(Cond *cp, absl::Duration timeout,                                bool exp_result, absl::Duration exp_duration) {  OperationTimer t;  bool act_result = cp->LockWhenWithTimeout(timeout);  CheckResults(exp_result, act_result, exp_duration, t.Get());}static void TestReaderLockWhenTimeout(Cond *cp, absl::Duration timeout,                                      bool exp_result,                                      absl::Duration exp_duration) {  OperationTimer t;  bool act_result = cp->ReaderLockWhenWithTimeout(timeout);  CheckResults(exp_result, act_result, exp_duration, t.Get());}static void TestWaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,                            absl::Duration exp_duration) {  OperationTimer t;  bool act_result = cp->WaitWithTimeout(timeout);  CheckResults(exp_result, act_result, exp_duration, t.Get());}// Tests with a negative timeout (deadline in the past), which should// immediately return the current state of the condition.static void TestNegativeTimeouts(absl::synchronization_internal::ThreadPool *tp,                                 Cond *cp) {  const absl::Duration negative = -absl::InfiniteDuration();  const absl::Duration immediate = absl::ZeroDuration();  // The condition is already true:  cp->Set(true);  TestAwaitTimeout(cp, negative, true, immediate);  TestLockWhenTimeout(cp, negative, true, immediate);  TestReaderLockWhenTimeout(cp, negative, true, immediate);  TestWaitTimeout(cp, negative, true, immediate);  // The condition becomes true, but the timeout has already expired:  const absl::Duration delay = absl::Milliseconds(200);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay);  TestAwaitTimeout(cp, negative, false, immediate);  TestLockWhenTimeout(cp, negative, false, immediate);  TestReaderLockWhenTimeout(cp, negative, false, immediate);  cp->Await();  // wait for the scheduled Set() to complete  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);  TestWaitTimeout(cp, negative, false, immediate);  cp->Wait();  // wait for the scheduled Signal() to complete  // The condition never becomes true:  cp->Set(false);  TestAwaitTimeout(cp, negative, false, immediate);  TestLockWhenTimeout(cp, negative, false, immediate);  TestReaderLockWhenTimeout(cp, negative, false, immediate);  TestWaitTimeout(cp, negative, false, immediate);}// Tests with an infinite timeout (deadline in the infinite future), which// should only return when the condition becomes true.static void TestInfiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,                                 Cond *cp) {  const absl::Duration infinite = absl::InfiniteDuration();  const absl::Duration immediate = absl::ZeroDuration();  // The condition is already true:  cp->Set(true);  TestAwaitTimeout(cp, infinite, true, immediate);  TestLockWhenTimeout(cp, infinite, true, immediate);  TestReaderLockWhenTimeout(cp, infinite, true, immediate);  TestWaitTimeout(cp, infinite, true, immediate);  // The condition becomes true before the (infinite) expiry:  const absl::Duration delay = absl::Milliseconds(200);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);  TestAwaitTimeout(cp, infinite, true, delay);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);  TestLockWhenTimeout(cp, infinite, true, delay);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);  TestReaderLockWhenTimeout(cp, infinite, true, delay);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);  TestWaitTimeout(cp, infinite, true, delay);}// Tests with a (small) finite timeout (deadline soon), with the condition// becoming true both before and after its expiry.static void TestFiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,                               Cond *cp) {  const absl::Duration finite = absl::Milliseconds(400);  const absl::Duration immediate = absl::ZeroDuration();  // The condition is already true:  cp->Set(true);  TestAwaitTimeout(cp, finite, true, immediate);  TestLockWhenTimeout(cp, finite, true, immediate);  TestReaderLockWhenTimeout(cp, finite, true, immediate);  TestWaitTimeout(cp, finite, true, immediate);  // The condition becomes true before the expiry:  const absl::Duration delay1 = finite / 2;  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);  TestAwaitTimeout(cp, finite, true, delay1);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);  TestLockWhenTimeout(cp, finite, true, delay1);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);  TestReaderLockWhenTimeout(cp, finite, true, delay1);  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay1);  TestWaitTimeout(cp, finite, true, delay1);  // The condition becomes true, but the timeout has already expired:  const absl::Duration delay2 = finite * 2;  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay2);  TestAwaitTimeout(cp, finite, false, finite);  TestLockWhenTimeout(cp, finite, false, finite);  TestReaderLockWhenTimeout(cp, finite, false, finite);  cp->Await();  // wait for the scheduled Set() to complete  cp->Set(false);  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay2);  TestWaitTimeout(cp, finite, false, finite);  cp->Wait();  // wait for the scheduled Signal() to complete  // The condition never becomes true:  cp->Set(false);  TestAwaitTimeout(cp, finite, false, finite);  TestLockWhenTimeout(cp, finite, false, finite);  TestReaderLockWhenTimeout(cp, finite, false, finite);  TestWaitTimeout(cp, finite, false, finite);}TEST(Mutex, Timeouts) {  auto tp = CreateDefaultPool();  for (bool use_deadline : {false, true}) {    Cond cond(use_deadline);    TestNegativeTimeouts(tp.get(), &cond);    TestInfiniteTimeouts(tp.get(), &cond);    TestFiniteTimeouts(tp.get(), &cond);  }}TEST(Mutex, Logging) {  // Allow user to look at logging output  absl::Mutex logged_mutex;  logged_mutex.EnableDebugLog("fido_mutex");  absl::CondVar logged_cv;  logged_cv.EnableDebugLog("rover_cv");  logged_mutex.Lock();  logged_cv.WaitWithTimeout(&logged_mutex, absl::Milliseconds(20));  logged_mutex.Unlock();  logged_mutex.ReaderLock();  logged_mutex.ReaderUnlock();  logged_mutex.Lock();  logged_mutex.Unlock();  logged_cv.Signal();  logged_cv.SignalAll();}// --------------------------------------------------------// Generate the vector of thread counts for tests parameterized on thread count.static std::vector<int> AllThreadCountValues() {  if (kExtendedTest) {    return {2, 4, 8, 10, 16, 20, 24, 30, 32};  }  return {2, 4, 10};}// A test fixture parameterized by thread count.class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {};// Instantiate the above with AllThreadCountOptions().INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest,                        ::testing::ValuesIn(AllThreadCountValues()),                        ::testing::PrintToStringParamName());// Reduces iterations by some factor for slow platforms// (determined empirically).static int ScaleIterations(int x) {  // ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE is set in the implementation  // of Mutex that uses either std::mutex or pthread_mutex_t. Use  // these as keys to determine the slow implementation.#if defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)  return x / 10;#else  return x;#endif}TEST_P(MutexVariableThreadCountTest, Mutex) {  int threads = GetParam();  int iterations = ScaleIterations(10000000) / threads;  int operations = threads * iterations;  EXPECT_EQ(RunTest(&TestMu, threads, iterations, operations), operations);#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)  iterations = std::min(iterations, 10);  operations = threads * iterations;  EXPECT_EQ(RunTestWithInvariantDebugging(&TestMu, threads, iterations,                                          operations, CheckSumG0G1),            operations);#endif}TEST_P(MutexVariableThreadCountTest, Try) {  int threads = GetParam();  int iterations = 1000000 / threads;  int operations = iterations * threads;  EXPECT_EQ(RunTest(&TestTry, threads, iterations, operations), operations);#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)  iterations = std::min(iterations, 10);  operations = threads * iterations;  EXPECT_EQ(RunTestWithInvariantDebugging(&TestTry, threads, iterations,                                          operations, CheckSumG0G1),            operations);#endif}TEST_P(MutexVariableThreadCountTest, R20ms) {  int threads = GetParam();  int iterations = 100;  int operations = iterations * threads;  EXPECT_EQ(RunTest(&TestR20ms, threads, iterations, operations), 0);}TEST_P(MutexVariableThreadCountTest, RW) {  int threads = GetParam();  int iterations = ScaleIterations(20000000) / threads;  int operations = iterations * threads;  EXPECT_EQ(RunTest(&TestRW, threads, iterations, operations), operations / 2);#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)  iterations = std::min(iterations, 10);  operations = threads * iterations;  EXPECT_EQ(RunTestWithInvariantDebugging(&TestRW, threads, iterations,                                          operations, CheckSumG0G1),            operations / 2);#endif}TEST_P(MutexVariableThreadCountTest, Await) {  int threads = GetParam();  int iterations = ScaleIterations(500000);  int operations = iterations;  EXPECT_EQ(RunTest(&TestAwait, threads, iterations, operations), operations);}TEST_P(MutexVariableThreadCountTest, SignalAll) {  int threads = GetParam();  int iterations = 200000 / threads;  int operations = iterations;  EXPECT_EQ(RunTest(&TestSignalAll, threads, iterations, operations),            operations);}TEST(Mutex, Signal) {  int threads = 2;  // TestSignal must use two threads  int iterations = 200000;  int operations = iterations;  EXPECT_EQ(RunTest(&TestSignal, threads, iterations, operations), operations);}TEST(Mutex, Timed) {  int threads = 10;  // Use a fixed thread count of 10  int iterations = 1000;  int operations = iterations;  EXPECT_EQ(RunTest(&TestCVTimeout, threads, iterations, operations),            operations);}TEST(Mutex, CVTime) {  int threads = 10;  // Use a fixed thread count of 10  int iterations = 1;  EXPECT_EQ(RunTest(&TestCVTime, threads, iterations, 1),            threads * iterations);}TEST(Mutex, MuTime) {  int threads = 10;  // Use a fixed thread count of 10  int iterations = 1;  EXPECT_EQ(RunTest(&TestMuTime, threads, iterations, 1), threads * iterations);}}  // namespace
 |