xref: /llvm-project/compiler-rt/lib/gwp_asan/tests/mutex_test.cpp (revision 5556616b5b5223f95607ad94053a55f0deaf2762)
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