1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
/*
* Copyright (c) 2023 The Khronos Group Inc.
* Copyright (c) 2023 Valve Corporation
* Copyright (c) 2023 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#pragma once
#include "layer_validation_tests.h"
// Helper class that fails the tests with a stuck worker thread.
// Its purpose is similar to an assert. We assume the code is correct.
// Then, in case of a bug or regression, the CI will continue to operate.
// Usage Example:
// TEST_F(VkLayerTest, MyTrickyTestWithThreads) {
// // The constructor parameter is the number of the worker threads
// ThreadTimeoutHelper timeout_helper(2);
// auto worker = [&]() {
// auto timeout_guard = timeout_helper.ThreadGuard();
// // Some code here
// };
// std::thread t0(worker);
// std::thread t1(worker);
// if (!timeout_helper.WaitForThreads(60)) ADD_FAILURE() << "It's time to move on";
// t0.join();
// t1.join();
// }
class ThreadTimeoutHelper {
public:
explicit ThreadTimeoutHelper(int thread_count = 1) : active_threads_(thread_count) {}
bool WaitForThreads(int timeout_in_seconds);
struct Guard {
Guard(ThreadTimeoutHelper &timeout_helper) : timeout_helper_(timeout_helper) {}
Guard(const Guard &) = delete;
Guard &operator=(const Guard &) = delete;
~Guard() { timeout_helper_.OnThreadDone(); }
ThreadTimeoutHelper &timeout_helper_;
};
// Mandatory elision of copy/move operations guarantees the destructor is not called
// (even in the presence of copy/move constructor) and the object is constructed directly
// into the destination storage: https://en.cppreference.com/w/cpp/language/copy_elision
Guard ThreadGuard() { return Guard(*this); }
private:
void OnThreadDone();
std::mutex active_thread_mutex_;
int active_threads_;
std::condition_variable cv_;
std::mutex mutex_;
};
#if GTEST_IS_THREADSAFE
struct ThreadTestData {
VkCommandBuffer commandBuffer;
VkDevice device;
VkEvent event;
VkDescriptorSet descriptorSet;
VkBuffer buffer;
uint32_t binding;
std::atomic<bool> *bailout;
};
void AddToCommandBuffer(ThreadTestData *);
void UpdateDescriptor(ThreadTestData *);
#endif // GTEST_IS_THREADSAFE
void ReleaseNullFence(ThreadTestData *);
|