diff options
Diffstat (limited to 'test/lock_test.cc')
-rw-r--r-- | test/lock_test.cc | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/test/lock_test.cc b/test/lock_test.cc new file mode 100644 index 0000000..b29a4bf --- /dev/null +++ b/test/lock_test.cc @@ -0,0 +1,244 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> + +#include "gtest/gtest.h" +#include "sfntly/port/lock.h" +#include "test/platform_thread.h" + +namespace sfntly { + +// Basic test to make sure that Acquire()/Unlock()/Try() don't crash + +class BasicLockTestThread : public PlatformThread::Delegate { + public: + BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {} + + virtual void ThreadMain() { + for (int i = 0; i < 10; i++) { + lock_->Acquire(); + acquired_++; + lock_->Unlock(); + } + for (int i = 0; i < 10; i++) { + lock_->Acquire(); + acquired_++; + PlatformThread::Sleep(rand() % 20); + lock_->Unlock(); + } + for (int i = 0; i < 10; i++) { + if (lock_->Try()) { + acquired_++; + PlatformThread::Sleep(rand() % 20); + lock_->Unlock(); + } + } + } + + int acquired() const { return acquired_; } + + private: + Lock* lock_; + int acquired_; + + NO_COPY_AND_ASSIGN(BasicLockTestThread); +}; + +bool BasicLockTest() { + Lock lock; + BasicLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + int acquired = 0; + for (int i = 0; i < 5; i++) { + lock.Acquire(); + acquired++; + lock.Unlock(); + } + for (int i = 0; i < 10; i++) { + lock.Acquire(); + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Unlock(); + } + for (int i = 0; i < 10; i++) { + if (lock.Try()) { + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Unlock(); + } + } + for (int i = 0; i < 5; i++) { + lock.Acquire(); + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Unlock(); + } + + PlatformThread::Join(handle); + + EXPECT_GE(acquired, 20); + EXPECT_GE(thread.acquired(), 20); + + return true; +} + +// Test that Try() works as expected ------------------------------------------- + +class TryLockTestThread : public PlatformThread::Delegate { + public: + TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {} + + virtual void ThreadMain() { + got_lock_ = lock_->Try(); + if (got_lock_) + lock_->Unlock(); + } + + bool got_lock() const { return got_lock_; } + + private: + Lock* lock_; + bool got_lock_; + + NO_COPY_AND_ASSIGN(TryLockTestThread); +}; + +bool TryLockTest() { + Lock lock; + + EXPECT_TRUE(lock.Try()); + // We now have the lock.... + + // This thread will not be able to get the lock. + { + TryLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + PlatformThread::Join(handle); + + EXPECT_FALSE(thread.got_lock()); + } + + lock.Unlock(); + + // This thread will.... + { + TryLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + PlatformThread::Join(handle); + + EXPECT_TRUE(thread.got_lock()); + // But it released it.... + EXPECT_TRUE(lock.Try()); + } + + lock.Unlock(); + return true; +} + +// Tests that locks actually exclude ------------------------------------------- + +class MutexLockTestThread : public PlatformThread::Delegate { + public: + MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {} + + // Static helper which can also be called from the main thread. + static void DoStuff(Lock* lock, int* value) { + for (int i = 0; i < 40; i++) { + lock->Acquire(); + int v = *value; + PlatformThread::Sleep(rand() % 10); + *value = v + 1; + lock->Unlock(); + } + } + + virtual void ThreadMain() { + DoStuff(lock_, value_); + } + + private: + Lock* lock_; + int* value_; + + NO_COPY_AND_ASSIGN(MutexLockTestThread); +}; + +bool MutexTwoThreads() { + Lock lock; + int value = 0; + + MutexLockTestThread thread(&lock, &value); + PlatformThreadHandle handle = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread, &handle)); + + MutexLockTestThread::DoStuff(&lock, &value); + + PlatformThread::Join(handle); + + EXPECT_EQ(2 * 40, value); + return true; +} + +bool MutexFourThreads() { + Lock lock; + int value = 0; + + MutexLockTestThread thread1(&lock, &value); + MutexLockTestThread thread2(&lock, &value); + MutexLockTestThread thread3(&lock, &value); + PlatformThreadHandle handle1 = kNullThreadHandle; + PlatformThreadHandle handle2 = kNullThreadHandle; + PlatformThreadHandle handle3 = kNullThreadHandle; + + EXPECT_TRUE(PlatformThread::Create(&thread1, &handle1)); + EXPECT_TRUE(PlatformThread::Create(&thread2, &handle2)); + EXPECT_TRUE(PlatformThread::Create(&thread3, &handle3)); + + MutexLockTestThread::DoStuff(&lock, &value); + + PlatformThread::Join(handle1); + PlatformThread::Join(handle2); + PlatformThread::Join(handle3); + + EXPECT_EQ(4 * 40, value); + return true; +} + +} // namespace sfntly + +TEST(LockTest, Basic) { + ASSERT_TRUE(sfntly::BasicLockTest()); +} + +TEST(LockTest, TryLock) { + ASSERT_TRUE(sfntly::TryLockTest()); +} + +TEST(LockTest, Mutex) { + ASSERT_TRUE(sfntly::MutexTwoThreads()); + ASSERT_TRUE(sfntly::MutexFourThreads()); +} |