22#include <commons/display_info.hpp>
38#if THREADMAN_PLATFORM_APPLE || THREADMAN_PLATFORM_LINUX
49 static std::atomic<std::uint64_t> counter{1};
50 return counter.fetch_add(1, std::memory_order_relaxed);
54#if THREADMAN_PLATFORM_APPLE
55 std::uint64_t tid = 0;
56 pthread_threadid_np(
nullptr, &tid);
58#elif THREADMAN_PLATFORM_LINUX
59 return static_cast<std::uint64_t
>(pthread_self());
61 return static_cast<std::uint64_t
>(std::hash<std::thread::id>{}(std::this_thread::get_id()));
66#if THREADMAN_PLATFORM_APPLE
68 pthread_setname_np(name.substr(0, 63).c_str());
69#elif THREADMAN_PLATFORM_LINUX
71 pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
91 std::chrono::steady_clock::time_point
ended_at;
93 mutable std::mutex
mtx;
105 template <
class Fn,
class... Args>
106 requires(std::invocable<Fn, std::stop_token, Args...> || std::invocable<Fn, Args...>)
108 : cb_(std::make_shared<ControlBlock>()), opts_manager_(opts.
manager) {
110 cb_->name = std::move(opts.
name);
114 register_with_manager();
116 if constexpr (std::invocable<Fn, std::stop_token, Args...>) {
118 [cb = cb_, fn = std::forward<Fn>(fn), ... captured_args = std::forward<Args>(args)](
122 std::stop_token tok)
mutable {
125 fn(std::move(tok), std::move(captured_args)...);
128 exit_failed(cb, std::current_exception());
133 [cb = cb_, fn = std::forward<Fn>(fn), ... captured_args = std::forward<Args>(args)](
134 const std::stop_token&)
mutable {
137 fn(std::move(captured_args)...);
140 exit_failed(cb, std::current_exception());
156 [[nodiscard]] std::uint64_t
id() const noexcept {
157 return cb_ ? cb_->id : 0;
159 [[nodiscard]]
const std::string&
name() const noexcept {
160 static constexpr std::string empty;
161 return cb_ ? cb_->name : empty;
163 [[nodiscard]] std::uint64_t
native_id() const noexcept {
164 return cb_ ? cb_->native_id : 0;
166 [[nodiscard]] std::optional<std::uint64_t>
pool_id() const noexcept {
167 return cb_ ? cb_->pool_id : std::nullopt;
170 return cb_ ? cb_->is_core :
true;
175 [[nodiscard]]
bool failed() const noexcept {
183 return std::chrono::nanoseconds{0};
185 std::scoped_lock guard(cb_->mtx);
186 if (cb_->started_at.time_since_epoch().count() == 0) {
187 return std::chrono::nanoseconds{0};
189 const auto end = cb_->ended_at.time_since_epoch().count() == 0
190 ? std::chrono::steady_clock::now()
192 return end - cb_->started_at;
196 return jth_.get_stop_source();
199 return jth_.get_stop_token();
204 return jth_.request_stop();
207 return jth_.joinable();
218 return jth_.get_id();
221 [[nodiscard]] std::shared_ptr<ControlBlock>
control_block() const noexcept {
230 snap.
state = cb_->state.load(std::memory_order_acquire);
233 std::scoped_lock guard(cb_->mtx);
235 snap.
name = cb_->name;
250 static const comms::DisplayInfo info{
251 .name =
"ManagedThread",
252 .description =
"RAII wrapper around std::jthread with lifecycle "
253 "introspection and ThreadManager integration.",
254 .icon = comms::Icon::from(
"mdi:cog-outline"),
260 static ControlBlock*& current_cb() noexcept {
261 thread_local ControlBlock* tls =
nullptr;
265 static void enter(
const std::shared_ptr<ControlBlock>& cb)
noexcept {
266 current_cb() = cb.get();
267 const auto now = std::chrono::steady_clock::now();
269 if (!cb->name.empty()) {
273 std::scoped_lock guard(cb->mtx);
274 cb->started_at = now;
275 cb->native_id = native;
281 lg && lg->should_log(spdlog::level::debug)) {
282 lg->debug(
"started '{}' (id={}, native={})", cb->name, cb->id, native);
286 static void exit_completed(
const std::shared_ptr<ControlBlock>& cb)
noexcept {
288 std::scoped_lock guard(cb->mtx);
289 cb->ended_at = std::chrono::steady_clock::now();
294 current_cb() =
nullptr;
297 static void exit_failed(
const std::shared_ptr<ControlBlock>& cb,
298 const std::exception_ptr& ex)
noexcept {
299 std::string what_msg =
"(unknown exception)";
302 std::rethrow_exception(ex);
304 }
catch (
const std::exception& e) {
310 std::scoped_lock guard(cb->mtx);
311 cb->ended_at = std::chrono::steady_clock::now();
318 lg->warn(
"'{}' failed: {}", cb->name, what_msg);
320 current_cb() =
nullptr;
323 void register_with_manager();
326 std::shared_ptr<ControlBlock> cb_;
327 ThreadManager* opts_manager_ =
nullptr;
static ControlBlock * current() noexcept
Returns a pointer to the ControlBlock of the currently-executing ManagedThread, or nullptr when calle...
Definition thread.hpp:245
void join()
Definition thread.hpp:209
std::optional< std::uint64_t > pool_id() const noexcept
Definition thread.hpp:166
std::shared_ptr< ControlBlock > control_block() const noexcept
Definition thread.hpp:221
ManagedThread(Options opts, Fn &&fn, Args &&... args)
Construct a managed thread; fn may take an optional leading std::stop_token.
Definition thread.hpp:107
ManagedThread & operator=(const ManagedThread &)=delete
bool request_stop() noexcept
Request the thread to stop. The body sees tok.stop_requested().
Definition thread.hpp:203
void detach()
Definition thread.hpp:212
ManagedThread(const ManagedThread &)=delete
std::chrono::nanoseconds run_duration() const noexcept
Time elapsed since the worker body entered; once exited, the duration from started_at to ended_at.
Definition thread.hpp:181
std::stop_token get_stop_token() const noexcept
Definition thread.hpp:198
const std::string & name() const noexcept
Definition thread.hpp:159
std::uint64_t id() const noexcept
Definition thread.hpp:156
std::uint64_t native_id() const noexcept
Definition thread.hpp:163
ThreadSnapshot snapshot() const
Definition thread.hpp:225
bool failed() const noexcept
Definition thread.hpp:175
ThreadState state() const noexcept
Definition thread.hpp:172
bool is_core() const noexcept
Definition thread.hpp:169
std::thread::id native_thread_id() const noexcept
Underlying std::jthread::id().
Definition thread.hpp:217
static const comms::DisplayInfo & display_info()
Definition thread.hpp:249
std::stop_source get_stop_source() noexcept
Definition thread.hpp:195
bool joinable() const noexcept
Definition thread.hpp:206
void unregister_from_manager() noexcept
Definition manager.hpp:627
Definition manager.hpp:47
Central feature-gate header for ThreadMan's optional integrations and tunable defaults.
Re-export <commons/display_info.hpp> and attach non-intrusive comms::HasDisplayInfo<> specializations...
Cached subsystem loggers for the tm.
Cached subsystem metrics for the tm_* Prometheus/OpenMetrics families, mirroring the tm.
std::uint64_t next_thread_id() noexcept
Definition thread.hpp:48
std::uint64_t current_native_id() noexcept
Definition thread.hpp:53
void apply_native_name(const std::string &name) noexcept
Definition thread.hpp:65
std::shared_ptr< spdlog::logger > & thread()
Logger for tm.thread — ManagedThread lifecycle and faults.
Definition log.hpp:33
prom::Counter & threads_failed()
ManagedThread bodies that exited by throwing.
Definition metrics.hpp:167
prom::Gauge & threads_live()
ManagedThread bodies currently running (inc on enter, dec on exit).
Definition metrics.hpp:174
prom::Counter & threads_completed()
ManagedThread bodies that returned normally.
Definition metrics.hpp:159
prom::Counter & threads_created()
ManagedThread bodies that entered (started running).
Definition metrics.hpp:152
Definition exceptions.hpp:22
ThreadState
Lifecycle state of a ManagedThread / pool worker.
Definition stats.hpp:21
@ Completed
Body returned normally; thread joined or about to.
@ Running
User body is actively executing.
@ Starting
Constructed; user body not yet entered.
@ Failed
Body threw an exception; reason captured in ControlBlock.
Plain value snapshots of the live state of the ThreadMan world — threads, pools, tasks,...
Heap-resident publishing block — shared by the thread, the manager's registry (as weak_ptr),...
Definition thread.hpp:83
std::atomic< ThreadState > state
Definition thread.hpp:89
std::mutex mtx
Definition thread.hpp:93
std::chrono::steady_clock::time_point ended_at
Definition thread.hpp:91
std::uint64_t native_id
Definition thread.hpp:86
std::optional< std::uint64_t > pool_id
Definition thread.hpp:87
bool is_core
Definition thread.hpp:88
std::exception_ptr exception
Definition thread.hpp:92
std::chrono::steady_clock::time_point started_at
Definition thread.hpp:90
std::string name
Definition thread.hpp:85
bool is_core
Definition thread.hpp:99
ThreadManager * manager
Definition thread.hpp:100
std::string name
Definition thread.hpp:97
std::optional< std::uint64_t > pool_id
Definition thread.hpp:98
A point-in-time snapshot of a ManagedThread's control block.
Definition stats.hpp:48
bool failed
True iff state == Failed.
Definition stats.hpp:55
std::uint64_t native_id
OS-level thread id, when known.
Definition stats.hpp:51
std::string name
User-chosen name.
Definition stats.hpp:50
std::optional< std::uint64_t > pool_id
Owning pool, when this is a pool worker.
Definition stats.hpp:52
std::uint64_t id
Monotonic per-process id.
Definition stats.hpp:49
std::chrono::nanoseconds run_duration
Time the body has been running (or ran).
Definition stats.hpp:54
bool is_core
Pool worker: not subject to idle retirement.
Definition stats.hpp:56
ThreadState state
Definition stats.hpp:53