1 // Copyright 2014 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 "mojo/public/cpp/utility/mutex.h" 6 7 #include <stdlib.h> // For |rand()|. 8 #include <time.h> // For |nanosleep()| (defined by POSIX). 9 10 #include <vector> 11 12 #include "mojo/public/cpp/system/macros.h" 13 #include "mojo/public/cpp/utility/thread.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace mojo { 17 namespace { 18 19 TEST(MutexTest, TrivialSingleThreaded) { 20 Mutex mutex; 21 22 mutex.Lock(); 23 mutex.AssertHeld(); 24 mutex.Unlock(); 25 26 EXPECT_TRUE(mutex.TryLock()); 27 mutex.AssertHeld(); 28 mutex.Unlock(); 29 30 { 31 MutexLock lock(&mutex); 32 mutex.AssertHeld(); 33 } 34 35 EXPECT_TRUE(mutex.TryLock()); 36 mutex.Unlock(); 37 } 38 39 class Fiddler { 40 public: 41 enum Type { kTypeLock, kTypeTry }; 42 Fiddler(size_t times_to_lock, 43 Type type, 44 bool should_sleep, 45 Mutex* mutex, 46 int* shared_value) 47 : times_to_lock_(times_to_lock), 48 type_(type), 49 should_sleep_(should_sleep), 50 mutex_(mutex), 51 shared_value_(shared_value) { 52 } 53 54 ~Fiddler() { 55 } 56 57 void Fiddle() { 58 for (size_t i = 0; i < times_to_lock_;) { 59 switch (type_) { 60 case kTypeLock: { 61 mutex_->Lock(); 62 int old_shared_value = *shared_value_; 63 if (should_sleep_) 64 SleepALittle(); 65 *shared_value_ = old_shared_value + 1; 66 mutex_->Unlock(); 67 i++; 68 break; 69 } 70 case kTypeTry: 71 if (mutex_->TryLock()) { 72 int old_shared_value = *shared_value_; 73 if (should_sleep_) 74 SleepALittle(); 75 *shared_value_ = old_shared_value + 1; 76 mutex_->Unlock(); 77 i++; 78 } else { 79 SleepALittle(); // Don't spin. 80 } 81 break; 82 } 83 } 84 } 85 86 private: 87 static void SleepALittle() { 88 static const long kNanosPerMilli = 1000000; 89 struct timespec req = { 90 0, // Seconds. 91 (rand() % 10) * kNanosPerMilli // Nanoseconds. 92 }; 93 int rv MOJO_ALLOW_UNUSED = nanosleep(&req, NULL); 94 assert(rv == 0); 95 } 96 97 const size_t times_to_lock_; 98 const Type type_; 99 const bool should_sleep_; 100 Mutex* const mutex_; 101 int* const shared_value_; 102 103 MOJO_DISALLOW_COPY_AND_ASSIGN(Fiddler); 104 }; 105 106 class FiddlerThread : public Thread { 107 public: 108 // Takes ownership of |fiddler|. 109 FiddlerThread(Fiddler* fiddler) 110 : fiddler_(fiddler) { 111 } 112 113 virtual ~FiddlerThread() { 114 delete fiddler_; 115 } 116 117 virtual void Run() MOJO_OVERRIDE { 118 fiddler_->Fiddle(); 119 } 120 121 private: 122 Fiddler* const fiddler_; 123 124 MOJO_DISALLOW_COPY_AND_ASSIGN(FiddlerThread); 125 }; 126 127 // This does a stress test (that also checks exclusion). 128 TEST(MutexTest, ThreadedStress) { 129 static const size_t kNumThreads = 20; 130 static const int kTimesToLockEach = 20; 131 assert(kNumThreads % 4 == 0); 132 133 Mutex mutex; 134 int shared_value = 0; 135 136 std::vector<FiddlerThread*> fiddler_threads; 137 138 for (size_t i = 0; i < kNumThreads; i += 4) { 139 fiddler_threads.push_back(new FiddlerThread(new Fiddler( 140 kTimesToLockEach, Fiddler::kTypeLock, false, &mutex, &shared_value))); 141 fiddler_threads.push_back(new FiddlerThread(new Fiddler( 142 kTimesToLockEach, Fiddler::kTypeTry, false, &mutex, &shared_value))); 143 fiddler_threads.push_back(new FiddlerThread(new Fiddler( 144 kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value))); 145 fiddler_threads.push_back(new FiddlerThread(new Fiddler( 146 kTimesToLockEach, Fiddler::kTypeTry, true, &mutex, &shared_value))); 147 } 148 149 for (size_t i = 0; i < kNumThreads; i++) 150 fiddler_threads[i]->Start(); 151 152 // Do some fiddling ourselves. 153 Fiddler(kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value) 154 .Fiddle(); 155 156 // Join. 157 for (size_t i = 0; i < kNumThreads; i++) 158 fiddler_threads[i]->Join(); 159 160 EXPECT_EQ(static_cast<int>(kNumThreads + 1) * kTimesToLockEach, shared_value); 161 162 // Delete. 163 for (size_t i = 0; i < kNumThreads; i++) 164 delete fiddler_threads[i]; 165 fiddler_threads.clear(); 166 } 167 168 class TryThread : public Thread { 169 public: 170 explicit TryThread(Mutex* mutex) : mutex_(mutex), try_lock_succeeded_() {} 171 virtual ~TryThread() {} 172 173 virtual void Run() MOJO_OVERRIDE { 174 try_lock_succeeded_ = mutex_->TryLock(); 175 if (try_lock_succeeded_) 176 mutex_->Unlock(); 177 } 178 179 bool try_lock_succeeded() const { return try_lock_succeeded_; } 180 181 private: 182 Mutex* const mutex_; 183 bool try_lock_succeeded_; 184 185 MOJO_DISALLOW_COPY_AND_ASSIGN(TryThread); 186 }; 187 188 TEST(MutexTest, TryLock) { 189 Mutex mutex; 190 191 // |TryLock()| should succeed -- we don't have the lock. 192 { 193 TryThread thread(&mutex); 194 thread.Start(); 195 thread.Join(); 196 EXPECT_TRUE(thread.try_lock_succeeded()); 197 } 198 199 // Take the lock. 200 ASSERT_TRUE(mutex.TryLock()); 201 202 // Now it should fail. 203 { 204 TryThread thread(&mutex); 205 thread.Start(); 206 thread.Join(); 207 EXPECT_FALSE(thread.try_lock_succeeded()); 208 } 209 210 // Release the lock. 211 mutex.Unlock(); 212 213 // It should succeed again. 214 { 215 TryThread thread(&mutex); 216 thread.Start(); 217 thread.Join(); 218 EXPECT_TRUE(thread.try_lock_succeeded()); 219 } 220 } 221 222 223 // Tests of assertions for Debug builds. 224 #if !defined(NDEBUG) 225 // Test |AssertHeld()| (which is an actual user API). 226 TEST(MutexTest, DebugAssertHeldFailure) { 227 Mutex mutex; 228 EXPECT_DEATH_IF_SUPPORTED(mutex.AssertHeld(), ""); 229 } 230 231 // Test other consistency checks. 232 TEST(MutexTest, DebugAssertionFailures) { 233 // Unlock without lock held. 234 EXPECT_DEATH_IF_SUPPORTED({ 235 Mutex mutex; 236 mutex.Unlock(); 237 }, ""); 238 239 // Lock with lock held (on same thread). 240 EXPECT_DEATH_IF_SUPPORTED({ 241 Mutex mutex; 242 mutex.Lock(); 243 mutex.Lock(); 244 }, ""); 245 246 // Try lock with lock held. 247 EXPECT_DEATH_IF_SUPPORTED({ 248 Mutex mutex; 249 mutex.Lock(); 250 mutex.TryLock(); 251 }, ""); 252 253 // Destroy lock with lock held. 254 EXPECT_DEATH_IF_SUPPORTED({ 255 Mutex mutex; 256 mutex.Lock(); 257 }, ""); 258 } 259 #endif // !defined(NDEBUG) 260 261 } // namespace 262 } // namespace mojo 263