13 #include <boost/test/unit_test.hpp> 16 #include <condition_variable> 19 #include <unordered_set> 30 #ifdef DEBUG_LOCKCONTENTION 53 n_calls.fetch_add(1, std::memory_order_relaxed);
69 static std::unordered_multiset<size_t> results
GUARDED_BY(
m);
108 static std::condition_variable
cv;
119 std::unique_lock<std::mutex> l(
m);
120 nFrozen.store(1, std::memory_order_relaxed);
122 cv.wait(l, []{
return nFrozen.load(std::memory_order_relaxed) == 0;});
128 other.should_freeze =
false;
133 other.should_freeze =
false;
143 std::unordered_multiset<size_t> UniqueCheck::results;
164 std::vector<FakeCheckCheckCompletion> vChecks;
166 for (
const size_t i : range) {
173 total -= vChecks.size();
174 control.
Add(std::move(vChecks));
176 BOOST_REQUIRE(control.Wait());
179 small_queue->StopWorkerThreads();
186 std::vector<size_t> range;
187 range.push_back(
size_t{0});
194 std::vector<size_t> range;
195 range.push_back(
size_t{1});
202 std::vector<size_t> range;
203 range.push_back(100000);
210 std::vector<size_t> range;
211 range.reserve(100000/1000);
212 for (
size_t i = 2; i < 100000; i += std::max((
size_t)1, (
size_t)
InsecureRandRange(std::min((
size_t)1000, ((
size_t)100000) - i))))
224 for (
size_t i = 0; i < 1001; ++i) {
226 size_t remaining = i;
230 std::vector<FailingCheck> vChecks;
232 for (
size_t k = 0;
k < r && remaining;
k++, remaining--)
233 vChecks.emplace_back(remaining == 1);
234 control.Add(std::move(vChecks));
236 bool success = control.Wait();
238 BOOST_REQUIRE(!success);
240 BOOST_REQUIRE(success);
243 fail_queue->StopWorkerThreads();
252 for (
auto times = 0; times < 10; ++times) {
253 for (
const bool end_fails : {
true,
false}) {
256 std::vector<FailingCheck> vChecks;
257 vChecks.resize(100,
false);
258 vChecks[99] = end_fails;
259 control.
Add(std::move(vChecks));
261 bool r =control.Wait();
262 BOOST_REQUIRE(r != end_fails);
265 fail_queue->StopWorkerThreads();
276 size_t COUNT = 100000;
277 size_t total =
COUNT;
282 std::vector<UniqueCheck> vChecks;
283 for (
size_t k = 0;
k < r && total;
k++)
284 vChecks.emplace_back(--total);
285 control.Add(std::move(vChecks));
291 BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(),
COUNT);
292 for (
size_t i = 0; i <
COUNT; ++i) {
293 r = r && UniqueCheck::results.count(i) == 1;
297 queue->StopWorkerThreads();
310 for (
size_t i = 0; i < 1000; ++i) {
316 std::vector<MemoryCheck> vChecks;
317 for (
size_t k = 0;
k < r && total;
k++) {
321 vChecks.emplace_back(total == 0 || total == i || total == i/2);
323 control.Add(std::move(vChecks));
328 queue->StopWorkerThreads();
338 std::thread t0([&]() {
340 std::vector<FrozenCleanupCheck> vChecks(1);
341 control.Add(std::move(vChecks));
342 bool waitResult = control.Wait();
351 for (
auto x = 0; x < 100 && !fails; ++x) {
352 fails = queue->m_control_mutex.try_lock();
363 BOOST_REQUIRE(!fails);
364 queue->StopWorkerThreads();
373 std::vector<std::thread> tg;
374 std::atomic<int> nThreads {0};
375 std::atomic<int> fails {0};
376 for (
size_t i = 0; i < 3; ++i) {
381 auto observed = ++nThreads;
383 fails += observed != nThreads;
386 for (
auto& thread: tg) {
387 if (thread.joinable()) thread.join();
389 BOOST_REQUIRE_EQUAL(fails, 0);
392 std::vector<std::thread> tg;
394 std::condition_variable cv;
395 bool has_lock{
false};
396 bool has_tried{
false};
398 bool done_ack{
false};
400 std::unique_lock<std::mutex> l(
m);
403 std::unique_lock<std::mutex> ll(
m);
406 cv.wait(ll, [&]{
return has_tried;});
411 cv.wait(ll, [&]{
return done_ack;});
414 cv.wait(l, [&](){
return has_lock;});
416 for (
auto x = 0; x < 100 && !fails; ++x) {
417 fails = queue->m_control_mutex.try_lock();
421 cv.wait(l, [&](){
return done;});
425 BOOST_REQUIRE(!fails);
427 for (
auto& thread: tg) {
428 if (thread.joinable()) thread.join();
CCheckQueue< FakeCheckCheckCompletion > Correct_Queue
CCheckQueue< FakeCheck > Standard_Queue
static std::atomic< uint64_t > nFrozen
CCheckQueue< MemoryCheck > Memory_Queue
static std::atomic< size_t > n_calls
FrozenCleanupCheck(FrozenCleanupCheck &&other) noexcept
CCheckQueue< UniqueCheck > Unique_Queue
static const int SCRIPT_CHECK_THREADS
RAII-style controller object for a CCheckQueue that guarantees the passed queue is finished before co...
FailingCheck(bool _fails)
UniqueCheck(size_t check_id_in)
static uint64_t InsecureRandRange(uint64_t range)
NoLockLoggingTestingSetup()
static void Correct_Queue_range(std::vector< size_t > range)
This test case checks that the CCheckQueue works properly with each specified size_t Checks pushed...
BOOST_AUTO_TEST_SUITE_END()
CCheckQueue< FrozenCleanupCheck > FrozenCleanup_Queue
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
Test that 0 checks is correct.
static std::unordered_multiset< size_t > results GUARDED_BY(m)
Identical to TestingSetup but excludes lock contention logging if DEBUG_LOCKCONTENTION is defined...
Queue for verifications that have to be performed.
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
void UninterruptibleSleep(const std::chrono::microseconds &n)
FrozenCleanupCheck & operator=(FrozenCleanupCheck &&other) noexcept
static std::atomic< size_t > fake_allocated_memory
FrozenCleanupCheck()=default
static const unsigned int QUEUE_BATCH_SIZE
CCheckQueue< FailingCheck > Failing_Queue
MemoryCheck(const MemoryCheck &x)
static std::condition_variable cv
void Add(std::vector< T > &&vChecks)
Testing setup that configures a complete environment.