18 std::optional<cancellation_reason>
reason;
21 std::unordered_map<callback_handle, callback_with_reason_type>
26 std::chrono::steady_clock::time_point::max()};
30 mutable std::condition_variable
cv;
46 std::shared_ptr<state>
state)
56 state_->timer_should_stop.store(
true, std::memory_order_release);
69 auto deadline_point = std::chrono::steady_clock::now() + timeout;
70 return create_with_deadline(deadline_point);
74 std::chrono::steady_clock::time_point deadline_point)
77 auto token = create();
78 token.state_->deadline_point = deadline_point;
79 token.state_->has_deadline.store(
true, std::memory_order_release);
82 std::weak_ptr<state> state_weak = token.state_;
83 start_timeout_timer(state_weak, deadline_point);
89 std::initializer_list<enhanced_cancellation_token> tokens)
92 auto new_token = create();
93 std::weak_ptr<state> new_state_weak = new_token.state_;
95 for (
const auto& parent : tokens)
97 auto parent_copy = parent;
98 parent_copy.register_callback(
101 if (
auto s = new_state_weak.lock())
103 std::vector<callback_type> simple_to_invoke;
104 std::vector<callback_with_reason_type> reason_to_invoke;
108 std::lock_guard<std::mutex> lock(s->mutex);
110 s->is_cancelled.exchange(
true, std::memory_order_release);
115 new_reason.
message =
"Parent token was cancelled";
116 new_reason.
cancel_time = std::chrono::steady_clock::now();
117 s->reason = new_reason;
119 for (
auto& [handle, cb] : s->simple_callbacks)
121 simple_to_invoke.push_back(std::move(cb));
123 s->simple_callbacks.clear();
125 for (
auto& [handle, cb] : s->reason_callbacks)
127 reason_to_invoke.push_back(std::move(cb));
129 s->reason_callbacks.clear();
135 for (
const auto& cb : simple_to_invoke)
139 for (
const auto& cb : reason_to_invoke)
154 auto deadline_point = std::chrono::steady_clock::now() + timeout;
156 auto token = create();
157 token.state_->deadline_point = deadline_point;
158 token.state_->has_deadline.store(
true, std::memory_order_release);
161 std::weak_ptr<state> token_state_weak = token.state_;
162 auto parent_copy = parent;
163 parent_copy.register_callback(
166 if (
auto s = token_state_weak.lock())
168 std::vector<callback_type> simple_to_invoke;
169 std::vector<callback_with_reason_type> reason_to_invoke;
173 std::lock_guard<std::mutex> lock(s->mutex);
175 s->is_cancelled.exchange(
true, std::memory_order_release);
180 new_reason.
message =
"Parent token was cancelled";
181 new_reason.
cancel_time = std::chrono::steady_clock::now();
182 s->reason = new_reason;
184 for (
auto& [handle, cb] : s->simple_callbacks)
186 simple_to_invoke.push_back(std::move(cb));
188 s->simple_callbacks.clear();
190 for (
auto& [handle, cb] : s->reason_callbacks)
192 reason_to_invoke.push_back(std::move(cb));
194 s->reason_callbacks.clear();
196 s->timer_should_stop.store(
true, std::memory_order_release);
202 for (
const auto& cb : simple_to_invoke)
206 for (
const auto& cb : reason_to_invoke)
214 start_timeout_timer(token_state_weak, deadline_point);
235 const std::string& message,
236 std::optional<std::exception_ptr> ex)
239 std::vector<callback_type> simple_to_invoke;
240 std::vector<callback_with_reason_type> reason_to_invoke;
244 std::lock_guard<std::mutex> lock(state_->mutex);
246 state_->is_cancelled.exchange(
true, std::memory_order_release);
251 new_reason.
cancel_time = std::chrono::steady_clock::now();
253 state_->reason = new_reason;
255 for (
auto& [handle, cb] : state_->simple_callbacks)
257 simple_to_invoke.push_back(std::move(cb));
259 state_->simple_callbacks.clear();
261 for (
auto& [handle, cb] : state_->reason_callbacks)
263 reason_to_invoke.push_back(std::move(cb));
265 state_->reason_callbacks.clear();
267 state_->timer_should_stop.store(
true, std::memory_order_release);
271 state_->cv.notify_all();
273 for (
const auto& cb : simple_to_invoke)
277 for (
const auto& cb : reason_to_invoke)
296 std::lock_guard<std::mutex> lock(
state_->mutex);
305 std::string msg =
"Operation cancelled";
306 if (reason && !reason->message.empty())
308 msg +=
": " + reason->message;
317 return state_->has_deadline.load(std::memory_order_acquire);
321 ->
std::chrono::milliseconds
325 return std::chrono::milliseconds::max();
328 auto now = std::chrono::steady_clock::now();
329 auto deadline_point =
state_->deadline_point;
331 if (now >= deadline_point)
333 return std::chrono::milliseconds::zero();
336 return std::chrono::duration_cast<std::chrono::milliseconds>(deadline_point -
341 ->
std::chrono::steady_clock::time_point
343 return state_->deadline_point;
347 std::chrono::milliseconds additional) ->
void
349 std::lock_guard<std::mutex> lock(state_->mutex);
350 if (state_->has_deadline.load(std::memory_order_acquire))
352 state_->deadline_point += additional;
359 std::unique_lock<std::mutex> lock(state_->mutex);
361 if (state_->is_cancelled.load(std::memory_order_acquire))
369 state_->next_handle.fetch_add(1, std::memory_order_relaxed);
370 state_->simple_callbacks[handle] = std::move(
callback);
377 std::unique_lock<std::mutex> lock(state_->mutex);
379 if (state_->is_cancelled.load(std::memory_order_acquire))
381 auto reason = state_->reason;
390 "Operation cancelled",
391 std::chrono::steady_clock::now(),
398 state_->next_handle.fetch_add(1, std::memory_order_relaxed);
399 state_->reason_callbacks[handle] = std::move(
callback);
411 std::lock_guard<std::mutex> lock(state_->mutex);
412 state_->simple_callbacks.erase(handle);
413 state_->reason_callbacks.erase(handle);
418 std::unique_lock<std::mutex> lock(
state_->mutex);
421 {
return state_->is_cancelled.load(std::memory_order_acquire); });
427 std::unique_lock<std::mutex> lock(state_->mutex);
428 return state_->cv.wait_for(
431 {
return state_->is_cancelled.load(std::memory_order_acquire); });
435 std::chrono::steady_clock::time_point deadline_point)
const ->
bool
437 std::unique_lock<std::mutex> lock(state_->mutex);
438 return state_->cv.wait_until(
439 lock, deadline_point,
441 {
return state_->is_cancelled.load(std::memory_order_acquire); });
445 std::weak_ptr<state> state_weak,
446 std::chrono::steady_clock::time_point deadline_point) ->
void
448 std::thread timer_thread(
449 [state_weak, deadline_point]()
mutable
451 auto s = state_weak.lock();
464 s->timer_active.store(
true, std::memory_order_release);
466 std::unique_lock<std::mutex> lock(s->mutex);
469 auto result = s->cv.wait_until(
470 lock, deadline_point,
473 return s->is_cancelled.load(std::memory_order_acquire) ||
474 s->timer_should_stop.load(std::memory_order_acquire);
478 if (!
result && !s->is_cancelled.load(std::memory_order_acquire))
480 std::vector<callback_type> simple_to_invoke;
481 std::vector<callback_with_reason_type> reason_to_invoke;
485 s->is_cancelled.exchange(
true, std::memory_order_release);
489 new_reason.
message =
"Timeout expired";
490 new_reason.
cancel_time = std::chrono::steady_clock::now();
491 s->reason = new_reason;
493 for (
auto& [handle, cb] : s->simple_callbacks)
495 simple_to_invoke.push_back(std::move(cb));
497 s->simple_callbacks.clear();
499 for (
auto& [handle, cb] : s->reason_callbacks)
501 reason_to_invoke.push_back(std::move(cb));
503 s->reason_callbacks.clear();
509 for (
const auto& cb : simple_to_invoke)
513 for (
const auto& cb : reason_to_invoke)
523 s->timer_active.store(
false, std::memory_order_release);
526 timer_thread.detach();
536 : token_(&token), handle_(token.register_callback(
std::move(
callback)))
550 : token_(other.token_), handle_(other.handle_)
552 other.token_ =
nullptr;
561 if (token_ && handle_ != 0)
563 token_->unregister_callback(handle_);
565 token_ = other.token_;
566 handle_ = other.handle_;
567 other.token_ =
nullptr;
578 : token_(
std::move(token))
603 thread_local std::vector<enhanced_cancellation_token> context_stack;
608 if (context_stack.empty())
612 return context_stack.back();
617 context_stack.push_back(std::move(token));
622 if (!context_stack.empty())
624 context_stack.pop_back();
RAII guard for automatic callback unregistration.
enhanced_cancellation_token * token_
~cancellation_callback_guard()
Destructor unregisters the callback.
enhanced_cancellation_token::callback_handle handle_
cancellation_callback_guard(enhanced_cancellation_token &token, std::function< void()> callback)
Constructs a guard and registers the callback.
auto operator=(const cancellation_callback_guard &) -> cancellation_callback_guard &=delete
guard(enhanced_cancellation_token token)
Constructs a guard and pushes the token.
~guard()
Destructor pops the token.
static auto push(enhanced_cancellation_token token) -> void
Pushes a token to the thread-local stack.
static auto current() -> enhanced_cancellation_token
Gets the current thread's cancellation token.
static auto pop() -> void
Pops a token from the thread-local stack.
auto is_cancelled() const -> bool
Checks if the token is cancelled.
enhanced_cancellation_token token_
auto token() const -> const enhanced_cancellation_token &
Gets the underlying token.
auto check_cancelled() const -> common::VoidResult
Checks if the token is cancelled and returns an error result.
cancellation_scope(enhanced_cancellation_token token)
Constructs a scope with the given token.
Advanced cancellation token with timeout, deadline, and reason support.
std::function< void()> callback_type
Simple callback function type.
static auto create() -> enhanced_cancellation_token
Creates a new cancellation token.
static auto create_linked_with_timeout(const enhanced_cancellation_token &parent, std::chrono::milliseconds timeout) -> enhanced_cancellation_token
Creates a linked token with additional timeout.
std::shared_ptr< state > state_
enhanced_cancellation_token()
Default constructor creates a new token.
auto has_timeout() const -> bool
Checks if the token has a timeout or deadline.
auto do_cancel(cancellation_reason::type reason_type, const std::string &message, std::optional< std::exception_ptr > ex) -> void
auto wait_for(std::chrono::milliseconds timeout) const -> bool
Waits for cancellation with a timeout.
auto remaining_time() const -> std::chrono::milliseconds
Gets the remaining time before timeout/deadline.
std::function< void(const cancellation_reason &)> callback_with_reason_type
Callback function type with reason parameter.
static auto create_linked(std::initializer_list< enhanced_cancellation_token > tokens) -> enhanced_cancellation_token
Creates a token linked to parent tokens.
auto is_cancelled() const -> bool
Checks if the token has been cancelled.
auto wait_until(std::chrono::steady_clock::time_point deadline) const -> bool
Waits for cancellation until a deadline.
auto unregister_callback(callback_handle handle) -> void
Unregisters a previously registered callback.
static auto create_with_timeout(std::chrono::milliseconds timeout) -> enhanced_cancellation_token
Creates a token that auto-cancels after the specified timeout.
static auto create_with_deadline(std::chrono::steady_clock::time_point deadline) -> enhanced_cancellation_token
Creates a token that auto-cancels at the specified deadline.
auto extend_timeout(std::chrono::milliseconds additional) -> void
Extends the timeout by the specified duration.
auto deadline() const -> std::chrono::steady_clock::time_point
Gets the deadline time point.
std::size_t callback_handle
Callback handle type for registration management.
auto cancel() -> void
Cancels the token.
static auto start_timeout_timer(std::weak_ptr< state > state_weak, std::chrono::steady_clock::time_point deadline) -> void
~enhanced_cancellation_token()
Destructor.
auto wait() const -> void
Waits until the token is cancelled.
auto is_cancellation_requested() const -> bool
Checks if cancellation has been requested.
auto get_reason() const -> std::optional< cancellation_reason >
Gets the cancellation reason.
auto register_callback(callback_type callback) -> callback_handle
Registers a callback to be invoked on cancellation.
auto check_cancelled() const -> common::VoidResult
Checks if the token has been cancelled and returns an error result.
A template class representing either a value or an error.
Enhanced cancellation token with timeout, deadline, and reason support.
@ callback
Call user callback for custom decision.
Core threading foundation of the thread system library.
common::VoidResult make_error_result(error_code code, const std::string &message="")
Create a common::VoidResult error from a thread::error_code.
Holds information about why a cancellation occurred.
std::chrono::steady_clock::time_point cancel_time
Time point when the cancellation occurred.
type reason_type
The type of cancellation that occurred.
std::optional< std::exception_ptr > exception
Optional exception that triggered the cancellation.
std::string message
Human-readable message describing the cancellation.
type
The type of cancellation that occurred.
@ parent_cancelled
Parent token was cancelled.
@ user_requested
Explicit cancel() call by user.
@ timeout
Timeout duration expired.
@ error
Cancellation triggered by an error.
std::unordered_map< callback_handle, callback_with_reason_type > reason_callbacks
std::atomic< bool > timer_active
std::atomic< bool > is_cancelled
std::atomic< callback_handle > next_handle
std::atomic< bool > timer_should_stop
std::unordered_map< callback_handle, callback_type > simple_callbacks
std::chrono::steady_clock::time_point deadline_point
std::condition_variable cv
std::atomic< bool > has_deadline
std::optional< cancellation_reason > reason