Files
clang-p2996/compiler-rt/lib/scudo/standalone/tests/mutex_test.cpp
Chia-hung Duan 6a4c39596d [scudo] Add the thread-safety annotations
This CL adds the proper thread-safety annotations for most of the
functions and variables. However, given the restriction of the current
architecture, in some cases, we may not be able to use the annotations
easily. The followings are two exceptions,

1. enable()/disable(): Many structures in scudo are enabled/disabled by
   acquiring the lock in each instance. This makes those structure act
   like a `lock`. We can't mark those functions with ACQUIRE()/RELEASE()
   because that makes the entire allocator become another `lock`. In the
   end, that implies we need to *acquire* the `allocator` before each
   malloc et al. request. Therefore, adding a variable to tell the
   status of those structures may be a better way to cooperate with
   thread-safety annotation.

2. TSD/TSD shared/TSD exclusive: These three have simiar restrictions as
   mentioned above. In addition, they don't always need to be released
   if it's a thread local instance. However, thread-safety analysis
   doesn't support conditional branch. Which means we can't mark the
   proper annotations around the uses of TSDs. We may consider to make
   it consistent and which makes the code structure simpler.

This CL is supposed to introduce the annotations with the least code
refactoring. So only trivial thread safety issues will be addressed
here. For example, lacking of acquiring certain lock before accessing
certain variables will have the ScopedLock inserted. Other than that,
they are supposed to be done in the later changes.

Reviewed By: cferris

Differential Revision: https://reviews.llvm.org/D140706
2023-02-15 01:19:51 +00:00

109 lines
2.6 KiB
C++

//===-- mutex_test.cpp ------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "tests/scudo_unit_test.h"
#include "mutex.h"
#include <pthread.h>
#include <string.h>
class TestData {
public:
explicit TestData(scudo::HybridMutex &M) : Mutex(M) {
for (scudo::u32 I = 0; I < Size; I++)
Data[I] = 0;
}
void write() {
scudo::ScopedLock L(Mutex);
T V0 = Data[0];
for (scudo::u32 I = 0; I < Size; I++) {
EXPECT_EQ(Data[I], V0);
Data[I]++;
}
}
void tryWrite() {
if (!Mutex.tryLock())
return;
T V0 = Data[0];
for (scudo::u32 I = 0; I < Size; I++) {
EXPECT_EQ(Data[I], V0);
Data[I]++;
}
Mutex.unlock();
}
void backoff() {
volatile T LocalData[Size] = {};
for (scudo::u32 I = 0; I < Size; I++) {
LocalData[I] = LocalData[I] + 1;
EXPECT_EQ(LocalData[I], 1U);
}
}
private:
static const scudo::u32 Size = 64U;
typedef scudo::u64 T;
scudo::HybridMutex &Mutex;
alignas(SCUDO_CACHE_LINE_SIZE) T Data[Size];
};
const scudo::u32 NumberOfThreads = 8;
#if SCUDO_DEBUG
const scudo::u32 NumberOfIterations = 4 * 1024;
#else
const scudo::u32 NumberOfIterations = 16 * 1024;
#endif
static void *lockThread(void *Param) {
TestData *Data = reinterpret_cast<TestData *>(Param);
for (scudo::u32 I = 0; I < NumberOfIterations; I++) {
Data->write();
Data->backoff();
}
return 0;
}
static void *tryThread(void *Param) {
TestData *Data = reinterpret_cast<TestData *>(Param);
for (scudo::u32 I = 0; I < NumberOfIterations; I++) {
Data->tryWrite();
Data->backoff();
}
return 0;
}
TEST(ScudoMutexTest, Mutex) {
scudo::HybridMutex M;
TestData Data(M);
pthread_t Threads[NumberOfThreads];
for (scudo::u32 I = 0; I < NumberOfThreads; I++)
pthread_create(&Threads[I], 0, lockThread, &Data);
for (scudo::u32 I = 0; I < NumberOfThreads; I++)
pthread_join(Threads[I], 0);
}
TEST(ScudoMutexTest, MutexTry) {
scudo::HybridMutex M;
TestData Data(M);
pthread_t Threads[NumberOfThreads];
for (scudo::u32 I = 0; I < NumberOfThreads; I++)
pthread_create(&Threads[I], 0, tryThread, &Data);
for (scudo::u32 I = 0; I < NumberOfThreads; I++)
pthread_join(Threads[I], 0);
}
TEST(ScudoMutexTest, MutexAssertHeld) {
scudo::HybridMutex M;
M.lock();
M.assertHeld();
M.unlock();
}