2
0
mirror of https://github.com/boostorg/asio.git synced 2026-01-27 18:42:07 +00:00

Allow the awaitable to be stored and co_await applied to it later.

This commit is contained in:
Christopher Kohlhoff
2018-03-05 22:50:26 +11:00
parent 9cb2eba353
commit 37d49a4f68
2 changed files with 103 additions and 69 deletions

View File

@@ -149,20 +149,20 @@ public:
// Support for co_await keyword.
bool await_ready() const noexcept
{
return false;
return awaitee_->ready();
}
// Support for co_await keyword.
void await_suspend(detail::coroutine_handle<detail::awaiter<Executor>> h)
{
awaitee_->start(&h.promise(), h);
awaitee_->attach_caller(&h.promise(), h);
}
// Support for co_await keyword.
template <class U>
void await_suspend(detail::coroutine_handle<detail::awaitee<U, Executor>> h)
{
awaitee_->start(h.promise().top(), h);
awaitee_->attach_caller(h.promise().top(), h);
}
// Support for co_await keyword.

View File

@@ -36,36 +36,6 @@ namespace asio {
namespace experimental {
namespace detail {
// Helper for returning an awaitable "always ready" value.
template <typename T>
class await_ready_value
{
public:
template <typename... Args>
explicit await_ready_value(Args&&... args)
: value_(std::forward<Args>(args)...)
{
}
bool await_ready() const noexcept
{
return true;
}
template <typename U, typename Ex>
void await_suspend(coroutine_handle<detail::awaitee<U, Ex>>) const noexcept
{
}
T await_resume()
{
return std::move(value_);
}
private:
T value_;
};
// Promise object for coroutine at top of thread-of-execution "stack".
template <typename Executor>
class awaiter
@@ -132,7 +102,12 @@ public:
coroutine_handle<awaiter>::from_promise(*this).destroy();
}
void rethrow_exception()
void unhandled_exception()
{
pending_exception_ = std::current_exception();
}
void rethrow_unhandled_exception()
{
if (pending_exception_)
{
@@ -141,19 +116,9 @@ public:
}
}
void unhandled_exception()
{
pending_exception_ = std::current_exception();
}
void set_except(std::exception_ptr e)
{
pending_exception_ = e;
}
private:
std::size_t ref_count_ = 0;
std::exception_ptr pending_exception_;
std::exception_ptr pending_exception_ = nullptr;
alignas(Executor) unsigned char executor_[sizeof(Executor)];
bool has_executor_ = false;
};
@@ -183,7 +148,7 @@ public:
auto initial_suspend()
{
return std::experimental::suspend_always();
return std::experimental::suspend_never();
}
struct final_suspender
@@ -212,7 +177,7 @@ public:
void set_except(std::exception_ptr e)
{
awaiter_->set_except(e);
pending_exception_ = e;
}
void unhandled_exception()
@@ -220,6 +185,15 @@ public:
set_except(std::current_exception());
}
void rethrow_exception()
{
if (pending_exception_)
{
std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
std::rethrow_exception(ex);
}
}
awaiter<Executor>* top()
{
return awaiter_;
@@ -230,34 +204,94 @@ public:
return caller_;
}
bool ready() const
{
return ready_;
}
void wake_caller()
{
if (caller_)
caller_.resume();
else
ready_ = true;
}
await_ready_value<Executor> await_transform(
this_coro::executor_t) const noexcept
class awaitable_executor
{
return await_ready_value<Executor>(awaiter_->get_executor());
public:
explicit awaitable_executor(const awaitee_base* a)
: this_(a)
{
}
bool await_ready() const noexcept
{
return this_->awaiter_ != nullptr;
}
template <typename U, typename Ex>
void await_suspend(coroutine_handle<detail::awaitee<U, Ex>>) const noexcept
{
}
Executor await_resume()
{
return this_->awaiter_->get_executor();
}
private:
const awaitee_base* this_;
};
awaitable_executor await_transform(this_coro::executor_t) const noexcept
{
return awaitable_executor(this);
}
await_ready_value<await_token<Executor>> await_transform(
this_coro::token_t) const noexcept
class awaitable_token
{
return await_ready_value<await_token<Executor>>(
await_token<Executor>(awaiter_));
public:
explicit awaitable_token(const awaitee_base* a)
: this_(a)
{
}
bool await_ready() const noexcept
{
return this_->awaiter_ != nullptr;
}
template <typename U, typename Ex>
void await_suspend(coroutine_handle<detail::awaitee<U, Ex>>) const noexcept
{
}
await_token<Executor> await_resume()
{
return await_token<Executor>(this_->awaiter_);
}
private:
const awaitee_base* this_;
};
awaitable_token await_transform(this_coro::token_t) const noexcept
{
return awaitable_token(this);
}
template <typename T>
T await_transform(T t) const
T await_transform(T&& t) const
{
return t;
return std::forward<T>(t);
}
protected:
awaiter<Executor>* awaiter_ = nullptr;
coroutine_handle<void> caller_ = nullptr;
std::exception_ptr pending_exception_ = nullptr;
bool ready_ = false;
};
// Promise object for coroutines further down the thread-of-execution "stack".
@@ -296,11 +330,11 @@ public:
T get()
{
this->caller_ = nullptr;
this->awaiter_->rethrow_exception();
this->rethrow_exception();
return std::move(*static_cast<T*>(static_cast<void*>(result_)));
}
void start(awaiter<Executor>* a, coroutine_handle<void> h)
void attach_caller(awaiter<Executor>* a, coroutine_handle<void> h)
{
this->awaiter_ = a;
this->caller_ = h;
@@ -330,10 +364,10 @@ public:
void get()
{
this->caller_ = nullptr;
this->awaiter_->rethrow_exception();
this->rethrow_exception();
}
void start(awaiter<Executor>* a, coroutine_handle<void> h)
void attach_caller(awaiter<Executor>* a, coroutine_handle<void> h)
{
this->awaiter_ = a;
this->caller_ = h;
@@ -434,7 +468,7 @@ public:
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
this->awaitee_->return_void();
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -455,7 +489,7 @@ public:
else
this->awaitee_->return_void();
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -474,7 +508,7 @@ public:
else
this->awaitee_->return_void();
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -491,7 +525,7 @@ public:
typename awaiter<Executor>::ptr ptr(std::move(this->awaiter_));
this->awaitee_->return_value(std::forward<Arg>(arg));
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -511,7 +545,7 @@ public:
else
this->awaitee_->return_value(std::forward<Arg>(arg));
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -531,7 +565,7 @@ public:
else
this->awaitee_->return_value(std::forward<Arg>(arg));
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -549,7 +583,7 @@ public:
this->awaitee_->return_value(
std::forward_as_tuple(std::forward<Args>(args)...));
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -570,7 +604,7 @@ public:
this->awaitee_->return_value(
std::forward_as_tuple(std::forward<Args>(args)...));
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};
@@ -591,7 +625,7 @@ public:
this->awaitee_->return_value(
std::forward_as_tuple(std::forward<Args>(args)...));
this->awaitee_->wake_caller();
ptr->rethrow_exception();
ptr->rethrow_unhandled_exception();
}
};