Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
// UNSUPPORTED: c++03, c++11, c++14

Expand All @@ -16,12 +16,6 @@
// shared_mutex& operator=(const shared_mutex&) = delete;

#include <shared_mutex>
#include <type_traits>

int main(int, char**)
{
std::shared_mutex m0;
std::shared_mutex m1;
m1 = m0; // expected-error {{overload resolution selected deleted operator '='}}

return 0;
}
static_assert(!std::is_copy_assignable<std::shared_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
// UNSUPPORTED: c++03, c++11, c++14

Expand All @@ -16,11 +16,6 @@
// shared_mutex(const shared_mutex&) = delete;

#include <shared_mutex>
#include <type_traits>

int main(int, char**)
{
std::shared_mutex m0;
std::shared_mutex m1(m0); // expected-error {{call to deleted constructor of 'std::shared_mutex'}}

return 0;
}
static_assert(!std::is_copy_constructible<std::shared_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
// UNSUPPORTED: c++03, c++11, c++14

Expand All @@ -19,10 +19,9 @@

#include "test_macros.h"

int main(int, char**)
{
std::shared_mutex m;
(void)m;
int main(int, char**) {
std::shared_mutex m;
(void)m;

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

// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03, c++11, c++14

// ALLOW_RETRIES: 2

// <shared_mutex>

// class shared_mutex;

// void lock();

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

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

std::shared_mutex m;
int main(int, char**) {
// Exclusive-lock a mutex that is not locked yet. This should succeed.
{
std::shared_mutex m;
m.lock();
m.unlock();
}

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;
// Exclusive-lock a mutex that is already locked exclusively. This should block until it is unlocked.
{
std::atomic<bool> ready(false);
std::shared_mutex m;
m.lock();
std::atomic<bool> is_locked_from_main(true);

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

// Thread sanitizer causes more overhead and will sometimes cause this test
// to fail. To prevent this we give Thread sanitizer more time to complete the
// test.
#if !defined(TEST_IS_EXECUTED_IN_A_SLOW_ENVIRONMENT)
ms Tolerance = ms(50);
#else
ms Tolerance = ms(50 * 5);
#endif
while (!ready)
/* spin */;

void f()
{
time_point t0 = Clock::now();
m.lock();
time_point t1 = Clock::now();
// 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 we're still holding it and for the test to still pass.
is_locked_from_main = false;
m.unlock();
ns d = t1 - t0 - WaitTime;
assert(d < Tolerance); // within tolerance
}

int main(int, char**)
{
m.lock();
std::thread t = support::make_test_thread(f);
std::this_thread::sleep_for(WaitTime);
m.unlock();
t.join();
}

// Exclusive-lock a mutex that is already share-locked. This should block until it is unlocked.
{
std::atomic<bool> ready(false);
std::shared_mutex m;
m.lock_shared();
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 we're still holding it and for the test to still pass.
is_locked_from_main = false;
m.unlock_shared();

t.join();
}

// Make sure that at most one thread can acquire the mutex concurrently.
{
std::atomic<int> counter = 0;
std::shared_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;
}
Loading