15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "mojo/public/cpp/utility/mutex.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <stdlib.h>  // For |rand()|.
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <time.h>  // For |nanosleep()| (defined by POSIX).
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "mojo/public/cpp/system/macros.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "mojo/public/cpp/utility/thread.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace mojo {
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(MutexTest, TrivialSingleThreaded) {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Mutex mutex;
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.Lock();
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.AssertHeld();
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.Unlock();
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(mutex.TryLock());
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.AssertHeld();
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.Unlock();
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MutexLock lock(&mutex);
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.AssertHeld();
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(mutex.TryLock());
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.Unlock();
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class Fiddler {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum Type { kTypeLock, kTypeTry };
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Fiddler(size_t times_to_lock,
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Type type,
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          bool should_sleep,
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Mutex* mutex,
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          int* shared_value)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : times_to_lock_(times_to_lock),
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        type_(type),
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        should_sleep_(should_sleep),
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        mutex_(mutex),
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shared_value_(shared_value) {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~Fiddler() {
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Fiddle() {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (size_t i = 0; i < times_to_lock_;) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      switch (type_) {
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        case kTypeLock: {
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          mutex_->Lock();
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          int old_shared_value = *shared_value_;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (should_sleep_)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SleepALittle();
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          *shared_value_ = old_shared_value + 1;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          mutex_->Unlock();
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          i++;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        case kTypeTry:
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (mutex_->TryLock()) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            int old_shared_value = *shared_value_;
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if (should_sleep_)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              SleepALittle();
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            *shared_value_ = old_shared_value + 1;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            mutex_->Unlock();
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            i++;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          } else {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SleepALittle();  // Don't spin.
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          }
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static void SleepALittle() {
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    static const long kNanosPerMilli = 1000000;
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    struct timespec req = {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0,  // Seconds.
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (rand() % 10) * kNanosPerMilli // Nanoseconds.
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    };
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int rv MOJO_ALLOW_UNUSED = nanosleep(&req, NULL);
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    assert(rv == 0);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const size_t times_to_lock_;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Type type_;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const bool should_sleep_;
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Mutex* const mutex_;
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int* const shared_value_;
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOJO_DISALLOW_COPY_AND_ASSIGN(Fiddler);
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class FiddlerThread : public Thread {
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Takes ownership of |fiddler|.
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FiddlerThread(Fiddler* fiddler)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : fiddler_(fiddler) {
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~FiddlerThread() {
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete fiddler_;
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Run() MOJO_OVERRIDE {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_->Fiddle();
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Fiddler* const fiddler_;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOJO_DISALLOW_COPY_AND_ASSIGN(FiddlerThread);
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This does a stress test (that also checks exclusion).
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(MutexTest, ThreadedStress) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const size_t kNumThreads = 20;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const int kTimesToLockEach = 20;
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  assert(kNumThreads % 4 == 0);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Mutex mutex;
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int shared_value = 0;
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<FiddlerThread*> fiddler_threads;
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kNumThreads; i += 4) {
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kTimesToLockEach, Fiddler::kTypeLock, false, &mutex, &shared_value)));
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kTimesToLockEach, Fiddler::kTypeTry, false, &mutex, &shared_value)));
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)));
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_threads.push_back(new FiddlerThread(new Fiddler(
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kTimesToLockEach, Fiddler::kTypeTry, true, &mutex, &shared_value)));
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kNumThreads; i++)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_threads[i]->Start();
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do some fiddling ourselves.
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Fiddler(kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .Fiddle();
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Join.
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kNumThreads; i++)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fiddler_threads[i]->Join();
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(static_cast<int>(kNumThreads + 1) * kTimesToLockEach, shared_value);
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Delete.
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kNumThreads; i++)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete fiddler_threads[i];
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  fiddler_threads.clear();
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class TryThread : public Thread {
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit TryThread(Mutex* mutex) : mutex_(mutex), try_lock_succeeded_() {}
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~TryThread() {}
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Run() MOJO_OVERRIDE {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    try_lock_succeeded_ = mutex_->TryLock();
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (try_lock_succeeded_)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      mutex_->Unlock();
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool try_lock_succeeded() const { return try_lock_succeeded_; }
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Mutex* const mutex_;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool try_lock_succeeded_;
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MOJO_DISALLOW_COPY_AND_ASSIGN(TryThread);
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(MutexTest, TryLock) {
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Mutex mutex;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |TryLock()| should succeed -- we don't have the lock.
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TryThread thread(&mutex);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    thread.Start();
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    thread.Join();
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_TRUE(thread.try_lock_succeeded());
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Take the lock.
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(mutex.TryLock());
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Now it should fail.
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TryThread thread(&mutex);
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    thread.Start();
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    thread.Join();
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_FALSE(thread.try_lock_succeeded());
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Release the lock.
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  mutex.Unlock();
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // It should succeed again.
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  {
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TryThread thread(&mutex);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    thread.Start();
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    thread.Join();
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_TRUE(thread.try_lock_succeeded());
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Tests of assertions for Debug builds.
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if !defined(NDEBUG)
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test |AssertHeld()| (which is an actual user API).
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(MutexTest, DebugAssertHeldFailure) {
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Mutex mutex;
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_DEATH_IF_SUPPORTED(mutex.AssertHeld(), "");
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test other consistency checks.
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(MutexTest, DebugAssertionFailures) {
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Unlock without lock held.
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_DEATH_IF_SUPPORTED({
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Mutex mutex;
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.Unlock();
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }, "");
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Lock with lock held (on same thread).
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_DEATH_IF_SUPPORTED({
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Mutex mutex;
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.Lock();
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.Lock();
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }, "");
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try lock with lock held.
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_DEATH_IF_SUPPORTED({
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Mutex mutex;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.Lock();
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.TryLock();
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }, "");
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Destroy lock with lock held.
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_DEATH_IF_SUPPORTED({
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Mutex mutex;
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    mutex.Lock();
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }, "");
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // !defined(NDEBUG)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace mojo
263