Home | History | Annotate | Download | only in synchronization
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/synchronization/lock.h"
      6 
      7 #include <stdlib.h>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/macros.h"
     11 #include "base/threading/platform_thread.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace base {
     15 
     16 // Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
     17 
     18 class BasicLockTestThread : public PlatformThread::Delegate {
     19  public:
     20   explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
     21 
     22   void ThreadMain() override {
     23     for (int i = 0; i < 10; i++) {
     24       lock_->Acquire();
     25       acquired_++;
     26       lock_->Release();
     27     }
     28     for (int i = 0; i < 10; i++) {
     29       lock_->Acquire();
     30       acquired_++;
     31       PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
     32       lock_->Release();
     33     }
     34     for (int i = 0; i < 10; i++) {
     35       if (lock_->Try()) {
     36         acquired_++;
     37         PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
     38         lock_->Release();
     39       }
     40     }
     41   }
     42 
     43   int acquired() const { return acquired_; }
     44 
     45  private:
     46   Lock* lock_;
     47   int acquired_;
     48 
     49   DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
     50 };
     51 
     52 TEST(LockTest, Basic) {
     53   Lock lock;
     54   BasicLockTestThread thread(&lock);
     55   PlatformThreadHandle handle;
     56 
     57   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
     58 
     59   int acquired = 0;
     60   for (int i = 0; i < 5; i++) {
     61     lock.Acquire();
     62     acquired++;
     63     lock.Release();
     64   }
     65   for (int i = 0; i < 10; i++) {
     66     lock.Acquire();
     67     acquired++;
     68     PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
     69     lock.Release();
     70   }
     71   for (int i = 0; i < 10; i++) {
     72     if (lock.Try()) {
     73       acquired++;
     74       PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
     75       lock.Release();
     76     }
     77   }
     78   for (int i = 0; i < 5; i++) {
     79     lock.Acquire();
     80     acquired++;
     81     PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
     82     lock.Release();
     83   }
     84 
     85   PlatformThread::Join(handle);
     86 
     87   EXPECT_GE(acquired, 20);
     88   EXPECT_GE(thread.acquired(), 20);
     89 }
     90 
     91 // Test that Try() works as expected -------------------------------------------
     92 
     93 class TryLockTestThread : public PlatformThread::Delegate {
     94  public:
     95   explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
     96 
     97   void ThreadMain() override {
     98     got_lock_ = lock_->Try();
     99     if (got_lock_)
    100       lock_->Release();
    101   }
    102 
    103   bool got_lock() const { return got_lock_; }
    104 
    105  private:
    106   Lock* lock_;
    107   bool got_lock_;
    108 
    109   DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
    110 };
    111 
    112 TEST(LockTest, TryLock) {
    113   Lock lock;
    114 
    115   ASSERT_TRUE(lock.Try());
    116   // We now have the lock....
    117 
    118   // This thread will not be able to get the lock.
    119   {
    120     TryLockTestThread thread(&lock);
    121     PlatformThreadHandle handle;
    122 
    123     ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
    124 
    125     PlatformThread::Join(handle);
    126 
    127     ASSERT_FALSE(thread.got_lock());
    128   }
    129 
    130   lock.Release();
    131 
    132   // This thread will....
    133   {
    134     TryLockTestThread thread(&lock);
    135     PlatformThreadHandle handle;
    136 
    137     ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
    138 
    139     PlatformThread::Join(handle);
    140 
    141     ASSERT_TRUE(thread.got_lock());
    142     // But it released it....
    143     ASSERT_TRUE(lock.Try());
    144   }
    145 
    146   lock.Release();
    147 }
    148 
    149 // Tests that locks actually exclude -------------------------------------------
    150 
    151 class MutexLockTestThread : public PlatformThread::Delegate {
    152  public:
    153   MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
    154 
    155   // Static helper which can also be called from the main thread.
    156   static void DoStuff(Lock* lock, int* value) {
    157     for (int i = 0; i < 40; i++) {
    158       lock->Acquire();
    159       int v = *value;
    160       PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
    161       *value = v + 1;
    162       lock->Release();
    163     }
    164   }
    165 
    166   void ThreadMain() override { DoStuff(lock_, value_); }
    167 
    168  private:
    169   Lock* lock_;
    170   int* value_;
    171 
    172   DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
    173 };
    174 
    175 TEST(LockTest, MutexTwoThreads) {
    176   Lock lock;
    177   int value = 0;
    178 
    179   MutexLockTestThread thread(&lock, &value);
    180   PlatformThreadHandle handle;
    181 
    182   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
    183 
    184   MutexLockTestThread::DoStuff(&lock, &value);
    185 
    186   PlatformThread::Join(handle);
    187 
    188   EXPECT_EQ(2 * 40, value);
    189 }
    190 
    191 TEST(LockTest, MutexFourThreads) {
    192   Lock lock;
    193   int value = 0;
    194 
    195   MutexLockTestThread thread1(&lock, &value);
    196   MutexLockTestThread thread2(&lock, &value);
    197   MutexLockTestThread thread3(&lock, &value);
    198   PlatformThreadHandle handle1;
    199   PlatformThreadHandle handle2;
    200   PlatformThreadHandle handle3;
    201 
    202   ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
    203   ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
    204   ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
    205 
    206   MutexLockTestThread::DoStuff(&lock, &value);
    207 
    208   PlatformThread::Join(handle1);
    209   PlatformThread::Join(handle2);
    210   PlatformThread::Join(handle3);
    211 
    212   EXPECT_EQ(4 * 40, value);
    213 }
    214 
    215 }  // namespace base
    216