Skip to content

Commit 1e5f275

Browse files
authored
[libc++] Refactor the tests for mutex, recursive mutex and their timed counterparts (llvm#104852)
This refactoring is done to remove flakyness as described in llvm#89083.
1 parent 40eca60 commit 1e5f275

24 files changed

+838
-478
lines changed
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,15 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// UNSUPPORTED: no-threads
10+
911
// <mutex>
1012

1113
// class mutex;
1214

1315
// mutex& operator=(const mutex&) = delete;
1416

1517
#include <mutex>
18+
#include <type_traits>
1619

17-
int main(int, char**)
18-
{
19-
std::mutex m0;
20-
std::mutex m1;
21-
m1 = m0;
22-
23-
return 0;
24-
}
20+
static_assert(!std::is_copy_assignable<std::mutex>::value, "");
Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// UNSUPPORTED: no-threads
10+
911
// <mutex>
1012

1113
// class mutex;
1214

1315
// mutex(const mutex&) = delete;
1416

1517
#include <mutex>
18+
#include <type_traits>
1619

17-
int main(int, char**)
18-
{
19-
std::mutex m0;
20-
std::mutex m1(m0);
21-
22-
return 0;
23-
}
20+
static_assert(!std::is_copy_constructible<std::mutex>::value, "");
Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,28 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8-
//
8+
99
// UNSUPPORTED: no-threads
1010

1111
// <mutex>
1212

1313
// class mutex;
1414

15-
// mutex();
15+
// mutex() noexcept;
1616

1717
#include <mutex>
18+
#include <cassert>
1819
#include <type_traits>
1920

20-
#include "test_macros.h"
21+
static_assert(std::is_nothrow_default_constructible<std::mutex>::value, "");
22+
23+
int main(int, char**) {
24+
// The mutex is unlocked after default construction
25+
{
26+
std::mutex m;
27+
assert(m.try_lock());
28+
m.unlock();
29+
}
2130

22-
int main(int, char**)
23-
{
24-
static_assert(std::is_nothrow_default_constructible<std::mutex>::value, "");
25-
std::mutex m;
26-
((void)m);
2731
return 0;
2832
}

libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/lock.pass.cpp

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,77 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8-
//
8+
9+
// UNSUPPORTED: c++03
910
// UNSUPPORTED: no-threads
10-
// ALLOW_RETRIES: 2
1111

1212
// <mutex>
1313

1414
// class mutex;
1515

1616
// void lock();
1717

18-
#include <cassert>
19-
#include <chrono>
20-
#include <cstdlib>
2118
#include <mutex>
19+
#include <atomic>
20+
#include <cassert>
2221
#include <thread>
22+
#include <vector>
2323

2424
#include "make_test_thread.h"
25-
#include "test_macros.h"
2625

27-
std::mutex m;
28-
29-
typedef std::chrono::system_clock Clock;
30-
typedef Clock::time_point time_point;
31-
typedef Clock::duration duration;
32-
typedef std::chrono::milliseconds ms;
33-
typedef std::chrono::nanoseconds ns;
34-
35-
void f()
36-
{
37-
time_point t0 = Clock::now();
26+
int main(int, char**) {
27+
// Lock a mutex that is not locked yet. This should succeed.
28+
{
29+
std::mutex m;
3830
m.lock();
39-
time_point t1 = Clock::now();
4031
m.unlock();
41-
ns d = t1 - t0 - ms(250);
42-
assert(d < ms(50)); // within 50ms
43-
}
32+
}
4433

45-
int main(int, char**)
46-
{
34+
// Lock a mutex that is already locked. This should block until it is unlocked.
35+
{
36+
std::atomic<bool> ready(false);
37+
std::mutex m;
4738
m.lock();
48-
std::thread t = support::make_test_thread(f);
49-
std::this_thread::sleep_for(ms(250));
39+
std::atomic<bool> is_locked_from_main(true);
40+
41+
std::thread t = support::make_test_thread([&] {
42+
ready = true;
43+
m.lock();
44+
assert(!is_locked_from_main);
45+
m.unlock();
46+
});
47+
48+
while (!ready)
49+
/* spin */;
50+
51+
// We would rather signal this after we unlock, but that would create a race condition.
52+
// We instead signal it before we unlock, which means that it's technically possible for
53+
// the thread to take the lock while main is still holding it yet for the test to still pass.
54+
is_locked_from_main = false;
5055
m.unlock();
56+
5157
t.join();
58+
}
59+
60+
// Make sure that at most one thread can acquire the mutex concurrently.
61+
{
62+
std::atomic<int> counter(0);
63+
std::mutex mutex;
64+
65+
std::vector<std::thread> threads;
66+
for (int i = 0; i != 10; ++i) {
67+
threads.push_back(support::make_test_thread([&] {
68+
mutex.lock();
69+
counter++;
70+
assert(counter == 1);
71+
counter--;
72+
mutex.unlock();
73+
}));
74+
}
75+
76+
for (auto& t : threads)
77+
t.join();
78+
}
5279

5380
return 0;
5481
}

libcxx/test/std/thread/thread.mutex/thread.mutex.requirements/thread.mutex.requirements.mutex/thread.mutex.class/try_lock.pass.cpp

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,46 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8-
//
8+
9+
// UNSUPPORTED: c++03
910
// UNSUPPORTED: no-threads
10-
// ALLOW_RETRIES: 2
1111

1212
// <mutex>
1313

1414
// class mutex;
1515

1616
// bool try_lock();
1717

18-
#include <cassert>
19-
#include <chrono>
20-
#include <cstdlib>
2118
#include <mutex>
19+
#include <cassert>
2220
#include <thread>
2321

2422
#include "make_test_thread.h"
25-
#include "test_macros.h"
26-
27-
std::mutex m;
28-
29-
typedef std::chrono::system_clock Clock;
30-
typedef Clock::time_point time_point;
31-
typedef Clock::duration duration;
32-
typedef std::chrono::milliseconds ms;
33-
typedef std::chrono::nanoseconds ns;
34-
35-
void f()
36-
{
37-
time_point t0 = Clock::now();
38-
assert(!m.try_lock());
39-
assert(!m.try_lock());
40-
assert(!m.try_lock());
41-
while(!m.try_lock())
42-
;
43-
time_point t1 = Clock::now();
23+
24+
int main(int, char**) {
25+
// Try to lock a mutex that is not locked yet. This should succeed.
26+
{
27+
std::mutex m;
28+
bool succeeded = m.try_lock();
29+
assert(succeeded);
4430
m.unlock();
45-
ns d = t1 - t0 - ms(250);
46-
assert(d < ms(200)); // within 200ms
47-
}
31+
}
4832

49-
int main(int, char**)
50-
{
33+
// Try to lock a mutex that is already locked. This should fail.
34+
{
35+
std::mutex m;
5136
m.lock();
52-
std::thread t = support::make_test_thread(f);
53-
std::this_thread::sleep_for(ms(250));
54-
m.unlock();
37+
38+
std::thread t = support::make_test_thread([&] {
39+
for (int i = 0; i != 10; ++i) {
40+
bool succeeded = m.try_lock();
41+
assert(!succeeded);
42+
}
43+
});
5544
t.join();
5645

46+
m.unlock();
47+
}
48+
5749
return 0;
5850
}
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,15 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// UNSUPPORTED: no-threads
10+
911
// <mutex>
1012

1113
// class recursive_mutex;
1214

1315
// recursive_mutex& operator=(const recursive_mutex&) = delete;
1416

1517
#include <mutex>
18+
#include <type_traits>
1619

17-
int main(int, char**)
18-
{
19-
std::recursive_mutex m0;
20-
std::recursive_mutex m1;
21-
m1 = m0;
22-
23-
return 0;
24-
}
20+
static_assert(!std::is_copy_assignable<std::recursive_mutex>::value, "");
Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// UNSUPPORTED: no-threads
10+
911
// <mutex>
1012

1113
// class recursive_mutex;
1214

1315
// recursive_mutex(const recursive_mutex&) = delete;
1416

1517
#include <mutex>
18+
#include <type_traits>
1619

17-
int main(int, char**)
18-
{
19-
std::recursive_mutex m0;
20-
std::recursive_mutex m1(m0);
21-
22-
return 0;
23-
}
20+
static_assert(!std::is_copy_constructible<std::recursive_mutex>::value, "");
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
8-
//
8+
99
// UNSUPPORTED: no-threads
1010

1111
// <mutex>
@@ -15,12 +15,16 @@
1515
// recursive_mutex();
1616

1717
#include <mutex>
18+
#include <cassert>
19+
#include <type_traits>
1820

19-
#include "test_macros.h"
20-
21-
int main(int, char**)
22-
{
21+
int main(int, char**) {
22+
// The mutex is unlocked after default construction
23+
{
2324
std::recursive_mutex m;
25+
assert(m.try_lock());
26+
m.unlock();
27+
}
2428

2529
return 0;
2630
}

0 commit comments

Comments
 (0)