diff --git a/core/future.hh b/core/future.hh index e7b8bf37e8..aa426e0c48 100644 --- a/core/future.hh +++ b/core/future.hh @@ -8,6 +8,7 @@ #include "apply.hh" #include #include +#include #include template @@ -20,12 +21,12 @@ template future make_ready_future(A&&... value); template -future make_exception_future(std::exception_ptr value); +future make_exception_future(std::exception_ptr value) noexcept; class task { public: - virtual ~task() {} - virtual void run() = 0; + virtual ~task() noexcept {} + virtual void run() noexcept = 0; }; void schedule(std::unique_ptr t); @@ -36,7 +37,7 @@ class lambda_task : public task { public: lambda_task(const Func& func) : _func(func) {} lambda_task(Func&& func) : _func(std::move(func)) {} - virtual void run() { _func(); } + virtual void run() noexcept { _func(); } }; template @@ -71,6 +72,8 @@ make_task(Func&& func) { template struct future_state { + static constexpr bool move_noexcept = std::is_nothrow_move_constructible>::value; + static constexpr bool copy_noexcept = std::is_nothrow_copy_constructible>::value; enum class state { invalid, future, @@ -83,8 +86,9 @@ struct future_state { std::tuple value; std::exception_ptr ex; } _u; - future_state() = default; - future_state(future_state&& x) : _state(x._state) { + future_state() noexcept {} + future_state(future_state&& x) noexcept(move_noexcept) + : _state(x._state) { switch (_state) { case state::future: break; @@ -116,22 +120,22 @@ struct future_state { abort(); } } - future_state& operator=(future_state&& x) { + future_state& operator=(future_state&& x) noexcept(move_noexcept) { if (this != &x) { this->~future_state(); new (this) future_state(std::move(x)); } return *this; } - bool available() const { return _state == state::result || _state == state::exception; } - bool failed() const { return _state == state::exception; } + bool available() const noexcept { return _state == state::result || _state == state::exception; } + bool failed() const noexcept { return _state == state::exception; } void wait(); - void set(const std::tuple& value) { + void set(const std::tuple& value) noexcept(copy_noexcept) { assert(_state == state::future); _state = state::result; new (&_u.value) std::tuple(value); } - void set(std::tuple&& value) { + void set(std::tuple&& value) noexcept(move_noexcept) { assert(_state == state::future); _state = state::result; new (&_u.value) std::tuple(std::move(value)); @@ -142,7 +146,7 @@ struct future_state { _state = state::result; new (&_u.value) std::tuple(std::forward(a)...); } - void set_exception(std::exception_ptr ex) { + void set_exception(std::exception_ptr ex) noexcept { assert(_state == state::future); _state = state::exception; new (&_u.ex) std::exception_ptr(ex); @@ -154,7 +158,7 @@ struct future_state { } return std::move(_u.value); } - void forward_to(promise& pr) { + void forward_to(promise& pr) noexcept { assert(_state != state::future); if (_state == state::exception) { pr.set_exception(_u.ex); @@ -168,7 +172,7 @@ template struct future_task final : task, future_state { Func _func; future_task(Func&& func) : _func(std::move(func)) {} - virtual void run() { + virtual void run() noexcept { func(*this); } }; @@ -179,9 +183,11 @@ class promise { future_state _local_state; future_state* _state; std::unique_ptr _task; + static constexpr const bool move_noexcept = future_state::move_noexcept; + static constexpr const bool copy_noexcept = future_state::copy_noexcept; public: - promise() : _state(&_local_state) {} - promise(promise&& x) : _future(x._future), _state(x._state), _task(std::move(x._task)) { + promise() noexcept : _state(&_local_state) {} + promise(promise&& x) noexcept(move_noexcept) : _future(x._future), _state(x._state), _task(std::move(x._task)) { if (_state == &x._local_state) { _state = &_local_state; _local_state = std::move(x._local_state); @@ -191,10 +197,10 @@ public: migrated(); } promise(const promise&) = delete; - ~promise() { + ~promise() noexcept { abandoned(); } - promise& operator=(promise&& x) { + promise& operator=(promise&& x) noexcept(move_noexcept) { if (this != &x) { this->~promise(); new (this) promise(std::move(x)); @@ -202,34 +208,34 @@ public: return *this; } void operator=(const promise&) = delete; - future get_future(); - void set_value(const std::tuple& result) { + future get_future() noexcept; + void set_value(const std::tuple& result) noexcept(copy_noexcept) { _state->set(result); make_ready(); } - void set_value(std::tuple&& result) { + void set_value(std::tuple&& result) noexcept(move_noexcept) { _state->set(std::move(result)); make_ready(); } template - void set_value(A&&... a) { + void set_value(A&&... a) noexcept { _state->set(std::forward(a)...); make_ready(); } - void set_exception(std::exception_ptr ex) { + void set_exception(std::exception_ptr ex) noexcept { _state->set_exception(std::move(ex)); make_ready(); } template - void set_exception(Exception&& e) { + void set_exception(Exception&& e) noexcept { set_exception(make_exception_ptr(std::forward(e))); } private: template - void schedule(Func&& func) { + void schedule(Func&& func) noexcept { struct task_with_state final : task { task_with_state(Func&& func) : _func(std::move(func)) {} - virtual void run() override { + virtual void run() noexcept override { _func(_state); } future_state _state; @@ -239,9 +245,9 @@ private: _state = &tws->_state; _task = std::move(tws); } - void make_ready(); - void migrated(); - void abandoned(); + void make_ready() noexcept; + void migrated() noexcept; + void abandoned() noexcept(move_noexcept); template friend class future; @@ -257,24 +263,26 @@ template class future { promise* _promise; future_state _local_state; // valid if !_promise + static constexpr const bool move_noexcept = future_state::move_noexcept; + static constexpr const bool copy_noexcept = future_state::copy_noexcept; private: - future(promise* pr) : _promise(pr) { + future(promise* pr) noexcept : _promise(pr) { _promise->_future = this; } template future(ready_future_marker, A&&... a) : _promise(nullptr) { _local_state.set(std::forward(a)...); } - future(exception_future_marker, std::exception_ptr ex) : _promise(nullptr) { + future(exception_future_marker, std::exception_ptr ex) noexcept : _promise(nullptr) { _local_state.set_exception(std::move(ex)); } - future_state* state() { + future_state* state() noexcept { return _promise ? _promise->_state : &_local_state; } public: using value_type = std::tuple; using promise_type = promise; - future(future&& x) : _promise(x._promise) { + future(future&& x) noexcept(move_noexcept) : _promise(x._promise) { if (!_promise) { _local_state = std::move(x._local_state); } @@ -284,7 +292,7 @@ public: } } future(const future&) = delete; - future& operator=(future&& x) { + future& operator=(future&& x) noexcept { if (this != &x) { this->~future(); new (this) future(std::move(x)); @@ -301,20 +309,20 @@ public: return state()->get(); } - bool available() { + bool available() noexcept { return state()->available(); } - bool failed() { + bool failed() noexcept { return state()->failed(); } template - void then(Func, Enable); + void then(Func, Enable) noexcept; template future<> then(Func&& func, - std::enable_if_t, void>::value, void*> = nullptr) { + std::enable_if_t, void>::value, void*> = nullptr) noexcept { if (state()->available()) { try { apply(std::move(func), std::move(state()->get())); @@ -338,7 +346,7 @@ public: return fut; } - void forward_to(promise&& pr) { + void forward_to(promise&& pr) noexcept { if (state()->available()) { state()->forward_to(pr); } else { @@ -359,7 +367,7 @@ public: template std::result_of_t then(Func&& func, - std::enable_if_t>::value, void*> = nullptr) { + std::enable_if_t>::value, void*> = nullptr) noexcept { using P = typename std::result_of_t::promise_type; if (state()->available()) { try { @@ -387,7 +395,7 @@ public: } template - future<> rescue(Func&& func) { + future<> rescue(Func&& func) noexcept { if (state()->available()) { try { func([&state = *state()] { return state.get(); }); @@ -412,7 +420,7 @@ public: } template - future finally(Func&& func) { + future finally(Func&& func) noexcept { promise pr; auto f = pr.get_future(); if (state()->available()) { @@ -439,7 +447,7 @@ public: return f; } - future<> or_terminate() { + future<> or_terminate() noexcept { return rescue([] (auto get) { try { get(); @@ -454,23 +462,22 @@ public: template friend future make_ready_future(A&&... value); template - friend future make_exception_future(std::exception_ptr ex); + friend future make_exception_future(std::exception_ptr ex) noexcept; template - friend future make_exception_future(Exception&& ex); + friend future make_exception_future(Exception&& ex) noexcept; }; template inline future -promise::get_future() -{ +promise::get_future() noexcept { assert(!_future); return future(this); } template inline -void promise::make_ready() { +void promise::make_ready() noexcept { if (_task) { ::schedule(std::move(_task)); } @@ -478,7 +485,7 @@ void promise::make_ready() { template inline -void promise::migrated() { +void promise::migrated() noexcept { if (_future) { _future->_promise = this; } @@ -486,7 +493,7 @@ void promise::migrated() { template inline -void promise::abandoned() { +void promise::abandoned() noexcept(move_noexcept) { if (_future) { assert(_state); assert(_state->available()); @@ -503,13 +510,13 @@ future make_ready_future(A&&... value) { template inline -future make_exception_future(std::exception_ptr ex) { +future make_exception_future(std::exception_ptr ex) noexcept { return future(exception_future_marker(), std::move(ex)); } template inline -future make_exception_future(Exception&& ex) { +future make_exception_future(Exception&& ex) noexcept { return make_exception_future(make_exception_ptr(std::forward(ex))); } diff --git a/core/reactor.hh b/core/reactor.hh index 3f95de0ffb..481d0385b9 100644 --- a/core/reactor.hh +++ b/core/reactor.hh @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -67,7 +66,7 @@ std::unique_ptr allocate_aligned_buffer(size_t size, s class semaphore { private: size_t _count; - std::list, size_t>> _wait_list; + circular_buffer, size_t>> _wait_list; public: semaphore(size_t count = 1) : _count(count) {} future<> wait(size_t nr = 1) {