15f0f4e3aSMitch Phillips //===-- mutex_test.cpp ------------------------------------------*- C++ -*-===//
25f0f4e3aSMitch Phillips //
35f0f4e3aSMitch Phillips // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f0f4e3aSMitch Phillips // See https://llvm.org/LICENSE.txt for license information.
55f0f4e3aSMitch Phillips // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f0f4e3aSMitch Phillips //
75f0f4e3aSMitch Phillips //===----------------------------------------------------------------------===//
85f0f4e3aSMitch Phillips
95f0f4e3aSMitch Phillips #include "gwp_asan/mutex.h"
10*5556616bSKostya Kortchinsky #include "gwp_asan/tests/harness.h"
115f0f4e3aSMitch Phillips
125f0f4e3aSMitch Phillips #include <atomic>
135f0f4e3aSMitch Phillips #include <mutex>
145f0f4e3aSMitch Phillips #include <thread>
155f0f4e3aSMitch Phillips #include <vector>
165f0f4e3aSMitch Phillips
175f0f4e3aSMitch Phillips using gwp_asan::Mutex;
185f0f4e3aSMitch Phillips using gwp_asan::ScopedLock;
195f0f4e3aSMitch Phillips
TEST(GwpAsanMutexTest,LockUnlockTest)205f0f4e3aSMitch Phillips TEST(GwpAsanMutexTest, LockUnlockTest) {
215f0f4e3aSMitch Phillips Mutex Mu;
225f0f4e3aSMitch Phillips
235f0f4e3aSMitch Phillips ASSERT_TRUE(Mu.tryLock());
245f0f4e3aSMitch Phillips ASSERT_FALSE(Mu.tryLock());
255f0f4e3aSMitch Phillips Mu.unlock();
265f0f4e3aSMitch Phillips
275f0f4e3aSMitch Phillips Mu.lock();
285f0f4e3aSMitch Phillips Mu.unlock();
295f0f4e3aSMitch Phillips
305f0f4e3aSMitch Phillips // Ensure that the mutex actually unlocked.
315f0f4e3aSMitch Phillips ASSERT_TRUE(Mu.tryLock());
325f0f4e3aSMitch Phillips Mu.unlock();
335f0f4e3aSMitch Phillips }
345f0f4e3aSMitch Phillips
TEST(GwpAsanMutexTest,ScopedLockUnlockTest)355f0f4e3aSMitch Phillips TEST(GwpAsanMutexTest, ScopedLockUnlockTest) {
365f0f4e3aSMitch Phillips Mutex Mu;
375f0f4e3aSMitch Phillips { ScopedLock L(Mu); }
385f0f4e3aSMitch Phillips // Locking will fail here if the scoped lock failed to unlock.
395f0f4e3aSMitch Phillips EXPECT_TRUE(Mu.tryLock());
405f0f4e3aSMitch Phillips Mu.unlock();
415f0f4e3aSMitch Phillips
425f0f4e3aSMitch Phillips {
435f0f4e3aSMitch Phillips ScopedLock L(Mu);
445f0f4e3aSMitch Phillips EXPECT_FALSE(Mu.tryLock()); // Check that the c'tor did lock.
455f0f4e3aSMitch Phillips
465f0f4e3aSMitch Phillips // Manually unlock and check that this succeeds.
475f0f4e3aSMitch Phillips Mu.unlock();
485f0f4e3aSMitch Phillips EXPECT_TRUE(Mu.tryLock()); // Manually lock.
495f0f4e3aSMitch Phillips }
505f0f4e3aSMitch Phillips EXPECT_TRUE(Mu.tryLock()); // Assert that the scoped destructor did unlock.
515f0f4e3aSMitch Phillips Mu.unlock();
525f0f4e3aSMitch Phillips }
535f0f4e3aSMitch Phillips
synchronousIncrementTask(std::atomic<bool> * StartingGun,Mutex * Mu,unsigned * Counter,unsigned NumIterations)545f0f4e3aSMitch Phillips static void synchronousIncrementTask(std::atomic<bool> *StartingGun, Mutex *Mu,
555f0f4e3aSMitch Phillips unsigned *Counter,
565f0f4e3aSMitch Phillips unsigned NumIterations) {
575f0f4e3aSMitch Phillips while (!StartingGun) {
585f0f4e3aSMitch Phillips // Wait for starting gun.
595f0f4e3aSMitch Phillips }
605f0f4e3aSMitch Phillips for (unsigned i = 0; i < NumIterations; ++i) {
615f0f4e3aSMitch Phillips ScopedLock L(*Mu);
625f0f4e3aSMitch Phillips (*Counter)++;
635f0f4e3aSMitch Phillips }
645f0f4e3aSMitch Phillips }
655f0f4e3aSMitch Phillips
runSynchronisedTest(unsigned NumThreads,unsigned CounterMax)665f0f4e3aSMitch Phillips static void runSynchronisedTest(unsigned NumThreads, unsigned CounterMax) {
675f0f4e3aSMitch Phillips std::vector<std::thread> Threads;
685f0f4e3aSMitch Phillips
695f0f4e3aSMitch Phillips ASSERT_TRUE(CounterMax % NumThreads == 0);
705f0f4e3aSMitch Phillips
715f0f4e3aSMitch Phillips std::atomic<bool> StartingGun{false};
725f0f4e3aSMitch Phillips Mutex Mu;
735f0f4e3aSMitch Phillips unsigned Counter = 0;
745f0f4e3aSMitch Phillips
755f0f4e3aSMitch Phillips for (unsigned i = 0; i < NumThreads; ++i)
765f0f4e3aSMitch Phillips Threads.emplace_back(synchronousIncrementTask, &StartingGun, &Mu, &Counter,
775f0f4e3aSMitch Phillips CounterMax / NumThreads);
785f0f4e3aSMitch Phillips
795f0f4e3aSMitch Phillips StartingGun = true;
805f0f4e3aSMitch Phillips for (auto &T : Threads)
815f0f4e3aSMitch Phillips T.join();
825f0f4e3aSMitch Phillips
835f0f4e3aSMitch Phillips EXPECT_EQ(CounterMax, Counter);
845f0f4e3aSMitch Phillips }
855f0f4e3aSMitch Phillips
TEST(GwpAsanMutexTest,SynchronisedCounterTest)865f0f4e3aSMitch Phillips TEST(GwpAsanMutexTest, SynchronisedCounterTest) {
87365e5924SMitch Phillips runSynchronisedTest(4, 1000000);
88365e5924SMitch Phillips runSynchronisedTest(100, 1000000);
895f0f4e3aSMitch Phillips }
90