13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <stdlib.h>
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
73f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/lock.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "testing/gtest/include/gtest/gtest.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base {
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass BasicLockTestThread : public PlatformThread::Delegate {
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void ThreadMain() {
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (int i = 0; i < 10; i++) {
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock_->Acquire();
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      acquired_++;
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock_->Release();
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (int i = 0; i < 10; i++) {
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock_->Acquire();
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      acquired_++;
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      PlatformThread::Sleep(rand() % 20);
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock_->Release();
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (int i = 0; i < 10; i++) {
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (lock_->Try()) {
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        acquired_++;
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        PlatformThread::Sleep(rand() % 20);
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        lock_->Release();
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int acquired() const { return acquired_; }
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock* lock_;
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int acquired_;
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
493f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenTEST(LockTest, Basic) {
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock lock;
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BasicLockTestThread thread(&lock);
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThreadHandle handle = kNullThreadHandle;
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int acquired = 0;
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < 5; i++) {
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock.Acquire();
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    acquired++;
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock.Release();
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < 10; i++) {
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock.Acquire();
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    acquired++;
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThread::Sleep(rand() % 20);
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock.Release();
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < 10; i++) {
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (lock.Try()) {
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      acquired++;
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      PlatformThread::Sleep(rand() % 20);
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock.Release();
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (int i = 0; i < 5; i++) {
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock.Acquire();
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    acquired++;
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThread::Sleep(rand() % 20);
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    lock.Release();
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThread::Join(handle);
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_GE(acquired, 20);
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_GE(thread.acquired(), 20);
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Test that Try() works as expected -------------------------------------------
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass TryLockTestThread : public PlatformThread::Delegate {
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void ThreadMain() {
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    got_lock_ = lock_->Try();
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (got_lock_)
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock_->Release();
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool got_lock() const { return got_lock_; }
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock* lock_;
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool got_lock_;
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1093f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenTEST(LockTest, TryLock) {
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock lock;
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(lock.Try());
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We now have the lock....
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This thread will not be able to get the lock.
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  {
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    TryLockTestThread thread(&lock);
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThreadHandle handle = kNullThreadHandle;
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThread::Join(handle);
1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_FALSE(thread.got_lock());
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  lock.Release();
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This thread will....
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  {
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    TryLockTestThread thread(&lock);
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThreadHandle handle = kNullThreadHandle;
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThread::Join(handle);
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_TRUE(thread.got_lock());
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // But it released it....
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_TRUE(lock.Try());
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  lock.Release();
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Tests that locks actually exclude -------------------------------------------
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass MutexLockTestThread : public PlatformThread::Delegate {
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Static helper which can also be called from the main thread.
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static void DoStuff(Lock* lock, int* value) {
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (int i = 0; i < 40; i++) {
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock->Acquire();
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      int v = *value;
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      PlatformThread::Sleep(rand() % 10);
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      *value = v + 1;
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      lock->Release();
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void ThreadMain() {
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DoStuff(lock_, value_);
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock* lock_;
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int* value_;
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1743f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenTEST(LockTest, MutexTwoThreads) {
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock lock;
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int value = 0;
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread thread(&lock, &value);
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThreadHandle handle = kNullThreadHandle;
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread::DoStuff(&lock, &value);
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThread::Join(handle);
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(2 * 40, value);
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1903f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenTEST(LockTest, MutexFourThreads) {
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Lock lock;
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int value = 0;
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread thread1(&lock, &value);
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread thread2(&lock, &value);
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread thread3(&lock, &value);
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThreadHandle handle1 = kNullThreadHandle;
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThreadHandle handle2 = kNullThreadHandle;
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThreadHandle handle3 = kNullThreadHandle;
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MutexLockTestThread::DoStuff(&lock, &value);
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThread::Join(handle1);
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThread::Join(handle2);
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PlatformThread::Join(handle3);
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(4 * 40, value);
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
2143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
215