13cab2bb3Spatrick //===-- mutex_test.cpp ------------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick
93cab2bb3Spatrick #include "gwp_asan/mutex.h"
10*d89ec533Spatrick #include "gwp_asan/tests/harness.h"
113cab2bb3Spatrick
123cab2bb3Spatrick #include <atomic>
133cab2bb3Spatrick #include <mutex>
143cab2bb3Spatrick #include <thread>
153cab2bb3Spatrick #include <vector>
163cab2bb3Spatrick
173cab2bb3Spatrick using gwp_asan::Mutex;
183cab2bb3Spatrick using gwp_asan::ScopedLock;
193cab2bb3Spatrick
TEST(GwpAsanMutexTest,LockUnlockTest)203cab2bb3Spatrick TEST(GwpAsanMutexTest, LockUnlockTest) {
213cab2bb3Spatrick Mutex Mu;
223cab2bb3Spatrick
233cab2bb3Spatrick ASSERT_TRUE(Mu.tryLock());
243cab2bb3Spatrick ASSERT_FALSE(Mu.tryLock());
253cab2bb3Spatrick Mu.unlock();
263cab2bb3Spatrick
273cab2bb3Spatrick Mu.lock();
283cab2bb3Spatrick Mu.unlock();
293cab2bb3Spatrick
303cab2bb3Spatrick // Ensure that the mutex actually unlocked.
313cab2bb3Spatrick ASSERT_TRUE(Mu.tryLock());
323cab2bb3Spatrick Mu.unlock();
333cab2bb3Spatrick }
343cab2bb3Spatrick
TEST(GwpAsanMutexTest,ScopedLockUnlockTest)353cab2bb3Spatrick TEST(GwpAsanMutexTest, ScopedLockUnlockTest) {
363cab2bb3Spatrick Mutex Mu;
373cab2bb3Spatrick { ScopedLock L(Mu); }
383cab2bb3Spatrick // Locking will fail here if the scoped lock failed to unlock.
393cab2bb3Spatrick EXPECT_TRUE(Mu.tryLock());
403cab2bb3Spatrick Mu.unlock();
413cab2bb3Spatrick
423cab2bb3Spatrick {
433cab2bb3Spatrick ScopedLock L(Mu);
443cab2bb3Spatrick EXPECT_FALSE(Mu.tryLock()); // Check that the c'tor did lock.
453cab2bb3Spatrick
463cab2bb3Spatrick // Manually unlock and check that this succeeds.
473cab2bb3Spatrick Mu.unlock();
483cab2bb3Spatrick EXPECT_TRUE(Mu.tryLock()); // Manually lock.
493cab2bb3Spatrick }
503cab2bb3Spatrick EXPECT_TRUE(Mu.tryLock()); // Assert that the scoped destructor did unlock.
513cab2bb3Spatrick Mu.unlock();
523cab2bb3Spatrick }
533cab2bb3Spatrick
synchronousIncrementTask(std::atomic<bool> * StartingGun,Mutex * Mu,unsigned * Counter,unsigned NumIterations)543cab2bb3Spatrick static void synchronousIncrementTask(std::atomic<bool> *StartingGun, Mutex *Mu,
553cab2bb3Spatrick unsigned *Counter,
563cab2bb3Spatrick unsigned NumIterations) {
573cab2bb3Spatrick while (!StartingGun) {
583cab2bb3Spatrick // Wait for starting gun.
593cab2bb3Spatrick }
603cab2bb3Spatrick for (unsigned i = 0; i < NumIterations; ++i) {
613cab2bb3Spatrick ScopedLock L(*Mu);
623cab2bb3Spatrick (*Counter)++;
633cab2bb3Spatrick }
643cab2bb3Spatrick }
653cab2bb3Spatrick
runSynchronisedTest(unsigned NumThreads,unsigned CounterMax)663cab2bb3Spatrick static void runSynchronisedTest(unsigned NumThreads, unsigned CounterMax) {
673cab2bb3Spatrick std::vector<std::thread> Threads;
683cab2bb3Spatrick
693cab2bb3Spatrick ASSERT_TRUE(CounterMax % NumThreads == 0);
703cab2bb3Spatrick
713cab2bb3Spatrick std::atomic<bool> StartingGun{false};
723cab2bb3Spatrick Mutex Mu;
733cab2bb3Spatrick unsigned Counter = 0;
743cab2bb3Spatrick
753cab2bb3Spatrick for (unsigned i = 0; i < NumThreads; ++i)
763cab2bb3Spatrick Threads.emplace_back(synchronousIncrementTask, &StartingGun, &Mu, &Counter,
773cab2bb3Spatrick CounterMax / NumThreads);
783cab2bb3Spatrick
793cab2bb3Spatrick StartingGun = true;
803cab2bb3Spatrick for (auto &T : Threads)
813cab2bb3Spatrick T.join();
823cab2bb3Spatrick
833cab2bb3Spatrick EXPECT_EQ(CounterMax, Counter);
843cab2bb3Spatrick }
853cab2bb3Spatrick
TEST(GwpAsanMutexTest,SynchronisedCounterTest)863cab2bb3Spatrick TEST(GwpAsanMutexTest, SynchronisedCounterTest) {
873cab2bb3Spatrick runSynchronisedTest(4, 1000000);
883cab2bb3Spatrick runSynchronisedTest(100, 1000000);
893cab2bb3Spatrick }
90