Skip to content

Commit 4280222

Browse files
committed
[Unittests] Add more threading library tests.
Added explicit tests for `swift::once` and also for the ulock implementation used on Linux. rdar://90776105
1 parent ddea8b1 commit 4280222

File tree

6 files changed

+315
-152
lines changed

6 files changed

+315
-152
lines changed

unittests/Threading/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
add_swift_unittest(SwiftThreadingTests
22
Mutex.cpp
3+
Once.cpp
4+
LinuxUlock.cpp
35
)
46

57
target_link_libraries(SwiftThreadingTests

unittests/Threading/LinuxUlock.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===--- LinuxULock.cpp - Tests the Linux ulock implementation ------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if SWIFT_THREADING_LINUX
14+
15+
#include "swift/Threading/Impl/Linux/ulock.h"
16+
#include "gtest/gtest.h"
17+
18+
#include "LockingHelpers.h"
19+
20+
using namespace swift;
21+
using namespace swift::threading_impl;
22+
23+
// -----------------------------------------------------------------------------
24+
25+
// Use the existing locking tests to check threaded operation
26+
class UlockMutex {
27+
private:
28+
linux::ulock_t lock_;
29+
30+
public:
31+
UlockMutex() : lock_(0) {}
32+
33+
void lock() { linux::ulock_lock(&lock); }
34+
void unlock() { linux::ulock_unlock(&lock); }
35+
bool try_lock() { return linux::ulock_trylock(&lock); }
36+
};
37+
38+
TEST(LinuxUlockTest, SingleThreaded) {
39+
UlockMutex mutex;
40+
basicLockable(mutex);
41+
}
42+
43+
TEST(LinuxUlockTest, SingleThreadedTryLock) {
44+
UlockMutex mutex;
45+
tryLockable(mutex);
46+
}
47+
48+
TEST(LinuxULockTest, BasicLockableThreaded) {
49+
UlockMutex mutex;
50+
basicLockableThreaded(mutex);
51+
}
52+
53+
TEST(LinuxULockTest, LockableThreaded) {
54+
UlockMutex mutex;
55+
lockableThreaded(mutex);
56+
}
57+
58+
#endif // SWIFT_THREADING_LINUX

unittests/Threading/LockingHelpers.h

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//===--- LockingHelpers.h - Utilities to help test locks ------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LOCKING_HELPERS_H
14+
#define LOCKING_HELPERS_H
15+
16+
#include "ThreadingHelpers.h"
17+
18+
// Test that a Mutex object can be locked and unlocked from a single thread
19+
template <typename M> void basicLockable(M &mutex) {
20+
// We can lock, unlock, lock and unlock an unlocked lock
21+
mutex.lock();
22+
mutex.unlock();
23+
mutex.lock();
24+
mutex.unlock();
25+
}
26+
27+
// Test that a Mutex object's try_lock() method works.
28+
template <typename M> void tryLockable(M &mutex) {
29+
bool ret;
30+
31+
// We can lock an unlocked lock
32+
ret = mutex.try_lock();
33+
ASSERT_TRUE(ret);
34+
35+
// We cannot lock a locked lock
36+
ret = mutex.try_lock();
37+
ASSERT_FALSE(ret);
38+
39+
mutex.unlock();
40+
}
41+
42+
// Test that a Mutex object can be locked and unlocked
43+
template <typename M> void basicLockableThreaded(M &mutex) {
44+
int count1 = 0;
45+
int count2 = 0;
46+
47+
threadedExecute(10, [&](int) {
48+
for (int j = 0; j < 50; ++j) {
49+
mutex.lock();
50+
auto count = count2;
51+
count1++;
52+
count2 = count + 1;
53+
mutex.unlock();
54+
}
55+
});
56+
57+
ASSERT_EQ(count1, 500);
58+
ASSERT_EQ(count2, 500);
59+
}
60+
61+
// More extensive tests
62+
template <typename M> void lockableThreaded(M &mutex) {
63+
mutex.lock();
64+
threadedExecute(5, [&](int) { ASSERT_FALSE(mutex.try_lock()); });
65+
mutex.unlock();
66+
threadedExecute(1, [&](int) {
67+
ASSERT_TRUE(mutex.try_lock());
68+
mutex.unlock();
69+
});
70+
71+
int count1 = 0;
72+
int count2 = 0;
73+
threadedExecute(10, [&](int) {
74+
for (int j = 0; j < 50; ++j) {
75+
if (mutex.try_lock()) {
76+
auto count = count2;
77+
count1++;
78+
count2 = count + 1;
79+
mutex.unlock();
80+
} else {
81+
j--;
82+
}
83+
}
84+
});
85+
86+
ASSERT_EQ(count1, 500);
87+
ASSERT_EQ(count2, 500);
88+
}
89+
90+
// Test a scoped lock implementation
91+
template <typename SL, typename M> void scopedLockThreaded(M &mutex) {
92+
int count1 = 0;
93+
int count2 = 0;
94+
95+
threadedExecute(10, [&](int) {
96+
for (int j = 0; j < 50; ++j) {
97+
SL guard(mutex);
98+
auto count = count2;
99+
count1++;
100+
count2 = count + 1;
101+
}
102+
});
103+
104+
ASSERT_EQ(count1, 500);
105+
ASSERT_EQ(count2, 500);
106+
}
107+
108+
// Test a scoped unlock nested in a scoped lock
109+
template <typename SL, typename SU, typename M>
110+
void scopedUnlockUnderScopedLockThreaded(M &mutex) {
111+
int count1 = 0;
112+
int count2 = 0;
113+
int badCount = 0;
114+
115+
threadedExecute(10, [&](int) {
116+
for (int j = 0; j < 50; ++j) {
117+
SL guard(mutex);
118+
{
119+
SU unguard(mutex);
120+
badCount++;
121+
}
122+
auto count = count2;
123+
count1++;
124+
count2 = count + 1;
125+
}
126+
});
127+
128+
ASSERT_EQ(count1, 500);
129+
ASSERT_EQ(count2, 500);
130+
}
131+
132+
// Test a critical section
133+
template <typename M> void criticalSectionThreaded(M &mutex) {
134+
int count1 = 0;
135+
int count2 = 0;
136+
137+
threadedExecute(10, [&](int) {
138+
for (int j = 0; j < 50; ++j) {
139+
mutex.withLock([&] {
140+
auto count = count2;
141+
count1++;
142+
count2 = count + 1;
143+
});
144+
}
145+
});
146+
147+
ASSERT_EQ(count1, 500);
148+
ASSERT_EQ(count2, 500);
149+
}
150+
151+
#endif

0 commit comments

Comments
 (0)