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