27class composite_thread_registry;
48class auto_register_current_thread;
49class global_registry_binding;
72 bool const keep_global_proxy = global_;
73 auto*
const current = owned_.get();
75 retired_.reserve(retired_.size() + (owned_ !=
nullptr ? 1u : 0u) + other.retired_.size());
76 bindings_.reserve(bindings_.size() + other.bindings_.size());
81 if (owned_ !=
nullptr)
82 retired_.push_back(std::move(owned_));
83 for (
auto& backend : other.retired_)
84 retired_.push_back(std::move(backend));
85 other.retired_.clear();
86 for (
auto& binding : other.bindings_)
87 bindings_.push_back(std::move(binding));
88 other.bindings_.clear();
89 owned_ = std::move(other.owned_);
91 if (keep_global_proxy)
100 state->replace(owned_);
103 std::make_shared<detail::external_registry_binding_state>(owned_));
112 state->replace(owned_);
114 global_ = other.global_;
138 return unexpected(std::make_error_code(std::errc::operation_canceled));
140 [&]() -> result<void>
143 native().register_current_thread(control, std::move(name), std::move(component));
153 return unexpected(std::make_error_code(std::errc::operation_canceled));
157 native().unregister_current_thread();
166 return has_native() ? native().count() : 0;
173 return !has_native() || native().empty();
184 return std::vector<registered_thread>{};
186 [&]() ->
result<std::vector<registered_thread>>
188 auto entries = native().query().entries();
189 std::vector<registered_thread> result_entries;
190 result_entries.reserve(entries.size());
191 for (
auto const& entry : entries)
194 entry.std_id, entry.name, entry.component, entry.alive });
196 return result_entries;
209 return unexpected(std::make_error_code(std::errc::operation_canceled));
210 auto const native_id = checked_native_id(
id);
229 return unexpected(std::make_error_code(std::errc::operation_canceled));
230 auto const native_id = checked_native_id(
id);
243 return unexpected(std::make_error_code(std::errc::operation_canceled));
244 auto const native_id = checked_native_id(
id);
250 auto value = native().get_nice_value(native_id.value());
262 return unexpected(std::make_error_code(std::errc::operation_canceled));
263 auto const native_id = checked_native_id(
id);
269 auto value = native().get_nice_value(native_id.value());
270 return detail::portable_thread_control::get_nice(std::move(value));
275 [[nodiscard]]
static auto
279 auto const maximum =
static_cast<std::uint64_t
>((std::numeric_limits<detail::native_thread_id>::max)());
281 return unexpected(std::make_error_code(std::errc::invalid_argument));
292 has_native() const noexcept ->
bool
294 return global_ || owned_ !=
nullptr;
298 native() -> detail::thread_registry_backend&
304 native() const -> detail::thread_registry_backend const&
309 std::shared_ptr<detail::thread_registry_backend> owned_;
310 std::vector<std::shared_ptr<detail::thread_registry_backend>> retired_;
311 std::vector<std::weak_ptr<detail::external_registry_binding_state>> bindings_;
312 bool global_{
false };
318 std::remove_if(bindings_.begin(), bindings_.end(), [](
auto const& binding) { return binding.expired(); }),
320 for (
auto const& binding : bindings_)
321 if (auto state = binding.lock())
322 state->replace(owned_);
326 track_binding(std::shared_ptr<detail::external_registry_binding_state>
const& state)
329 std::remove_if(bindings_.begin(), bindings_.end(), [](
auto const& binding) { return binding.expired(); }),
331 bindings_.push_back(state);
340[[nodiscard]]
inline auto
368 if (registry.global_ || registry.owned_ ==
nullptr)
369 throw std::invalid_argument(
"global registry facade cannot be bound as an external registry");
370 owner_ = registry.owned_;
371 state_ = std::make_shared<detail::external_registry_binding_state>(owner_);
372 registry.track_binding(state_);
385 : owner_(std::move(other.owner_)), state_(std::move(other.state_))
395 owner_ = std::move(other.owner_);
396 state_ = std::move(other.state_);
407 state_->active =
false;
410 auto previous = state_->previous;
411 while (previous && !previous->active)
412 previous = previous->previous;
420 std::shared_ptr<detail::thread_registry_backend> owner_;
421 std::shared_ptr<detail::external_registry_binding_state> state_;
435 if (!registry.has_native())
436 throw std::system_error(std::make_error_code(std::errc::operation_canceled),
437 "auto_register_current_thread: moved-from registry");
438 if (registry.global_)
441 registry_owner_ = state->owner;
445 registry_owner_ = registry.owned_;
447 registry_ = registry_owner_ ? registry_owner_.get() : ®istry.native();
449 native_id_ = control->tid();
450 (void)control->set_name(name);
451 active_ = registry_->register_guard(control, name, component);
452 control_ = std::move(control);
464 : active_(other.active_), registry_(other.registry_), native_id_(other.native_id_),
465 control_(std::move(other.control_)), registry_owner_(std::move(other.registry_owner_))
467 other.active_ =
false;
468 other.registry_ =
nullptr;
469 other.native_id_ = {};
478 active_ = other.active_;
479 registry_ = other.registry_;
480 native_id_ = other.native_id_;
481 control_ = std::move(other.control_);
482 registry_owner_ = std::move(other.registry_owner_);
483 other.active_ =
false;
484 other.registry_ =
nullptr;
485 other.native_id_ = {};
494 if (active_ && registry_ !=
nullptr)
495 registry_->unregister_thread(native_id_, control_.get());
498 registry_owner_.reset();
501 bool active_{
false };
502 detail::thread_registry_backend* registry_{
nullptr };
504 std::shared_ptr<detail::thread_control_block> control_;
505 std::shared_ptr<detail::thread_registry_backend> registry_owner_;
Non-owning facade that merges snapshots from multiple registries.
RAII registration of the calling thread in a portable registry.
auto operator=(auto_register_current_thread const &) -> auto_register_current_thread &=delete
auto operator=(auto_register_current_thread &&other) noexcept -> auto_register_current_thread &
auto_register_current_thread(std::string name={}, std::string component={})
~auto_register_current_thread()
auto_register_current_thread(thread_registry ®istry, std::string name={}, std::string component={})
auto_register_current_thread(auto_register_current_thread &&other) noexcept
auto_register_current_thread(auto_register_current_thread const &)=delete
static auto create_for_current_thread() -> std::shared_ptr< thread_control_block >
Temporarily bind an owning registry as the global external registry.
global_registry_binding(global_registry_binding &&other) noexcept
auto operator=(global_registry_binding const &) -> global_registry_binding &=delete
auto operator=(global_registry_binding &&other) noexcept -> global_registry_binding &
~global_registry_binding()
global_registry_binding(thread_registry ®istry)
Install external binding.
global_registry_binding(global_registry_binding const &)=delete
Strongly-typed nice value in the POSIX range $[-20, 19]$.
Portable thread configuration bundle.
Registry for named/configurable threads.
thread_registry(thread_registry const &)=delete
static auto create() -> result< thread_registry >
Create an owning registry without throwing.
friend auto global_registry() -> thread_registry &
auto register_current_thread(std::string name={}, std::string component={}) -> result< void >
Register the calling thread.
auto count() const -> std::size_t
Return number of tracked entries.
thread_registry(thread_registry &&) noexcept=default
auto get_priority(thread_id id) const -> result< priority_level >
Query portable priority preset for a registered thread.
auto set_nice(thread_id id, nice_value value) -> result< void >
Set explicit nice value for a registered thread.
auto snapshot() const -> result< std::vector< registered_thread > >
Take a snapshot of all registry entries.
auto operator=(thread_registry const &) -> thread_registry &=delete
thread_registry()
Construct an owning registry instance.
auto empty() const -> bool
Return whether registry has no tracked entries.
auto set_priority(thread_id id, priority_level level) -> result< void >
Set portable priority preset for a registered thread.
auto unregister_current_thread() -> result< void >
Unregister the calling thread.
auto configure(thread_id id, thread_config const &config) -> result< void >
Apply configuration to a registered thread.
auto get_nice(thread_id id) const -> result< nice_value >
Query nice value for a registered thread.
constexpr auto posix_nice(int nice_value) noexcept -> native_scheduling_config
auto runtime_exchange_external_registry_state(std::shared_ptr< external_registry_binding_state > state) -> std::shared_ptr< external_registry_binding_state >
auto runtime_external_registry_state() -> std::shared_ptr< external_registry_binding_state >
void runtime_set_external_registry_state(std::shared_ptr< external_registry_binding_state > state)
constexpr auto to_native(shutdown_policy policy) noexcept -> shutdown_policy_backend
constexpr auto to_priority_level(int nice_value) noexcept -> priority_level
void runtime_set_external_registry(thread_registry_backend *reg)
auto runtime_registry() -> thread_registry_backend &
auto try_result(Function &&function) -> decltype(std::forward< Function >(function)())
auto global_registry() -> thread_registry &
priority_level
Portable non-realtime priority levels.
static constexpr auto value(thread_id id) noexcept -> std::uint64_t
static constexpr auto make(std::uint64_t value) -> thread_id
Snapshot entry returned by thread_registry::snapshot.
std::string name
User-visible thread name if known.
std::thread::id std_id
Native std::thread identifier.
std::string component
Optional logical component/group label.
bool alive
Whether thread is currently alive according to the registry.
thread_id id
Stable logical thread id inside the registry.
Portable thread startup and runtime configuration.
Strongly-typed registry thread identifier.