Skip to content

Commit

Permalink
[libc++] Refactor the tests for mutex, recursive mutex and their time…
Browse files Browse the repository at this point in the history
…d counterparts (#104852)

This refactoring is done to remove flakyness as described in
#89083.
  • Loading branch information
ldionne authored Aug 21, 2024
1 parent 40eca60 commit 1e5f275
Show file tree
Hide file tree
Showing 24 changed files with 838 additions and 478 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,15 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: no-threads

// <mutex>

// class mutex;

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

#include <mutex>
#include <type_traits>

int main(int, char**)
{
std::mutex m0;
std::mutex m1;
m1 = m0;

return 0;
}
static_assert(!std::is_copy_assignable<std::mutex>::value, "");
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: no-threads

// <mutex>

// class mutex;

// mutex(const mutex&) = delete;

#include <mutex>
#include <type_traits>

int main(int, char**)
{
std::mutex m0;
std::mutex m1(m0);

return 0;
}
static_assert(!std::is_copy_constructible<std::mutex>::value, "");
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//

// UNSUPPORTED: no-threads

// <mutex>

// class mutex;

// mutex();
// mutex() noexcept;

#include <mutex>
#include <cassert>
#include <type_traits>

#include "test_macros.h"
static_assert(std::is_nothrow_default_constructible<std::mutex>::value, "");

int main(int, char**) {
// The mutex is unlocked after default construction
{
std::mutex m;
assert(m.try_lock());
m.unlock();
}

int main(int, char**)
{
static_assert(std::is_nothrow_default_constructible<std::mutex>::value, "");
std::mutex m;
((void)m);
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,77 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//

// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
// ALLOW_RETRIES: 2

// <mutex>

// class mutex;

// void lock();

#include <cassert>
#include <chrono>
#include <cstdlib>
#include <mutex>
#include <atomic>
#include <cassert>
#include <thread>
#include <vector>

#include "make_test_thread.h"
#include "test_macros.h"

std::mutex m;

typedef std::chrono::system_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::duration duration;
typedef std::chrono::milliseconds ms;
typedef std::chrono::nanoseconds ns;

void f()
{
time_point t0 = Clock::now();
int main(int, char**) {
// Lock a mutex that is not locked yet. This should succeed.
{
std::mutex m;
m.lock();
time_point t1 = Clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
assert(d < ms(50)); // within 50ms
}
}

int main(int, char**)
{
// Lock a mutex that is already locked. This should block until it is unlocked.
{
std::atomic<bool> ready(false);
std::mutex m;
m.lock();
std::thread t = support::make_test_thread(f);
std::this_thread::sleep_for(ms(250));
std::atomic<bool> is_locked_from_main(true);

std::thread t = support::make_test_thread([&] {
ready = true;
m.lock();
assert(!is_locked_from_main);
m.unlock();
});

while (!ready)
/* spin */;

// We would rather signal this after we unlock, but that would create a race condition.
// We instead signal it before we unlock, which means that it's technically possible for
// the thread to take the lock while main is still holding it yet for the test to still pass.
is_locked_from_main = false;
m.unlock();

t.join();
}

// Make sure that at most one thread can acquire the mutex concurrently.
{
std::atomic<int> counter(0);
std::mutex mutex;

std::vector<std::thread> threads;
for (int i = 0; i != 10; ++i) {
threads.push_back(support::make_test_thread([&] {
mutex.lock();
counter++;
assert(counter == 1);
counter--;
mutex.unlock();
}));
}

for (auto& t : threads)
t.join();
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,46 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//

// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
// ALLOW_RETRIES: 2

// <mutex>

// class mutex;

// bool try_lock();

#include <cassert>
#include <chrono>
#include <cstdlib>
#include <mutex>
#include <cassert>
#include <thread>

#include "make_test_thread.h"
#include "test_macros.h"

std::mutex m;

typedef std::chrono::system_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::duration duration;
typedef std::chrono::milliseconds ms;
typedef std::chrono::nanoseconds ns;

void f()
{
time_point t0 = Clock::now();
assert(!m.try_lock());
assert(!m.try_lock());
assert(!m.try_lock());
while(!m.try_lock())
;
time_point t1 = Clock::now();

int main(int, char**) {
// Try to lock a mutex that is not locked yet. This should succeed.
{
std::mutex m;
bool succeeded = m.try_lock();
assert(succeeded);
m.unlock();
ns d = t1 - t0 - ms(250);
assert(d < ms(200)); // within 200ms
}
}

int main(int, char**)
{
// Try to lock a mutex that is already locked. This should fail.
{
std::mutex m;
m.lock();
std::thread t = support::make_test_thread(f);
std::this_thread::sleep_for(ms(250));
m.unlock();

std::thread t = support::make_test_thread([&] {
for (int i = 0; i != 10; ++i) {
bool succeeded = m.try_lock();
assert(!succeeded);
}
});
t.join();

m.unlock();
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,15 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: no-threads

// <mutex>

// class recursive_mutex;

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

#include <mutex>
#include <type_traits>

int main(int, char**)
{
std::recursive_mutex m0;
std::recursive_mutex m1;
m1 = m0;

return 0;
}
static_assert(!std::is_copy_assignable<std::recursive_mutex>::value, "");
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: no-threads

// <mutex>

// class recursive_mutex;

// recursive_mutex(const recursive_mutex&) = delete;

#include <mutex>
#include <type_traits>

int main(int, char**)
{
std::recursive_mutex m0;
std::recursive_mutex m1(m0);

return 0;
}
static_assert(!std::is_copy_constructible<std::recursive_mutex>::value, "");
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//

// UNSUPPORTED: no-threads

// <mutex>
Expand All @@ -15,12 +15,16 @@
// recursive_mutex();

#include <mutex>
#include <cassert>
#include <type_traits>

#include "test_macros.h"

int main(int, char**)
{
int main(int, char**) {
// The mutex is unlocked after default construction
{
std::recursive_mutex m;
assert(m.try_lock());
m.unlock();
}

return 0;
}
Loading

0 comments on commit 1e5f275

Please sign in to comment.