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