diff --git a/include/condy/awaiters.hpp b/include/condy/awaiters.hpp index 4832e9ae..12bf42a7 100644 --- a/include/condy/awaiters.hpp +++ b/include/condy/awaiters.hpp @@ -15,6 +15,7 @@ #include "condy/finish_handles.hpp" #include "condy/ring.hpp" #include "condy/runtime.hpp" +#include "condy/type_traits.hpp" #include "condy/work_type.hpp" #include #include @@ -28,9 +29,9 @@ template class HandleBox { public: HandleBox(Handle h) : handle_(std::move(h)) {} - Handle &get() { return handle_; } + Handle &get() noexcept { return handle_; } - void maybe_release() { /* No-op */ } + void maybe_release() noexcept { /* No-op */ } private: Handle handle_; @@ -44,9 +45,9 @@ class HandleBox> { HandleBox(const HandleBox &other) // Deep copy : handle_ptr_(std::make_unique(*other.handle_ptr_)) {} - Handle &get() { return *handle_ptr_; } + Handle &get() noexcept { return *handle_ptr_; } - void maybe_release() { handle_ptr_.release(); } + void maybe_release() noexcept { handle_ptr_.release(); } private: std::unique_ptr handle_ptr_; @@ -60,9 +61,9 @@ template class OpAwaiterBase { : prep_func_(func), finish_handle_(std::move(handle)) {} public: - HandleType *get_handle() { return &finish_handle_.get(); } + HandleType *get_handle() noexcept { return &finish_handle_.get(); } - void init_finish_handle() { /* Leaf node, no-op */ } + void init_finish_handle() noexcept { /* Leaf node, no-op */ } void register_operation(unsigned int flags) noexcept { auto &context = detail::Context::current(); @@ -87,7 +88,7 @@ template class OpAwaiterBase { register_operation(0); } - auto await_resume() { + auto await_resume() noexcept { auto result = finish_handle_.get().extract_result(); finish_handle_.maybe_release(); return result; @@ -147,12 +148,14 @@ class [[nodiscard]] FlaggedOpAwaiter : public Awaiter { using Base = Awaiter; FlaggedOpAwaiter(Awaiter awaiter) : Base(std::move(awaiter)) {} - void register_operation(unsigned int flags) { + void register_operation(unsigned int flags) noexcept( + is_nothrow_suspendible_v) { Base::register_operation(flags | Flags); } template - void await_suspend(std::coroutine_handle h) { + void await_suspend(std::coroutine_handle h) noexcept( + is_nothrow_suspendible_v) { Base::init_finish_handle(); Base::get_handle()->set_invoker(&h.promise()); register_operation(0); @@ -168,9 +171,9 @@ class [[nodiscard]] RangedParallelAwaiterBase { : awaiters_(std::move(awaiters)) {} public: - HandleType *get_handle() { return &finish_handle_; } + HandleType *get_handle() noexcept { return &finish_handle_; } - void init_finish_handle() { + void init_finish_handle() noexcept { using ChildHandle = typename Awaiter::HandleType; std::vector handles; handles.reserve(awaiters_.size()); @@ -181,7 +184,8 @@ class [[nodiscard]] RangedParallelAwaiterBase { finish_handle_.init(std::move(handles)); } - void register_operation(unsigned int flags) { + void register_operation(unsigned int flags) noexcept( + is_nothrow_suspendible_v) { for (auto &awaiter : awaiters_) { awaiter.register_operation(flags); } @@ -191,13 +195,15 @@ class [[nodiscard]] RangedParallelAwaiterBase { bool await_ready() const noexcept { return awaiters_.empty(); } template - void await_suspend(std::coroutine_handle h) { + void await_suspend(std::coroutine_handle h) noexcept( + is_nothrow_suspendible_v) { init_finish_handle(); finish_handle_.set_invoker(&h.promise()); register_operation(0); } - typename Handle::ReturnType await_resume() { + typename Handle::ReturnType + await_resume() noexcept(is_nothrow_extract_result_v) { return finish_handle_.extract_result(); } @@ -264,7 +270,8 @@ class [[nodiscard]] RangedLinkAwaiterBase using Base = RangedWhenAllAwaiter; using Base::Base; - void register_operation(unsigned int flags) { + void register_operation(unsigned int flags) noexcept( + is_nothrow_suspendible_v) { auto *ring = detail::Context::current().ring(); ring->reserve_space(Base::awaiters_.size()); for (int i = 0; i < Base::awaiters_.size() - 1; ++i) { @@ -274,7 +281,8 @@ class [[nodiscard]] RangedLinkAwaiterBase } template - void await_suspend(std::coroutine_handle h) { + void await_suspend(std::coroutine_handle h) noexcept( + is_nothrow_suspendible_v) { Base::init_finish_handle(); Base::finish_handle_.set_invoker(&h.promise()); register_operation(0); @@ -313,9 +321,9 @@ class [[nodiscard]] ParallelAwaiterBase { std::make_tuple(std::move(new_awaiter)))) {} public: - HandleType *get_handle() { return &finish_handle_; } + HandleType *get_handle() noexcept { return &finish_handle_; } - void init_finish_handle() { + void init_finish_handle() noexcept { auto handles = foreach_init_finish_handle_(); static_assert(std::tuple_size::value == sizeof...(Awaiters), @@ -327,7 +335,8 @@ class [[nodiscard]] ParallelAwaiterBase { handles); } - void register_operation(unsigned int flags) { + void register_operation(unsigned int flags) noexcept( + (is_nothrow_suspendible_v && ...)) { foreach_register_operation_(flags); } @@ -335,18 +344,20 @@ class [[nodiscard]] ParallelAwaiterBase { bool await_ready() const noexcept { return false; } template - void await_suspend(std::coroutine_handle h) { + void await_suspend(std::coroutine_handle h) noexcept( + (is_nothrow_suspendible_v && ...)) { init_finish_handle(); finish_handle_.set_invoker(&h.promise()); register_operation(0); } - typename Handle::ReturnType await_resume() { + typename Handle::ReturnType + await_resume() noexcept(is_nothrow_extract_result_v) { return finish_handle_.extract_result(); } private: - template auto foreach_init_finish_handle_() { + template auto foreach_init_finish_handle_() noexcept { if constexpr (Idx < sizeof...(Awaiters)) { std::get(awaiters_).init_finish_handle(); return std::tuple_cat( @@ -358,7 +369,8 @@ class [[nodiscard]] ParallelAwaiterBase { } template - void foreach_register_operation_(unsigned int flags) { + void foreach_register_operation_(unsigned int flags) noexcept( + (is_nothrow_suspendible_v && ...)) { if constexpr (Idx < sizeof...(Awaiters)) { std::get(awaiters_).register_operation(flags); foreach_register_operation_(flags); @@ -428,14 +440,16 @@ class [[nodiscard]] LinkAwaiterBase : public WhenAllAwaiter { using Base = WhenAllAwaiter; using Base::Base; - void register_operation(unsigned int flags) { + void register_operation(unsigned int flags) noexcept( + (is_nothrow_suspendible_v && ...)) { auto *ring = detail::Context::current().ring(); ring->reserve_space(sizeof...(Awaiter)); foreach_register_operation_(flags); } template - void await_suspend(std::coroutine_handle h) { + void await_suspend(std::coroutine_handle h) noexcept( + (is_nothrow_suspendible_v && ...)) { Base::init_finish_handle(); Base::finish_handle_.set_invoker(&h.promise()); register_operation(0); @@ -443,7 +457,8 @@ class [[nodiscard]] LinkAwaiterBase : public WhenAllAwaiter { private: template - void foreach_register_operation_(unsigned int flags) { + void foreach_register_operation_(unsigned int flags) noexcept( + (is_nothrow_suspendible_v && ...)) { if constexpr (Idx < sizeof...(Awaiter)) { std::get(Base::awaiters_) .register_operation(Idx < sizeof...(Awaiter) - 1 ? flags | Flags diff --git a/include/condy/buffers.hpp b/include/condy/buffers.hpp index a2fb854a..155a32ee 100644 --- a/include/condy/buffers.hpp +++ b/include/condy/buffers.hpp @@ -32,12 +32,12 @@ class MutableBuffer : public BufferBase { /** * @brief Get the data of the buffer */ - void *data() const { return data_; } + void *data() const noexcept { return data_; } /** * @brief Get the byte size of the buffer */ - size_t size() const { return size_; } + size_t size() const noexcept { return size_; } private: void *data_ = nullptr; @@ -62,12 +62,12 @@ class ConstBuffer : public BufferBase { /** * @brief Get the data of the buffer */ - const void *data() const { return data_; } + const void *data() const noexcept { return data_; } /** * @brief Get the byte size of the buffer */ - size_t size() const { return size_; } + size_t size() const noexcept { return size_; } private: const void *data_ = nullptr; @@ -82,14 +82,14 @@ class ConstBuffer : public BufferBase { * convert different types of memory regions into buffer objects for use in * asynchronous operations. */ -inline MutableBuffer buffer(void *data, size_t size) { +inline MutableBuffer buffer(void *data, size_t size) noexcept { return MutableBuffer(data, size); } /** * @copydoc buffer(void*, size_t) */ -inline ConstBuffer buffer(const void *data, size_t size) { +inline ConstBuffer buffer(const void *data, size_t size) noexcept { return ConstBuffer(data, size); } @@ -97,7 +97,7 @@ inline ConstBuffer buffer(const void *data, size_t size) { * @copydoc buffer(void*, size_t) */ template -inline MutableBuffer buffer(PodType (&arr)[N]) { +inline MutableBuffer buffer(PodType (&arr)[N]) noexcept { return MutableBuffer(static_cast(arr), sizeof(PodType) * N); } @@ -105,7 +105,7 @@ inline MutableBuffer buffer(PodType (&arr)[N]) { * @copydoc buffer(void*, size_t) */ template -inline ConstBuffer buffer(const PodType (&arr)[N]) { +inline ConstBuffer buffer(const PodType (&arr)[N]) noexcept { return ConstBuffer(static_cast(arr), sizeof(PodType) * N); } @@ -113,7 +113,7 @@ inline ConstBuffer buffer(const PodType (&arr)[N]) { * @copydoc buffer(void*, size_t) */ template -inline MutableBuffer buffer(std::array &arr) { +inline MutableBuffer buffer(std::array &arr) noexcept { return MutableBuffer(static_cast(arr.data()), sizeof(PodType) * N); } @@ -121,7 +121,7 @@ inline MutableBuffer buffer(std::array &arr) { * @copydoc buffer(void*, size_t) */ template -inline ConstBuffer buffer(const std::array &arr) { +inline ConstBuffer buffer(const std::array &arr) noexcept { return ConstBuffer(static_cast(arr.data()), sizeof(PodType) * N); } @@ -130,7 +130,7 @@ inline ConstBuffer buffer(const std::array &arr) { * @copydoc buffer(void*, size_t) */ template -inline MutableBuffer buffer(std::vector &vec) { +inline MutableBuffer buffer(std::vector &vec) noexcept { return MutableBuffer(static_cast(vec.data()), sizeof(PodType) * vec.size()); } @@ -139,7 +139,7 @@ inline MutableBuffer buffer(std::vector &vec) { * @copydoc buffer(void*, size_t) */ template -inline ConstBuffer buffer(const std::vector &vec) { +inline ConstBuffer buffer(const std::vector &vec) noexcept { return ConstBuffer(static_cast(vec.data()), sizeof(PodType) * vec.size()); } @@ -147,28 +147,28 @@ inline ConstBuffer buffer(const std::vector &vec) { /** * @copydoc buffer(void*, size_t) */ -inline MutableBuffer buffer(std::string &str) { +inline MutableBuffer buffer(std::string &str) noexcept { return MutableBuffer(static_cast(str.data()), str.size()); } /** * @copydoc buffer(void*, size_t) */ -inline ConstBuffer buffer(const std::string &str) { +inline ConstBuffer buffer(const std::string &str) noexcept { return ConstBuffer(static_cast(str.data()), str.size()); } /** * @copydoc buffer(void*, size_t) */ -inline ConstBuffer buffer(std::string_view strv) { +inline ConstBuffer buffer(std::string_view strv) noexcept { return ConstBuffer(static_cast(strv.data()), strv.size()); } /** * @copydoc buffer(void*, size_t) */ -inline MutableBuffer buffer(iovec &iov) { +inline MutableBuffer buffer(iovec &iov) noexcept { return MutableBuffer(iov.iov_base, iov.iov_len); } @@ -176,7 +176,7 @@ inline MutableBuffer buffer(iovec &iov) { * @copydoc buffer(void*, size_t) */ template -inline ConstBuffer buffer(std::span sp) { +inline ConstBuffer buffer(std::span sp) noexcept { return ConstBuffer(static_cast(sp.data()), sp.size() * sizeof(PodType)); } @@ -185,7 +185,7 @@ inline ConstBuffer buffer(std::span sp) { * @copydoc buffer(void*, size_t) */ template -inline MutableBuffer buffer(std::span sp) { +inline MutableBuffer buffer(std::span sp) noexcept { return MutableBuffer(static_cast(sp.data()), sp.size() * sizeof(PodType)); } diff --git a/include/condy/channel.hpp b/include/condy/channel.hpp index 4651a142..2e5f2e08 100644 --- a/include/condy/channel.hpp +++ b/include/condy/channel.hpp @@ -14,6 +14,7 @@ #include "condy/utils.hpp" #include #include +#include #include namespace condy { @@ -74,14 +75,18 @@ template class Channel { return try_pop_inner_(); } - template void force_push(U &&item) { - std::lock_guard lock(mutex_); - if (try_push_inner_(std::forward(item))) [[likely]] { - return; + template void force_push(U &&item) noexcept { + try { + std::lock_guard lock(mutex_); + if (try_push_inner_(std::forward(item))) [[likely]] { + return; + } + auto *fake_handle = new PushFinishHandle(std::forward(item)); + assert(pop_awaiters_.empty()); + push_awaiters_.push_back(fake_handle); + } catch (const std::exception &e) { + panic_on(std::format("Failed to push into channel: {}", e.what())); } - auto *fake_handle = new PushFinishHandle(std::forward(item)); - assert(pop_awaiters_.empty()); - push_awaiters_.push_back(fake_handle); } struct [[nodiscard]] PushAwaiter; @@ -122,7 +127,7 @@ template class Channel { * @brief Get the current size of the channel. * @warning This function may not be accurate in multithreaded scenarios. */ - size_t size() const noexcept { + size_t size() const { std::lock_guard lock(mutex_); return size_; } @@ -131,7 +136,7 @@ template class Channel { * @brief Check if the channel is empty. * @warning This function may not be accurate in multithreaded scenarios. */ - bool empty() const noexcept { + bool empty() const { std::lock_guard lock(mutex_); return size_ == 0; } @@ -140,7 +145,7 @@ template class Channel { * @brief Check if the channel is closed. * @warning This function may not be accurate in multithreaded scenarios. */ - bool is_closed() const noexcept { + bool is_closed() const { std::lock_guard lock(mutex_); return closed_; } @@ -173,7 +178,7 @@ template class Channel { return false; } - bool cancel_push_(PushFinishHandle *finish_handle) { + bool cancel_push_(PushFinishHandle *finish_handle) noexcept { std::lock_guard lock(mutex_); return push_awaiters_.remove(finish_handle); } @@ -190,7 +195,7 @@ template class Channel { return std::nullopt; } - bool cancel_pop_(PopFinishHandle *finish_handle) { + bool cancel_pop_(PopFinishHandle *finish_handle) noexcept { std::lock_guard lock(mutex_); return pop_awaiters_.remove(finish_handle); } @@ -323,7 +328,7 @@ class Channel::PushFinishHandle PushFinishHandle(T item) : item_(std::move(item)) {} - void cancel() { + void cancel() noexcept { if (channel_->cancel_push_(this)) { // Successfully canceled canceled_ = true; @@ -340,9 +345,9 @@ class Channel::PushFinishHandle return success; } - void set_invoker(Invoker *invoker) { invoker_ = invoker; } + void set_invoker(Invoker *invoker) noexcept { invoker_ = invoker; } - void invoke() { + void invoke() noexcept { if (need_resume_) { runtime_->resume_work(); } @@ -350,14 +355,14 @@ class Channel::PushFinishHandle } public: - void init(Channel *channel, Runtime *runtime) { + void init(Channel *channel, Runtime *runtime) noexcept { channel_ = channel; runtime_ = runtime; } - T &get_item() { return item_; } + T &get_item() noexcept { return item_; } - void schedule() { + void schedule() noexcept { if (runtime_ == nullptr) [[unlikely]] { // Fake handle, no need to schedule delete this; @@ -367,7 +372,7 @@ class Channel::PushFinishHandle } } - void enable_throw() { should_throw_ = true; } + void enable_throw() noexcept { should_throw_ = true; } public: DoubleLinkEntry link_entry_; @@ -388,7 +393,7 @@ class Channel::PopFinishHandle public: using ReturnType = T; - void cancel() { + void cancel() noexcept { if (channel_->cancel_pop_(this)) { // Successfully canceled runtime_->resume_work(); @@ -398,9 +403,9 @@ class Channel::PopFinishHandle ReturnType extract_result() { return std::move(result_); } - void set_invoker(Invoker *invoker) { invoker_ = invoker; } + void set_invoker(Invoker *invoker) noexcept { invoker_ = invoker; } - void invoke() { + void invoke() noexcept { if (need_resume_) { runtime_->resume_work(); } @@ -408,14 +413,14 @@ class Channel::PopFinishHandle } public: - void init(Channel *channel, Runtime *runtime) { + void init(Channel *channel, Runtime *runtime) noexcept { channel_ = channel; runtime_ = runtime; } void set_result(T result) { result_ = std::move(result); } - void schedule() { + void schedule() noexcept { assert(runtime_ != nullptr); need_resume_ = true; runtime_->schedule(this); @@ -446,9 +451,9 @@ template struct Channel::PushAwaiter { : channel_(channel), finish_handle_(std::move(item)) {} public: - HandleType *get_handle() { return &finish_handle_; } + HandleType *get_handle() noexcept { return &finish_handle_; } - void init_finish_handle() { /* Leaf node, no-op */ } + void init_finish_handle() noexcept { /* Leaf node, no-op */ } void register_operation(unsigned int /*flags*/) { auto *runtime = detail::Context::current().runtime(); @@ -491,11 +496,11 @@ template struct Channel::PopAwaiter { PopAwaiter(Channel &channel) : channel_(channel) {} public: - HandleType *get_handle() { return &finish_handle_; } + HandleType *get_handle() noexcept { return &finish_handle_; } - void init_finish_handle() { /* Leaf node, no-op */ } + void init_finish_handle() noexcept { /* Leaf node, no-op */ } - void register_operation(unsigned int /*flags*/) noexcept { + void register_operation(unsigned int /*flags*/) { auto *runtime = detail::Context::current().runtime(); finish_handle_.init(&channel_, runtime); auto item = channel_.request_pop_(&finish_handle_); @@ -509,7 +514,7 @@ template struct Channel::PopAwaiter { bool await_ready() const noexcept { return false; } template - bool await_suspend(std::coroutine_handle h) noexcept { + bool await_suspend(std::coroutine_handle h) { init_finish_handle(); finish_handle_.set_invoker(&h.promise()); finish_handle_.init(&channel_, detail::Context::current().runtime()); diff --git a/include/condy/concepts.hpp b/include/condy/concepts.hpp index a866d40a..9db8bdd5 100644 --- a/include/condy/concepts.hpp +++ b/include/condy/concepts.hpp @@ -47,10 +47,10 @@ concept PrepFuncLike = requires(T prep_func, Ring *ring) { template concept CQEHandlerLike = requires(T handler, io_uring_cqe *cqe) { typename std::decay_t::ReturnType; - { handler.handle_cqe(cqe) } -> std::same_as; + { handler.handle_cqe(cqe) } noexcept -> std::same_as; { handler.extract_result() - } -> std::same_as::ReturnType>; + } noexcept -> std::same_as::ReturnType>; }; template diff --git a/include/condy/context.hpp b/include/condy/context.hpp index e4ac7b84..132a3a27 100644 --- a/include/condy/context.hpp +++ b/include/condy/context.hpp @@ -19,24 +19,24 @@ namespace detail { class Context : public ThreadLocalSingleton { public: - void init(Ring *ring, Runtime *runtime) { + void init(Ring *ring, Runtime *runtime) noexcept { ring_ = ring; runtime_ = runtime; bgid_pool_.reset(); } - void reset() { + void reset() noexcept { ring_ = nullptr; runtime_ = nullptr; bgid_pool_.reset(); } - Ring *ring() { return ring_; } + Ring *ring() noexcept { return ring_; } - Runtime *runtime() { return runtime_; } + Runtime *runtime() noexcept { return runtime_; } uint16_t next_bgid() { return bgid_pool_.allocate(); } - void recycle_bgid(uint16_t bgid) { bgid_pool_.recycle(bgid); } + void recycle_bgid(uint16_t bgid) noexcept { bgid_pool_.recycle(bgid); } private: Ring *ring_ = nullptr; diff --git a/include/condy/coro.inl b/include/condy/coro.inl index fdd7a7f7..b474d84e 100644 --- a/include/condy/coro.inl +++ b/include/condy/coro.inl @@ -91,14 +91,16 @@ public: } } - Coro get_return_object() { + Coro get_return_object() noexcept { return Coro{std::coroutine_handle::from_promise( static_cast(*this))}; } - std::suspend_always initial_suspend() noexcept { return {}; } + std::suspend_always initial_suspend() const noexcept { return {}; } - void unhandled_exception() { exception_ = std::current_exception(); } + void unhandled_exception() noexcept { + exception_ = std::current_exception(); + } struct FinalAwaiter { bool await_ready() const noexcept { return false; } @@ -130,10 +132,10 @@ public: return self.caller_handle_; } - void await_resume() noexcept {} + void await_resume() const noexcept {} }; - FinalAwaiter final_suspend() noexcept { return {}; } + FinalAwaiter final_suspend() const noexcept { return {}; } public: void request_detach() noexcept { @@ -165,12 +167,9 @@ public: auto_destroy_ = auto_destroy; } - std::exception_ptr &exception() & noexcept { return exception_; } - std::exception_ptr &&exception() && noexcept { - return std::move(exception_); - } + std::exception_ptr exception() noexcept { return std::move(exception_); } - void invoke() { + void invoke() noexcept { auto h = std::coroutine_handle::from_promise( static_cast(*this)); h.resume(); @@ -189,7 +188,7 @@ template class Promise : public BindAllocator>, Allocator> { public: - void return_void() noexcept {} + void return_void() const noexcept {} }; template @@ -198,8 +197,7 @@ class Promise public: void return_value(T value) { value_ = std::move(value); } - T &value() & noexcept { return value_.value(); } - T &&value() && noexcept { return std::move(value_).value(); } + T value() { return std::move(value_.value()); } private: std::optional value_; @@ -223,12 +221,12 @@ struct CoroAwaiter : public CoroAwaiterBase::promise_type> { using Base = CoroAwaiterBase::promise_type>; T await_resume() { - auto exception = std::move(Base::handle_.promise()).exception(); + auto exception = Base::handle_.promise().exception(); if (exception) [[unlikely]] { Base::handle_.destroy(); std::rethrow_exception(exception); } - T value = std::move(Base::handle_.promise()).value(); + T value = Base::handle_.promise().value(); Base::handle_.destroy(); return value; } @@ -239,7 +237,7 @@ struct CoroAwaiter : public CoroAwaiterBase::promise_type> { using Base = CoroAwaiterBase::promise_type>; void await_resume() { - auto exception = std::move(Base::handle_.promise()).exception(); + auto exception = Base::handle_.promise().exception(); Base::handle_.destroy(); if (exception) [[unlikely]] { std::rethrow_exception(exception); diff --git a/include/condy/cqe_handler.hpp b/include/condy/cqe_handler.hpp index 9b21c857..1f05e527 100644 --- a/include/condy/cqe_handler.hpp +++ b/include/condy/cqe_handler.hpp @@ -47,9 +47,9 @@ class SimpleCQEHandler { public: using ReturnType = int32_t; - void handle_cqe(io_uring_cqe *cqe) { res_ = cqe->res; } + void handle_cqe(io_uring_cqe *cqe) noexcept { res_ = cqe->res; } - ReturnType extract_result() { return res_; } + ReturnType extract_result() noexcept { return res_; } private: int32_t res_ = -ENOTRECOVERABLE; // Internal error if not set @@ -66,12 +66,12 @@ template class SelectBufferCQEHandler { SelectBufferCQEHandler(Br *buffers) : buffers_(buffers) {} - void handle_cqe(io_uring_cqe *cqe) { + void handle_cqe(io_uring_cqe *cqe) noexcept { res_ = cqe->res; flags_ = cqe->flags; } - ReturnType extract_result() { + ReturnType extract_result() noexcept { return std::make_pair(res_, buffers_->handle_finish(res_, flags_)); } @@ -98,14 +98,14 @@ class NVMePassthruCQEHandler { public: using ReturnType = NVMeResult; - void handle_cqe(io_uring_cqe *cqe) { + void handle_cqe(io_uring_cqe *cqe) noexcept { assert(detail::check_cqe32(cqe) && "Expected big CQE for NVMe passthrough"); result_.status = cqe->res; result_.result = cqe->big_cqe[0]; } - ReturnType extract_result() { return result_; } + ReturnType extract_result() noexcept { return result_; } private: NVMeResult result_; @@ -131,7 +131,7 @@ class TxTimestampCQEHandler { public: using ReturnType = TxTimestampResult; - void handle_cqe(io_uring_cqe *cqe) { + void handle_cqe(io_uring_cqe *cqe) noexcept { assert(detail::check_cqe32(cqe) && "Expected big CQE for TX timestamp operations"); result_.tskey = cqe->res; @@ -141,7 +141,7 @@ class TxTimestampCQEHandler { result_.hwts = cqe->flags & IORING_CQE_F_TSTAMP_HW; } - ReturnType extract_result() { return result_; } + ReturnType extract_result() noexcept { return result_; } private: TxTimestampResult result_; diff --git a/include/condy/finish_handles.hpp b/include/condy/finish_handles.hpp index 230a4767..7238989e 100644 --- a/include/condy/finish_handles.hpp +++ b/include/condy/finish_handles.hpp @@ -13,12 +13,14 @@ #include "condy/context.hpp" #include "condy/invoker.hpp" #include "condy/ring.hpp" +#include "condy/type_traits.hpp" #include "condy/work_type.hpp" #include #include #include #include #include +#include #include #include @@ -38,9 +40,9 @@ struct Action { class OpFinishHandleBase : public InvokerAdapter { public: - using HandleCQEFunc = detail::Action (*)(void *, io_uring_cqe *); + using HandleCQEFunc = detail::Action (*)(void *, io_uring_cqe *) noexcept; - void cancel() { + void cancel() noexcept { auto *ring = detail::Context::current().ring(); io_uring_sqe *sqe = ring->get_sqe(); io_uring_prep_cancel(sqe, this, 0); @@ -48,17 +50,17 @@ class OpFinishHandleBase io_uring_sqe_set_flags(sqe, IOSQE_CQE_SKIP_SUCCESS); } - detail::Action handle_cqe(io_uring_cqe *cqe) { + detail::Action handle_cqe(io_uring_cqe *cqe) noexcept { assert(handle_func_ != nullptr); return handle_func_(this, cqe); } - void invoke() { + void invoke() noexcept { assert(invoker_ != nullptr); (*invoker_)(); } - void set_invoker(Invoker *invoker) { invoker_ = invoker; } + void set_invoker(Invoker *invoker) noexcept { invoker_ = invoker; } protected: OpFinishHandleBase() = default; @@ -78,15 +80,18 @@ class OpFinishHandle : public OpFinishHandleBase { this->handle_func_ = handle_cqe_static_; } - detail::Action handle_cqe_impl(io_uring_cqe *cqe) { + detail::Action handle_cqe_impl(io_uring_cqe *cqe) noexcept { cqe_handler_.handle_cqe(cqe); return {.queue_work = true, .op_finish = true}; } - ReturnType extract_result() { return cqe_handler_.extract_result(); } + ReturnType extract_result() noexcept { + return cqe_handler_.extract_result(); + } private: - static detail::Action handle_cqe_static_(void *data, io_uring_cqe *cqe) { + static detail::Action handle_cqe_static_(void *data, + io_uring_cqe *cqe) noexcept { auto *self = static_cast(data); return self->handle_cqe_impl(cqe); } @@ -104,7 +109,8 @@ class MultiShotMixin : public HandleBase { this->handle_func_ = handle_cqe_static_; } - detail::Action handle_cqe_impl(io_uring_cqe *cqe) /* fake override */ { + detail::Action handle_cqe_impl(io_uring_cqe *cqe) noexcept + /* fake override */ { if (cqe->flags & IORING_CQE_F_MORE) { HandleBase::handle_cqe_impl(cqe); func_(HandleBase::extract_result()); @@ -116,7 +122,8 @@ class MultiShotMixin : public HandleBase { } private: - static detail::Action handle_cqe_static_(void *data, io_uring_cqe *cqe) { + static detail::Action handle_cqe_static_(void *data, + io_uring_cqe *cqe) noexcept { auto *self = static_cast(data); return self->handle_cqe_impl(cqe); } @@ -139,7 +146,7 @@ class ZeroCopyMixin : public HandleBase { this->handle_func_ = handle_cqe_static_; } - void invoke() /* fake override */ { + void invoke() noexcept /* fake override */ { assert(this->invoker_ != nullptr); (*this->invoker_)(); resumed_ = true; @@ -149,7 +156,8 @@ class ZeroCopyMixin : public HandleBase { maybe_free_(); } - detail::Action handle_cqe_impl(io_uring_cqe *cqe) /* fake override */ { + detail::Action handle_cqe_impl(io_uring_cqe *cqe) noexcept + /* fake override */ { if (cqe->flags & IORING_CQE_F_MORE) { HandleBase::handle_cqe_impl(cqe); return {.queue_work = true, .op_finish = false}; @@ -169,26 +177,27 @@ class ZeroCopyMixin : public HandleBase { } private: - void maybe_free_() { + void maybe_free_() noexcept { if (resumed_ && notified_) { free_func_(notify_res_); delete this; } } - void notify_(int32_t res) { + void notify_(int32_t res) noexcept { assert(res != -ENOTRECOVERABLE); notify_res_ = res; notified_ = true; maybe_free_(); } - static void invoke_static_(void *data) { + static void invoke_static_(void *data) noexcept { auto *self = static_cast(data); self->invoke(); } - static detail::Action handle_cqe_static_(void *data, io_uring_cqe *cqe) { + static detail::Action handle_cqe_static_(void *data, + io_uring_cqe *cqe) noexcept { auto *self = static_cast(data); return self->handle_cqe_impl(cqe); } @@ -211,7 +220,7 @@ template class RangedParallelFinishHandle { using ReturnType = std::pair, std::vector>; - void init(std::vector handles) { + void init(std::vector handles) noexcept { handles_ = std::move(handles); child_invokers_.resize(handles_.size()); for (size_t i = 0; i < handles_.size(); i++) { @@ -224,7 +233,7 @@ template class RangedParallelFinishHandle { order_.resize(handles_.size()); } - void cancel() { + void cancel() noexcept { if (!canceled_) { canceled_ = true; for (auto &handle : handles_) { @@ -233,7 +242,7 @@ template class RangedParallelFinishHandle { } } - ReturnType extract_result() { + ReturnType extract_result() noexcept(is_nothrow_extract_result_v) { std::vector result; result.reserve(handles_.size()); for (size_t i = 0; i < handles_.size(); i++) { @@ -242,10 +251,10 @@ template class RangedParallelFinishHandle { return std::make_pair(std::move(order_), std::move(result)); } - void set_invoker(Invoker *invoker) { invoker_ = invoker; } + void set_invoker(Invoker *invoker) noexcept { invoker_ = invoker; } private: - void finish_(size_t idx) { + void finish_(size_t idx) noexcept { size_t no = finished_count_++; order_[no] = idx; @@ -269,7 +278,7 @@ template class RangedParallelFinishHandle { private: struct FinishInvoker : public InvokerAdapter { - void invoke() { self_->finish_(no_); } + void invoke() noexcept { self_->finish_(no_); } RangedParallelFinishHandle *self_; size_t no_; }; @@ -294,7 +303,7 @@ class RangedWhenAllFinishHandle : public RangedParallelAllFinishHandle { using Base = RangedParallelAllFinishHandle; using ReturnType = std::vector; - ReturnType extract_result() { + ReturnType extract_result() noexcept(noexcept(Base::extract_result())) { auto r = Base::extract_result(); return std::move(r.second); } @@ -322,12 +331,12 @@ template class ParallelFinishHandle { using ReturnType = std::pair, std::tuple>; - template void init(HandlePtr... handles) { + template void init(HandlePtr... handles) noexcept { handles_ = std::make_tuple(handles...); foreach_set_invoker_(); } - void cancel() { + void cancel() noexcept { if (!canceled_) { canceled_ = true; constexpr size_t SkipIdx = std::numeric_limits::max(); @@ -335,7 +344,8 @@ template class ParallelFinishHandle { } } - ReturnType extract_result() { + ReturnType + extract_result() noexcept((is_nothrow_extract_result_v && ...)) { auto result = std::apply( [](auto *...handle_ptrs) { return std::make_tuple(handle_ptrs->extract_result()...); @@ -344,10 +354,10 @@ template class ParallelFinishHandle { return std::make_pair(std::move(order_), std::move(result)); } - void set_invoker(Invoker *invoker) { invoker_ = invoker; } + void set_invoker(Invoker *invoker) noexcept { invoker_ = invoker; } private: - template void foreach_set_invoker_() { + template void foreach_set_invoker_() noexcept { if constexpr (I < sizeof...(Handles)) { auto *handle = std::get(handles_); auto &invoker = std::get(child_invokers_); @@ -357,7 +367,8 @@ template class ParallelFinishHandle { } } - template void foreach_call_cancel_() { + template + void foreach_call_cancel_() noexcept { if constexpr (I < sizeof...(Handles)) { auto handle = std::get(handles_); if constexpr (I != SkipIdx) { @@ -367,7 +378,7 @@ template class ParallelFinishHandle { } } - template void finish_() { + template void finish_() noexcept { size_t no = finished_count_++; order_[no] = Idx; @@ -387,7 +398,7 @@ template class ParallelFinishHandle { private: template struct FinishInvoker : public InvokerAdapter> { - void invoke() { self_->template finish_(); } + void invoke() noexcept { self_->template finish_(); } ParallelFinishHandle *self_; }; @@ -425,7 +436,7 @@ class WhenAllFinishHandle : public ParallelAllFinishHandle { using Base = ParallelAllFinishHandle; using ReturnType = std::tuple; - ReturnType extract_result() { + ReturnType extract_result() noexcept(noexcept(Base::extract_result())) { auto r = Base::extract_result(); return std::move(r.second); } @@ -437,7 +448,7 @@ class WhenAnyFinishHandle : public ParallelAnyFinishHandle { using Base = ParallelAnyFinishHandle; using ReturnType = std::variant; - ReturnType extract_result() { + ReturnType extract_result() noexcept(noexcept(Base::extract_result())) { auto r = Base::extract_result(); auto &[order, results] = r; return tuple_at_(std::move(results), order[0]); diff --git a/include/condy/helpers.hpp b/include/condy/helpers.hpp index cc008f1d..796da831 100644 --- a/include/condy/helpers.hpp +++ b/include/condy/helpers.hpp @@ -30,17 +30,20 @@ namespace condy { namespace detail { template struct SpawnHelper { - void operator()(auto &&res) { + void operator()(auto &&res) noexcept { + // This helper will only be called inside the coroutine context, so it's + // safe to assume that the runtime is available. + assert(detail::Context::current().runtime() != nullptr); co_spawn(func(std::forward(res))).detach(); } - std::decay_t func; + CoroFunc func; }; template struct PushHelper { - void operator()(auto &&res) { + void operator()(auto &&res) noexcept { channel.force_push(std::forward(res)); } - std::decay_t &channel; + Channel &channel; }; } // namespace detail @@ -70,7 +73,7 @@ template auto will_spawn(CoroFunc &&coro) { * async_read_multishot(). */ template auto will_push(Channel &channel) { - return detail::PushHelper>{channel}; + return detail::PushHelper{channel}; } namespace detail { diff --git a/include/condy/invoker.hpp b/include/condy/invoker.hpp index 5eaf3aae..3e1af618 100644 --- a/include/condy/invoker.hpp +++ b/include/condy/invoker.hpp @@ -12,10 +12,10 @@ namespace condy { class Invoker { public: - using Func = void (*)(void *); + using Func = void (*)(void *) noexcept; Invoker(Func func) : func_(func) {} - void operator()() { func_(this); } + void operator()() noexcept { func_(this); } protected: Func func_; @@ -27,7 +27,9 @@ class InvokerAdapter : public Invoker { InvokerAdapter() : Invoker(&InvokerAdapter::invoke_) {} private: - static void invoke_(void *self) { static_cast(self)->invoke(); } + static void invoke_(void *self) noexcept { + static_cast(self)->invoke(); + } }; class WorkInvoker : public Invoker { diff --git a/include/condy/provided_buffers.hpp b/include/condy/provided_buffers.hpp index 28b80607..24e8d85c 100644 --- a/include/condy/provided_buffers.hpp +++ b/include/condy/provided_buffers.hpp @@ -56,7 +56,7 @@ class BundledProvidedBufferQueue { void *data = mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (data == MAP_FAILED) [[unlikely]] { - throw std::bad_alloc(); + throw make_system_error("mmap"); } br_ = reinterpret_cast(data); io_uring_buf_ring_init(br_); @@ -97,12 +97,12 @@ class BundledProvidedBufferQueue { /** * @brief Get the current size of the buffer queue */ - size_t size() const { return size_; } + size_t size() const noexcept { return size_; } /** * @brief Get the capacity of the buffer queue */ - size_t capacity() const { return capacity_; } + size_t capacity() const noexcept { return capacity_; } /** * @brief Push a buffer into the provided buffer queue @@ -129,9 +129,9 @@ class BundledProvidedBufferQueue { } public: - uint16_t bgid() const { return bgid_; } + uint16_t bgid() const noexcept { return bgid_; } - ReturnType handle_finish(int32_t res, uint32_t flags) { + ReturnType handle_finish(int32_t res, uint32_t flags) noexcept { if (!(flags & IORING_CQE_F_BUFFER)) { return ReturnType{0, 0}; } @@ -236,22 +236,22 @@ struct ProvidedBuffer : public BufferBase { /** * @brief Get the data pointer of the provided buffer */ - void *data() const { return data_; } + void *data() const noexcept { return data_; } /** * * @brief Get the size of the provided buffer */ - size_t size() const { return size_; } + size_t size() const noexcept { return size_; } /** * @brief Reset the provided buffer, returning it to the pool if owned */ - void reset(); + void reset() noexcept; /** * @brief Check if the provided buffer owns a buffer from a pool. */ - bool owns_buffer() const { return pool_ != nullptr; } + bool owns_buffer() const noexcept { return pool_ != nullptr; } private: void *data_ = nullptr; @@ -275,7 +275,7 @@ class BundledProvidedBufferPool { void *data = mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (data == MAP_FAILED) [[unlikely]] { - throw std::bad_alloc(); + throw make_system_error("mmap"); } br_ = reinterpret_cast(data); io_uring_buf_ring_init(br_); @@ -325,17 +325,17 @@ class BundledProvidedBufferPool { /** * @brief Get the capacity of the buffer pool */ - size_t capacity() const { return num_buffers_; } + size_t capacity() const noexcept { return num_buffers_; } /** * @brief Get the size of each buffer in the pool */ - size_t buffer_size() const { return buffer_size_; } + size_t buffer_size() const noexcept { return buffer_size_; } public: - uint16_t bgid() const { return bgid_; } + uint16_t bgid() const noexcept { return bgid_; } - ReturnType handle_finish(int32_t res, [[maybe_unused]] uint32_t flags) { + ReturnType handle_finish(int32_t res, uint32_t flags) noexcept { std::vector buffers; if (!(flags & IORING_CQE_F_BUFFER)) { @@ -369,7 +369,7 @@ class BundledProvidedBufferPool { return buffers; } - void add_buffer_back(void *ptr) { + void add_buffer_back(void *ptr) noexcept { char *base = get_buffers_base_(); assert(ptr >= base); size_t offset = static_cast(ptr) - base; @@ -382,21 +382,21 @@ class BundledProvidedBufferPool { } private: - char *get_buffer_(uint16_t bid) const { + char *get_buffer_(uint16_t bid) const noexcept { return get_buffers_base_() + static_cast(bid) * buffer_size_; } - char *get_buffers_base_() const { + char *get_buffers_base_() const noexcept { return reinterpret_cast(br_) + sizeof(io_uring_buf) * num_buffers_; } - io_uring_buf *curr_io_uring_buf_() { + io_uring_buf *curr_io_uring_buf_() noexcept { auto mask = io_uring_buf_ring_mask(num_buffers_); return &br_->bufs[br_head_ & mask]; } - void advance_io_uring_buf_() { br_head_++; } + void advance_io_uring_buf_() noexcept { br_head_++; } private: io_uring_buf_ring *br_ = nullptr; @@ -409,7 +409,7 @@ class BundledProvidedBufferPool { } // namespace detail -inline void ProvidedBuffer::reset() { +inline void ProvidedBuffer::reset() noexcept { if (pool_ != nullptr) { pool_->add_buffer_back(data_); } @@ -446,7 +446,7 @@ class ProvidedBufferPool : public detail::BundledProvidedBufferPool { : BundledProvidedBufferPool(num_buffers, buffer_size, flags) {} public: - ReturnType handle_finish(int32_t res, uint32_t flags) { + ReturnType handle_finish(int32_t res, uint32_t flags) noexcept { auto buffers = BundledProvidedBufferPool::handle_finish(res, flags); if (buffers.empty()) { return ReturnType(); diff --git a/include/condy/runtime.hpp b/include/condy/runtime.hpp index b0663281..d621f7b1 100644 --- a/include/condy/runtime.hpp +++ b/include/condy/runtime.hpp @@ -411,6 +411,8 @@ class Runtime { * @note This function assumes that there is a current runtime. Calling this * function outside of a coroutine will lead to undefined behavior. */ -inline auto ¤t_runtime() { return *detail::Context::current().runtime(); } +inline auto ¤t_runtime() noexcept { + return *detail::Context::current().runtime(); +} } // namespace condy \ No newline at end of file diff --git a/include/condy/singleton.hpp b/include/condy/singleton.hpp index 2311c75b..a006210d 100644 --- a/include/condy/singleton.hpp +++ b/include/condy/singleton.hpp @@ -14,7 +14,7 @@ template class ThreadLocalSingleton { ThreadLocalSingleton(ThreadLocalSingleton &&) = delete; ThreadLocalSingleton &operator=(ThreadLocalSingleton &&) = delete; - static T ¤t() { + static T ¤t() noexcept { static thread_local T instance; return instance; } diff --git a/include/condy/sync_wait.hpp b/include/condy/sync_wait.hpp index b12b9ec1..b061ef8b 100644 --- a/include/condy/sync_wait.hpp +++ b/include/condy/sync_wait.hpp @@ -33,7 +33,7 @@ T sync_wait(Runtime &runtime, Coro coro) { * using sync_wait without specifying runtime. * @return RuntimeOptions& Reference to the default runtime options. */ -inline RuntimeOptions &default_runtime_options() { +inline RuntimeOptions &default_runtime_options() noexcept { static RuntimeOptions options; return options; } diff --git a/include/condy/task.hpp b/include/condy/task.hpp index 9deb4612..eb79f6eb 100644 --- a/include/condy/task.hpp +++ b/include/condy/task.hpp @@ -97,7 +97,7 @@ void TaskBase::wait_inner_( struct TaskWaiter : public InvokerAdapter { TaskWaiter(std::promise &p) : prom_(p) {} - void invoke() { prom_.set_value(); } + void invoke() noexcept { prom_.set_value(); } std::promise &prom_; }; @@ -201,7 +201,7 @@ struct TaskAwaiterBase : public InvokerAdapter> { return task_handle_.promise().register_task_await(this); } - void invoke() { + void invoke() noexcept { assert(caller_promise_ != nullptr); runtime_->schedule(caller_promise_); } @@ -263,7 +263,8 @@ inline auto TaskBase::operator co_await() noexcept { * runtime. */ template -inline Task co_spawn(Runtime &runtime, Coro coro) { +inline Task co_spawn(Runtime &runtime, + Coro coro) noexcept { auto handle = coro.release(); auto &promise = handle.promise(); promise.set_auto_destroy(false); @@ -314,6 +315,8 @@ struct [[nodiscard]] SwitchAwaiter { * run in the specified runtime. The caller coroutine will be resumed in the * target runtime. */ -inline detail::SwitchAwaiter co_switch(Runtime &runtime) { return {&runtime}; } +inline detail::SwitchAwaiter co_switch(Runtime &runtime) noexcept { + return {&runtime}; +} } // namespace condy \ No newline at end of file diff --git a/include/condy/type_traits.hpp b/include/condy/type_traits.hpp new file mode 100644 index 00000000..2f03537b --- /dev/null +++ b/include/condy/type_traits.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +namespace condy { + +template +struct is_nothrow_suspendible + : std::bool_constant().await_suspend( + std::declval>()))> {}; + +template +constexpr bool is_nothrow_suspendible_v = is_nothrow_suspendible::value; + +template +struct is_nothrow_extract_result + : std::bool_constant().extract_result())> {}; + +template +constexpr bool is_nothrow_extract_result_v = + is_nothrow_extract_result::value; + +} // namespace condy \ No newline at end of file diff --git a/include/condy/utils.hpp b/include/condy/utils.hpp index f61dbca8..761c7507 100644 --- a/include/condy/utils.hpp +++ b/include/condy/utils.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #if defined(__has_feature) @@ -63,36 +65,6 @@ template Defer defer(Func &&func) { return Defer(std::forward(func)); } -template class MaybeMutex : public BaseMutex { -public: - using Base = BaseMutex; - using Base::Base; - - void lock() noexcept { - if (use_mutex_) { - Base::lock(); - } - } - - void unlock() noexcept { - if (use_mutex_) { - Base::unlock(); - } - } - - bool try_lock() noexcept { - if (use_mutex_) { - return Base::try_lock(); - } - return true; - } - - void set_use_mutex(bool use_mutex) noexcept { use_mutex_ = use_mutex; } - -private: - bool use_mutex_ = false; -}; - [[noreturn]] inline void panic_on(std::string_view msg) noexcept { std::cerr << std::format("Panic: {}\n", msg); #ifndef CRASH_TEST @@ -105,15 +77,19 @@ template class MaybeMutex : public BaseMutex { template class RawStorage { public: - template void construct(Args &&...args) { + template + void construct(Args &&...args) noexcept( + std::is_nothrow_constructible_v) { new (&storage_) T(std::forward(args)...); } - T &get() { return *reinterpret_cast(&storage_); } + T &get() noexcept { return *reinterpret_cast(&storage_); } - const T &get() const { return *reinterpret_cast(&storage_); } + const T &get() const noexcept { + return *reinterpret_cast(&storage_); + } - void destroy() { get().~T(); } + void destroy() noexcept { get().~T(); } private: alignas(T) unsigned char storage_[sizeof(T)]; @@ -133,18 +109,18 @@ template class SmallArray { } } - T &operator[](size_t index) { + T &operator[](size_t index) noexcept { return is_small_() ? small_[index] : large_[index]; } - const T &operator[](size_t index) const { + const T &operator[](size_t index) const noexcept { return is_small_() ? small_[index] : large_[index]; } - size_t capacity() const { return capacity_; } + size_t capacity() const noexcept { return capacity_; } private: - bool is_small_() const { return capacity_ <= N; } + bool is_small_() const noexcept { return capacity_ <= N; } private: size_t capacity_; @@ -158,12 +134,18 @@ inline auto make_system_error(std::string_view msg, int ec) { return std::system_error(ec, std::generic_category(), std::string(msg)); } -template constexpr ptrdiff_t offset_of(M T::*member) { +inline auto make_system_error(std::string_view msg) { + return make_system_error(msg, errno); +} + +template +constexpr ptrdiff_t offset_of(M T::*member) noexcept { constexpr T *dummy = nullptr; return reinterpret_cast(&(dummy->*member)); } -template T *container_of(M T::*member, M *ptr) { +template +T *container_of(M T::*member, M *ptr) noexcept { auto offset = offset_of(member); // NOLINTNEXTLINE(performance-no-int-to-ptr) return reinterpret_cast(reinterpret_cast(ptr) - offset); @@ -186,12 +168,12 @@ class IdPool { throw std::runtime_error("ID pool exhausted"); } - void recycle(T id) { + void recycle(T id) noexcept { assert(From <= id && id < next_id_ && id < To); recycled_ids_.push(id); } - void reset() { + void reset() noexcept { next_id_ = From; while (!recycled_ids_.empty()) { recycled_ids_.pop(); diff --git a/include/condy/work_type.hpp b/include/condy/work_type.hpp index 4ca6b257..fe6156f2 100644 --- a/include/condy/work_type.hpp +++ b/include/condy/work_type.hpp @@ -17,7 +17,7 @@ enum class WorkType : uint8_t { Schedule, }; -inline std::pair decode_work(void *ptr) { +inline std::pair decode_work(void *ptr) noexcept { intptr_t mask = (1 << 3) - 1; intptr_t addr = reinterpret_cast(ptr); WorkType type = static_cast(addr & mask); @@ -26,7 +26,7 @@ inline std::pair decode_work(void *ptr) { return std::make_pair(actual_ptr, type); } -inline void *encode_work(void *ptr, WorkType type) { +inline void *encode_work(void *ptr, WorkType type) noexcept { intptr_t addr = reinterpret_cast(ptr); // Ensure align of 8 assert(addr % 8 == 0); diff --git a/tests/test_async_operations.4.cpp b/tests/test_async_operations.4.cpp index 21959de6..0013c0e9 100644 --- a/tests/test_async_operations.4.cpp +++ b/tests/test_async_operations.4.cpp @@ -438,7 +438,7 @@ TEST_CASE("test async_operations - test uring_cmd_multishot - tx timestamp") { [&](auto r) { results.push_back(r); if (results.size() == 3) { - chan.try_push(std::monostate{}); + chan.force_push(std::monostate{}); } }) || chan.pop());