GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 1 / 0 / 1
Functions: 100.0% 1 / 0 / 1
Branches: -% 0 / 0 / 0

include/DetourModKit/worker.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_WORKER_HPP
2 #define DETOURMODKIT_WORKER_HPP
3
4 /**
5 * @file worker.hpp
6 * @brief RAII wrapper around std::jthread with a named stop signal.
7 */
8
9 #include <atomic>
10 #include <functional>
11 #include <stop_token>
12 #include <string>
13 #include <string_view>
14 #include <thread>
15
16 namespace DetourModKit
17 {
18 /**
19 * @class StoppableWorker
20 * @brief RAII-owned named background worker built on std::jthread.
21 * @details The body receives a std::stop_token and must poll it
22 * cooperatively. On destruction the worker requests stop and
23 * joins the thread, unless it detects that the current thread
24 * is executing under the Windows loader lock -- in which case
25 * the thread is detached to avoid deadlock. Callers that need
26 * to preempt the loader-lock case should call request_stop()
27 * and join() from a thread outside DllMain prior to teardown.
28 *
29 * Non-copyable and non-movable: the name, stop state, and
30 * thread handle form a single invariant. Copying would
31 * duplicate the thread handle; moving would race with a
32 * running body.
33 */
34 class StoppableWorker
35 {
36 public:
37 /**
38 * @brief Starts a new worker thread running the supplied body.
39 * @param name Descriptive name for logging. Copied into the worker.
40 * @param body Invocable receiving a stop_token. Must return promptly
41 * when stop_requested() becomes true.
42 */
43 StoppableWorker(std::string_view name,
44 std::function<void(std::stop_token)> body);
45
46 ~StoppableWorker() noexcept;
47
48 StoppableWorker(const StoppableWorker &) = delete;
49 StoppableWorker &operator=(const StoppableWorker &) = delete;
50 StoppableWorker(StoppableWorker &&) = delete;
51 StoppableWorker &operator=(StoppableWorker &&) = delete;
52
53 /**
54 * @brief Signals the worker to stop cooperatively.
55 * @details Idempotent. Does not block.
56 */
57 void request_stop() noexcept;
58
59 /**
60 * @brief Returns true while the worker thread is still joinable.
61 */
62 [[nodiscard]] bool is_running() const noexcept;
63
64 /**
65 * @brief Returns the worker's descriptive name.
66 */
67 2 [[nodiscard]] const std::string &name() const noexcept { return name_; }
68
69 /**
70 * @brief Requests stop and joins the worker thread.
71 * @details Safe to call multiple times. If invoked under the
72 * Windows loader lock the thread is detached instead of
73 * joined (documented trade-off -- the pinned module
74 * keeps code pages alive).
75 */
76 void shutdown() noexcept;
77
78 private:
79 std::string name_;
80 std::jthread thread_;
81 std::atomic<bool> joined_{false};
82 };
83 } // namespace DetourModKit
84
85 #endif // DETOURMODKIT_WORKER_HPP
86