/* Copyright (c) 2020 Themaister * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include #include #include #include #include #include "thread_id.hpp" #ifdef PARALLEL_RDP_SHADER_DIR #include "global_managers.hpp" #endif namespace RDP { template class WorkerThread { public: explicit WorkerThread( #ifdef PARALLEL_RDP_SHADER_DIR Granite::Global::GlobalManagersHandle globals, #endif Executor exec) : executor(std::move(exec)) #ifdef PARALLEL_RDP_SHADER_DIR , handles(std::move(globals)) #endif { thr = std::thread(&WorkerThread::main_loop, this); } ~WorkerThread() { if (thr.joinable()) { { std::lock_guard holder{to_thread_mutex}; work_queue.push({}); to_thread_cond.notify_one(); } thr.join(); } } template void wait(Cond &&cond) { std::unique_lock holder{to_main_mutex}; to_main_cond.wait(holder, std::forward(cond)); } void push(T &&t) { std::lock_guard holder{to_thread_mutex}; work_queue.push(std::move(t)); to_thread_cond.notify_one(); } private: std::thread thr; std::mutex to_thread_mutex; std::condition_variable to_thread_cond; std::mutex to_main_mutex; std::condition_variable to_main_cond; std::queue work_queue; Executor executor; #ifdef PARALLEL_RDP_SHADER_DIR Granite::Global::GlobalManagersHandle handles; #endif void main_loop() { #ifdef PARALLEL_RDP_SHADER_DIR Granite::Global::set_thread_context(*handles); handles.reset(); #endif // Avoid benign errors in logging. // This thread never actually needs the thread ID. Util::register_thread_index(0); for (;;) { T value; { std::unique_lock holder{to_thread_mutex}; to_thread_cond.wait(holder, [this]() { return !work_queue.empty(); }); value = std::move(work_queue.front()); work_queue.pop(); } if (executor.is_sentinel(value)) break; executor.perform_work(value); std::lock_guard holder{to_main_mutex}; executor.notify_work_locked(value); to_main_cond.notify_one(); } } }; }