Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Leave
FixNamespaceComments: true
IfMacros: [
'STDEXEC_CATCH'
'STDEXEC_CATCH',
'STDEXEC_IF_CONSTEVAL',
'STDEXEC_IF_NOT_CONSTEVAL'
]
IncludeBlocks: Preserve
IndentAccessModifiers: false
Expand Down
2 changes: 1 addition & 1 deletion include/exec/async_scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ namespace experimental::execution
}

[[nodiscard]]
constexpr auto query(get_scheduler_t) const noexcept -> STDEXEC::inline_scheduler
constexpr auto query(get_start_scheduler_t) const noexcept -> STDEXEC::inline_scheduler
{
return {};
}
Expand Down
14 changes: 6 additions & 8 deletions include/exec/at_coroutine_exit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ namespace experimental::execution
{
using namespace STDEXEC;

using __any_scheduler_t =
any_receiver_ref<completion_signatures<set_value_t(),
set_error_t(std::exception_ptr),
set_stopped_t()>>::any_sender<>::any_scheduler<>;
using __any_scheduler_t = any_scheduler<any_sender<any_receiver<
completion_signatures<set_value_t(), set_error_t(std::exception_ptr), set_stopped_t()>>>>;

struct __die_on_stop_t
{
Expand Down Expand Up @@ -153,7 +151,7 @@ namespace experimental::execution
auto await_suspend(__std::coroutine_handle<_Promise> __parent) noexcept -> bool
{
// Set the cleanup task's scheduler to the parent coroutine's scheduler.
__coro_.promise().__scheduler_ = get_scheduler(get_env(__parent.promise()));
__coro_.promise().__scheduler_ = get_start_scheduler(get_env(__parent.promise()));
// This causes the parent to be resumed after the cleanup action is performed.
__coro_.promise().set_continuation(__parent.promise().continuation());
// This causes the parent to invoke the cleanup action when it performs the final
Expand Down Expand Up @@ -190,13 +188,13 @@ namespace experimental::execution

struct __env
{
__promise const & __promise_;

[[nodiscard]]
auto query(get_scheduler_t) const noexcept -> __any_scheduler_t
auto query(get_start_scheduler_t) const noexcept -> __any_scheduler_t
{
return __promise_.__scheduler_;
}

__promise const & __promise_;
};

struct __promise : with_awaitable_senders<__promise>
Expand Down
23 changes: 7 additions & 16 deletions include/exec/on_coro_disposition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@ namespace experimental::execution
{
using namespace STDEXEC;

using __any_scheduler =
any_receiver_ref<completion_signatures<set_value_t(),
set_error_t(std::exception_ptr),
set_stopped_t()>>::any_sender<>::any_scheduler<>;
using __any_scheduler = any_scheduler<any_sender<any_receiver<
completion_signatures<set_value_t(), set_error_t(std::exception_ptr), set_stopped_t()>>>>;

template <class _Promise>
concept __promise_with_disposition = __at_coro_exit::__has_continuation<_Promise>
Expand Down Expand Up @@ -99,7 +97,7 @@ namespace experimental::execution
_Promise& __promise = __std::coroutine_handle<_Promise>::from_address(__parent).promise();
return __promise.disposition();
};
__coro_.promise().__scheduler_ = get_scheduler(get_env(__parent.promise()));
__coro_.promise().__scheduler_ = get_start_scheduler(get_env(__parent.promise()));
__coro_.promise().set_continuation(__parent.promise().continuation());
__parent.promise().set_continuation(__coro_);
return false;
Expand Down Expand Up @@ -131,28 +129,21 @@ namespace experimental::execution

struct __env
{
__promise const & __promise_;

[[nodiscard]]
auto query(get_scheduler_t) const noexcept -> __any_scheduler
auto query(get_start_scheduler_t) const noexcept -> __any_scheduler
{
return __promise_.__scheduler_;
}

__promise const & __promise_;
};

struct __promise : with_awaitable_senders<__promise>
{
#if STDEXEC_EDG()
template <class _Action>
__promise(_Action&&, _Ts&&... __ts) noexcept
explicit(STDEXEC_EDG() != 0) __promise(_Action&&, _Ts&... __ts) noexcept
: __args_{__ts...}
{}
#else
template <class _Action>
explicit __promise(_Action&&, _Ts&... __ts) noexcept
: __args_{__ts...}
{}
#endif

auto initial_suspend() noexcept -> __std::suspend_always
{
Expand Down
4 changes: 2 additions & 2 deletions include/exec/reschedule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace experimental::execution
_WITH_ENVIRONMENT_(_Env)>;

template <class _Env>
using __schedule_sender_t = schedule_result_t<__call_result_t<get_scheduler_t, _Env>>;
using __schedule_sender_t = schedule_result_t<__call_result_t<get_start_scheduler_t, _Env>>;

template <class _Env>
using __try_schedule_sender_t =
Expand All @@ -63,7 +63,7 @@ namespace experimental::execution
auto connect(_Receiver __rcvr) const
-> connect_result_t<__schedule_sender_t<env_of_t<_Receiver>>, _Receiver>
{
auto __sched = get_scheduler(STDEXEC::get_env(__rcvr));
auto __sched = get_start_scheduler(STDEXEC::get_env(__rcvr));
return STDEXEC::connect(STDEXEC::schedule(__sched), static_cast<_Receiver&&>(__rcvr));
}

Expand Down
6 changes: 4 additions & 2 deletions include/exec/static_thread_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ namespace experimental::execution
{
if constexpr (__completes_on<Sender, _static_thread_pool::scheduler, Env>)
{
auto sched = STDEXEC::get_completion_scheduler<set_value_t>(get_env(sndr), env);
auto sched = STDEXEC::get_completion_scheduler<STDEXEC::set_value_t>(get_env(sndr),
env);
static_assert(std::is_same_v<decltype(sched), _static_thread_pool::scheduler>);
return __apply(_transform_bulk{*sched.pool_}, static_cast<Sender&&>(sndr));
}
Expand All @@ -308,7 +309,8 @@ namespace experimental::execution
{
if constexpr (__completes_on<Sender, _static_thread_pool::scheduler, Env>)
{
auto sched = STDEXEC::get_scheduler(env);
auto sched = STDEXEC::get_completion_scheduler<STDEXEC::set_value_t>(get_env(sndr),
env);
return __apply(_transform_iterate{*sched.pool_}, static_cast<Sender&&>(sndr));
}
else
Expand Down
92 changes: 57 additions & 35 deletions include/exec/task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ namespace experimental::execution
using __any_scheduler_completions =
completion_signatures<set_value_t(), set_error_t(std::exception_ptr), set_stopped_t()>;

using __any_scheduler =
any_receiver_ref<__any_scheduler_completions>::any_sender<>::any_scheduler<>;
using __any_scheduler = any_scheduler<any_sender<any_receiver<__any_scheduler_completions>>>;

static_assert(scheduler<__any_scheduler>);

Expand All @@ -59,17 +58,17 @@ namespace experimental::execution
};

template <class _Ty>
concept __indirect_scheduler_provider = requires(_Ty const & t) {
{ get_env(t) } -> __scheduler_provider;
concept __indirect_start_scheduler_provider = requires(_Ty const & t) {
{ get_start_scheduler(get_env(t)) } -> scheduler;
};

template <class _ParentPromise>
constexpr auto __check_parent_promise_has_scheduler() noexcept -> bool
constexpr auto __parent_promise_has_start_scheduler() noexcept -> bool
{
static_assert(__indirect_scheduler_provider<_ParentPromise>,
static_assert(__indirect_start_scheduler_provider<_ParentPromise>,
"exec::task<T> cannot be co_await-ed in a coroutine that "
"does not have an associated scheduler.");
return __indirect_scheduler_provider<_ParentPromise>;
"does not have an associated start scheduler.");
return __indirect_start_scheduler_provider<_ParentPromise>;
}

template <class _ParentPromise>
Expand All @@ -84,41 +83,59 @@ namespace experimental::execution
__sticky
};

template <__scheduler_affinity _SchedulerAffinity>
struct __optional_scheduler_storage
{
__optional_scheduler_storage() = default;
constexpr explicit __optional_scheduler_storage(__ignore) noexcept {}
};

template <>
struct __optional_scheduler_storage<__scheduler_affinity::__sticky>
{
__optional_scheduler_storage() = default;

template <scheduler _Scheduler>
constexpr explicit __optional_scheduler_storage(_Scheduler __sched) noexcept
: __scheduler_(__sched)
{}

__any_scheduler __scheduler_{STDEXEC::inline_scheduler{}};
};

template <__scheduler_affinity _SchedulerAffinity = __scheduler_affinity::__sticky>
class __default_task_context_impl
class __default_task_context_impl : private __optional_scheduler_storage<_SchedulerAffinity>
{
template <class _ParentPromise>
friend struct __default_awaiter_context;

static constexpr bool __with_scheduler = _SchedulerAffinity == __scheduler_affinity::__sticky;
static constexpr bool __with_affinity = _SchedulerAffinity == __scheduler_affinity::__sticky;

STDEXEC_ATTRIBUTE(no_unique_address)
__if_c<__with_scheduler, __any_scheduler, __ignore> __scheduler_{STDEXEC::inline_scheduler{}};
inplace_stop_token __stop_token_;
inplace_stop_token __stop_token_;

public:
template <class _ParentPromise>
constexpr explicit __default_task_context_impl(_ParentPromise& __parent) noexcept
{
if constexpr (_SchedulerAffinity == __scheduler_affinity::__sticky)
if constexpr (__with_affinity && __parent_promise_has_start_scheduler<_ParentPromise>())
{
if constexpr (__check_parent_promise_has_scheduler<_ParentPromise>())
{
__scheduler_ = get_scheduler(get_env(__parent));
}
// get_start_scheduler is used here to get the parent's "current" scheduler,
// which is the one on which this task has been started (i.e., co_await-ed).
auto __parent_sched = get_start_scheduler(get_env(__parent));
this->__scheduler_ = __parent_sched;
}
}

template <scheduler _Scheduler>
constexpr explicit __default_task_context_impl(_Scheduler&& __scheduler)
: __scheduler_{static_cast<_Scheduler&&>(__scheduler)}
constexpr explicit __default_task_context_impl(_Scheduler&& __sched) noexcept
: __optional_scheduler_storage<_SchedulerAffinity>{static_cast<_Scheduler&&>(__sched)}
{}

[[nodiscard]]
constexpr auto query(get_scheduler_t) const noexcept -> __any_scheduler const &
requires(__with_scheduler)
constexpr auto query(get_start_scheduler_t) const noexcept -> __any_scheduler const &
requires(__with_affinity)
{
return __scheduler_;
return this->__scheduler_;
}

[[nodiscard]]
Expand All @@ -130,7 +147,7 @@ namespace experimental::execution
[[nodiscard]]
constexpr auto query(get_completion_behavior_t<set_value_t>) const noexcept
{
if constexpr (__with_scheduler)
if constexpr (__with_affinity)
{
return completion_behavior::asynchronous_affine | completion_behavior::inline_completion;
}
Expand All @@ -148,24 +165,24 @@ namespace experimental::execution

template <scheduler _Scheduler>
constexpr void set_scheduler(_Scheduler&& __sched)
requires(__with_scheduler)
requires(__with_affinity)
{
__scheduler_ = static_cast<_Scheduler&&>(__sched);
this->__scheduler_ = static_cast<_Scheduler&&>(__sched);
}

template <class _ThisPromise>
using promise_context_t = __default_task_context_impl;

template <class _ThisPromise, class _ParentPromise = void>
requires(!__with_scheduler) || __indirect_scheduler_provider<_ParentPromise>
requires(!__with_affinity) || __indirect_start_scheduler_provider<_ParentPromise>
using awaiter_context_t = __default_awaiter_context<_ParentPromise>;
};

template <class _Ty>
using default_task_context = __default_task_context_impl<__scheduler_affinity::__sticky>;

template <class _Ty>
using __raw_task_context = __default_task_context_impl<__scheduler_affinity::__none>;
using inline_task_context = __default_task_context_impl<__scheduler_affinity::__none>;

// This is the context associated with basic_task's awaiter. By default
// it does nothing.
Expand Down Expand Up @@ -387,7 +404,7 @@ namespace experimental::execution
if (!std::exchange(__p.__rescheduled_, true))
{
// Create a cleanup action that transitions back onto the current scheduler:
auto __sched = get_scheduler(*__p.__context_);
auto __sched = get_start_scheduler(*__p.__context_);
auto __guard = at_coroutine_exit(__compose(unstoppable, STDEXEC::schedule),
std::move(__sched));
// Insert the cleanup action into the head of the continuation chain by
Expand Down Expand Up @@ -483,7 +500,7 @@ namespace experimental::execution

private:
using __scheduler_t =
__call_result_or_t<get_scheduler_t, STDEXEC::inline_scheduler, _Context>;
__call_result_or_t<get_start_scheduler_t, STDEXEC::inline_scheduler, _Context>;

struct __final_awaitable
{
Expand Down Expand Up @@ -541,7 +558,7 @@ namespace experimental::execution

#ifndef __clang_analyzer__
template <sender _CvSender>
requires __scheduler_provider<_Context>
requires __start_scheduler_provider<_Context>
auto await_transform(_CvSender&& __sndr) noexcept -> decltype(auto)
{
if constexpr (__completes_where_it_starts<set_value_t,
Expand All @@ -553,13 +570,13 @@ namespace experimental::execution
else
{
return STDEXEC::as_awaitable(continues_on(static_cast<_CvSender&&>(__sndr),
get_scheduler(*__context_)),
get_start_scheduler(*__context_)),
*this);
}
}

template <class _Scheduler>
requires __scheduler_provider<_Context>
requires __start_scheduler_provider<_Context>
auto await_transform(__reschedule_coroutine_on_t::__wrapper<_Scheduler> __box) noexcept
-> decltype(auto)
{
Expand Down Expand Up @@ -592,6 +609,11 @@ namespace experimental::execution
template <class _ParentPromise>
struct __task_awaiter
{
constexpr __task_awaiter(__std::coroutine_handle<__promise> __coro) noexcept
: __coro_(__coro)
{}
STDEXEC_IMMOVABLE(__task_awaiter);

constexpr ~__task_awaiter()
{
if (__coro_)
Expand Down Expand Up @@ -631,7 +653,7 @@ namespace experimental::execution
return std::move(__var::__get<0>(__coro_.promise().__data_));
}

__std::coroutine_handle<__promise> __coro_;
__std::coroutine_handle<__promise> __coro_{};
__optional<awaiter_context_t<__promise, _ParentPromise>> __context_{};
};

Expand All @@ -640,7 +662,7 @@ namespace experimental::execution
: __coro_(__coro)
{}

__std::coroutine_handle<promise_type> __coro_;
__std::coroutine_handle<promise_type> __coro_{};
};
} // namespace __task

Expand Down
5 changes: 3 additions & 2 deletions include/exec/trampoline_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ namespace experimental::execution

struct __attrs
{
template <__one_of<set_value_t, set_stopped_t> _Tag, __queryable_with<get_scheduler_t> _Env>
template <__one_of<set_value_t, set_stopped_t> _Tag,
__queryable_with<get_start_scheduler_t> _Env>
[[nodiscard]]
constexpr auto query(get_completion_scheduler_t<_Tag>, _Env const & __env) const noexcept
{
return get_scheduler(__env);
return get_start_scheduler(__env);
}

template <__one_of<set_value_t, set_stopped_t> _Tag, __queryable_with<get_domain_t> _Env>
Expand Down
Loading
Loading