//===--- Mutex.cpp - Mutex Tests ------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/Threading/Mutex.h" #include "gtest/gtest.h" #include #include #include #include #include "ThreadingHelpers.h" using namespace swift; // ----------------------------------------------------------------------------- template void basicLockableThreaded(M &mutex) { int count1 = 0; int count2 = 0; threadedExecute(10, [&](int) { for (int j = 0; j < 50; ++j) { mutex.lock(); auto count = count2; count1++; count2 = count + 1; mutex.unlock(); } }); ASSERT_EQ(count1, 500); ASSERT_EQ(count2, 500); } TEST(MutexTest, BasicLockableThreaded) { Mutex mutex(/* checked = */ true); basicLockableThreaded(mutex); } TEST(LazyMutexTest, BasicLockableThreaded) { static LazyMutex mutex; basicLockableThreaded(mutex); } TEST(LazyUnsafeMutexTest, BasicLockableThreaded) { static LazyUnsafeMutex mutex; basicLockableThreaded(mutex); } TEST(SmallMutex, BasicLockableThreaded) { SmallMutex mutex; basicLockableThreaded(mutex); } template void lockableThreaded(M &mutex) { mutex.lock(); threadedExecute(5, [&](int) { ASSERT_FALSE(mutex.try_lock()); }); mutex.unlock(); threadedExecute(1, [&](int) { ASSERT_TRUE(mutex.try_lock()); mutex.unlock(); }); int count1 = 0; int count2 = 0; threadedExecute(10, [&](int) { for (int j = 0; j < 50; ++j) { if (mutex.try_lock()) { auto count = count2; count1++; count2 = count + 1; mutex.unlock(); } else { j--; } } }); ASSERT_EQ(count1, 500); ASSERT_EQ(count2, 500); } TEST(MutexTest, LockableThreaded) { Mutex mutex(/* checked = */ true); lockableThreaded(mutex); } TEST(LazyMutexTest, LockableThreaded) { static LazyMutex Mutex; lockableThreaded(Mutex); } TEST(SmallMutexTest, LockableThreaded) { SmallMutex Mutex; lockableThreaded(Mutex); } template void scopedLockThreaded(M &mutex) { int count1 = 0; int count2 = 0; threadedExecute(10, [&](int) { for (int j = 0; j < 50; ++j) { SL guard(mutex); auto count = count2; count1++; count2 = count + 1; } }); ASSERT_EQ(count1, 500); ASSERT_EQ(count2, 500); } TEST(MutexTest, ScopedLockThreaded) { Mutex mutex(/* checked = */ true); scopedLockThreaded(mutex); } TEST(LazyMutexTest, ScopedLockThreaded) { static LazyMutex Mutex; scopedLockThreaded(Mutex); } TEST(SmallMutexTest, ScopedLockThreaded) { SmallMutex mutex(/* checked = */ true); scopedLockThreaded>(mutex); } template void scopedUnlockUnderScopedLockThreaded(M &mutex) { int count1 = 0; int count2 = 0; int badCount = 0; threadedExecute(10, [&](int) { for (int j = 0; j < 50; ++j) { SL guard(mutex); { SU unguard(mutex); badCount++; } auto count = count2; count1++; count2 = count + 1; } }); ASSERT_EQ(count1, 500); ASSERT_EQ(count2, 500); } TEST(MutexTest, ScopedUnlockUnderScopedLockThreaded) { Mutex mutex(/* checked = */ true); scopedUnlockUnderScopedLockThreaded( mutex); } TEST(LazyMutexTest, ScopedUnlockUnderScopedLockThreaded) { static LazyMutex Mutex; scopedUnlockUnderScopedLockThreaded(Mutex); } TEST(SmallMutexTest, ScopedUnlockUnderScopedLockThreaded) { SmallMutex mutex(/* checked = */ true); scopedUnlockUnderScopedLockThreaded(mutex); } template void criticalSectionThreaded(M &mutex) { int count1 = 0; int count2 = 0; threadedExecute(10, [&](int) { for (int j = 0; j < 50; ++j) { mutex.withLock([&] { auto count = count2; count1++; count2 = count + 1; }); } }); ASSERT_EQ(count1, 500); ASSERT_EQ(count2, 500); } TEST(MutexTest, CriticalSectionThreaded) { Mutex mutex(/* checked = */ true); criticalSectionThreaded(mutex); } TEST(LazyMutexTest, CriticalSectionThreaded) { static LazyMutex Mutex; criticalSectionThreaded(Mutex); } template void scopedReadThreaded(RW &lock) { const int threadCount = 10; std::set writerHistory; std::vector> readerHistory; readerHistory.assign(threadCount, std::set()); int protectedValue = 0; writerHistory.insert(protectedValue); threadedExecute(threadCount, [&](int index) { if (Locking) { for (int i = 0; i < 50; ++i) { { SRL guard(lock); readerHistory[index].insert(protectedValue); } std::this_thread::yield(); } } else { lock.readLock(); for (int i = 0; i < 50; ++i) { readerHistory[index].insert(protectedValue); { SRL unguard(lock); std::this_thread::yield(); } } lock.readUnlock(); } }, [&] { for (int i = 0; i < 25; ++i) { lock.writeLock(); protectedValue += i; writerHistory.insert(protectedValue); lock.writeUnlock(); } }); for (auto &history : readerHistory) { for (auto value : history) { ASSERT_EQ(writerHistory.count(value), 1U); } } }