Skip to content

Commit 0ec597f

Browse files
authored
add the get_start_scheduler query per P3941R4 (#1992)
* add the `get_start_scheduler` query per P3941R4
1 parent e2f8632 commit 0ec597f

33 files changed

+280
-210
lines changed

.clang-format

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ EmptyLineAfterAccessModifier: Never
7171
EmptyLineBeforeAccessModifier: Leave
7272
FixNamespaceComments: true
7373
IfMacros: [
74-
'STDEXEC_CATCH'
74+
'STDEXEC_CATCH',
75+
'STDEXEC_IF_CONSTEVAL',
76+
'STDEXEC_IF_NOT_CONSTEVAL'
7577
]
7678
IncludeBlocks: Preserve
7779
IndentAccessModifiers: false

include/exec/async_scope.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ namespace experimental::execution
726726
}
727727

728728
[[nodiscard]]
729-
constexpr auto query(get_scheduler_t) const noexcept -> STDEXEC::inline_scheduler
729+
constexpr auto query(get_start_scheduler_t) const noexcept -> STDEXEC::inline_scheduler
730730
{
731731
return {};
732732
}

include/exec/at_coroutine_exit.hpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ namespace experimental::execution
3030
{
3131
using namespace STDEXEC;
3232

33-
using __any_scheduler_t =
34-
any_receiver_ref<completion_signatures<set_value_t(),
35-
set_error_t(std::exception_ptr),
36-
set_stopped_t()>>::any_sender<>::any_scheduler<>;
33+
using __any_scheduler_t = any_scheduler<any_sender<any_receiver<
34+
completion_signatures<set_value_t(), set_error_t(std::exception_ptr), set_stopped_t()>>>>;
3735

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

191189
struct __env
192190
{
193-
__promise const & __promise_;
194-
195191
[[nodiscard]]
196-
auto query(get_scheduler_t) const noexcept -> __any_scheduler_t
192+
auto query(get_start_scheduler_t) const noexcept -> __any_scheduler_t
197193
{
198194
return __promise_.__scheduler_;
199195
}
196+
197+
__promise const & __promise_;
200198
};
201199

202200
struct __promise : with_awaitable_senders<__promise>

include/exec/on_coro_disposition.hpp

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ namespace experimental::execution
3232
{
3333
using namespace STDEXEC;
3434

35-
using __any_scheduler =
36-
any_receiver_ref<completion_signatures<set_value_t(),
37-
set_error_t(std::exception_ptr),
38-
set_stopped_t()>>::any_sender<>::any_scheduler<>;
35+
using __any_scheduler = any_scheduler<any_sender<any_receiver<
36+
completion_signatures<set_value_t(), set_error_t(std::exception_ptr), set_stopped_t()>>>>;
3937

4038
template <class _Promise>
4139
concept __promise_with_disposition = __at_coro_exit::__has_continuation<_Promise>
@@ -99,7 +97,7 @@ namespace experimental::execution
9997
_Promise& __promise = __std::coroutine_handle<_Promise>::from_address(__parent).promise();
10098
return __promise.disposition();
10199
};
102-
__coro_.promise().__scheduler_ = get_scheduler(get_env(__parent.promise()));
100+
__coro_.promise().__scheduler_ = get_start_scheduler(get_env(__parent.promise()));
103101
__coro_.promise().set_continuation(__parent.promise().continuation());
104102
__parent.promise().set_continuation(__coro_);
105103
return false;
@@ -131,28 +129,21 @@ namespace experimental::execution
131129

132130
struct __env
133131
{
134-
__promise const & __promise_;
135-
136132
[[nodiscard]]
137-
auto query(get_scheduler_t) const noexcept -> __any_scheduler
133+
auto query(get_start_scheduler_t) const noexcept -> __any_scheduler
138134
{
139135
return __promise_.__scheduler_;
140136
}
137+
138+
__promise const & __promise_;
141139
};
142140

143141
struct __promise : with_awaitable_senders<__promise>
144142
{
145-
#if STDEXEC_EDG()
146143
template <class _Action>
147-
__promise(_Action&&, _Ts&&... __ts) noexcept
144+
explicit(STDEXEC_EDG() != 0) __promise(_Action&&, _Ts&... __ts) noexcept
148145
: __args_{__ts...}
149146
{}
150-
#else
151-
template <class _Action>
152-
explicit __promise(_Action&&, _Ts&... __ts) noexcept
153-
: __args_{__ts...}
154-
{}
155-
#endif
156147

157148
auto initial_suspend() noexcept -> __std::suspend_always
158149
{

include/exec/reschedule.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace experimental::execution
3636
_WITH_ENVIRONMENT_(_Env)>;
3737

3838
template <class _Env>
39-
using __schedule_sender_t = schedule_result_t<__call_result_t<get_scheduler_t, _Env>>;
39+
using __schedule_sender_t = schedule_result_t<__call_result_t<get_start_scheduler_t, _Env>>;
4040

4141
template <class _Env>
4242
using __try_schedule_sender_t =
@@ -63,7 +63,7 @@ namespace experimental::execution
6363
auto connect(_Receiver __rcvr) const
6464
-> connect_result_t<__schedule_sender_t<env_of_t<_Receiver>>, _Receiver>
6565
{
66-
auto __sched = get_scheduler(STDEXEC::get_env(__rcvr));
66+
auto __sched = get_start_scheduler(STDEXEC::get_env(__rcvr));
6767
return STDEXEC::connect(STDEXEC::schedule(__sched), static_cast<_Receiver&&>(__rcvr));
6868
}
6969

include/exec/static_thread_pool.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ namespace experimental::execution
283283
{
284284
if constexpr (__completes_on<Sender, _static_thread_pool::scheduler, Env>)
285285
{
286-
auto sched = STDEXEC::get_completion_scheduler<set_value_t>(get_env(sndr), env);
286+
auto sched = STDEXEC::get_completion_scheduler<STDEXEC::set_value_t>(get_env(sndr),
287+
env);
287288
static_assert(std::is_same_v<decltype(sched), _static_thread_pool::scheduler>);
288289
return __apply(_transform_bulk{*sched.pool_}, static_cast<Sender&&>(sndr));
289290
}
@@ -308,7 +309,8 @@ namespace experimental::execution
308309
{
309310
if constexpr (__completes_on<Sender, _static_thread_pool::scheduler, Env>)
310311
{
311-
auto sched = STDEXEC::get_scheduler(env);
312+
auto sched = STDEXEC::get_completion_scheduler<STDEXEC::set_value_t>(get_env(sndr),
313+
env);
312314
return __apply(_transform_iterate{*sched.pool_}, static_cast<Sender&&>(sndr));
313315
}
314316
else

include/exec/task.hpp

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ namespace experimental::execution
4545
using __any_scheduler_completions =
4646
completion_signatures<set_value_t(), set_error_t(std::exception_ptr), set_stopped_t()>;
4747

48-
using __any_scheduler =
49-
any_receiver_ref<__any_scheduler_completions>::any_sender<>::any_scheduler<>;
48+
using __any_scheduler = any_scheduler<any_sender<any_receiver<__any_scheduler_completions>>>;
5049

5150
static_assert(scheduler<__any_scheduler>);
5251

@@ -59,17 +58,17 @@ namespace experimental::execution
5958
};
6059

6160
template <class _Ty>
62-
concept __indirect_scheduler_provider = requires(_Ty const & t) {
63-
{ get_env(t) } -> __scheduler_provider;
61+
concept __indirect_start_scheduler_provider = requires(_Ty const & t) {
62+
{ get_start_scheduler(get_env(t)) } -> scheduler;
6463
};
6564

6665
template <class _ParentPromise>
67-
constexpr auto __check_parent_promise_has_scheduler() noexcept -> bool
66+
constexpr auto __parent_promise_has_start_scheduler() noexcept -> bool
6867
{
69-
static_assert(__indirect_scheduler_provider<_ParentPromise>,
68+
static_assert(__indirect_start_scheduler_provider<_ParentPromise>,
7069
"exec::task<T> cannot be co_await-ed in a coroutine that "
71-
"does not have an associated scheduler.");
72-
return __indirect_scheduler_provider<_ParentPromise>;
70+
"does not have an associated start scheduler.");
71+
return __indirect_start_scheduler_provider<_ParentPromise>;
7372
}
7473

7574
template <class _ParentPromise>
@@ -84,41 +83,59 @@ namespace experimental::execution
8483
__sticky
8584
};
8685

86+
template <__scheduler_affinity _SchedulerAffinity>
87+
struct __optional_scheduler_storage
88+
{
89+
__optional_scheduler_storage() = default;
90+
constexpr explicit __optional_scheduler_storage(__ignore) noexcept {}
91+
};
92+
93+
template <>
94+
struct __optional_scheduler_storage<__scheduler_affinity::__sticky>
95+
{
96+
__optional_scheduler_storage() = default;
97+
98+
template <scheduler _Scheduler>
99+
constexpr explicit __optional_scheduler_storage(_Scheduler __sched) noexcept
100+
: __scheduler_(__sched)
101+
{}
102+
103+
__any_scheduler __scheduler_{STDEXEC::inline_scheduler{}};
104+
};
105+
87106
template <__scheduler_affinity _SchedulerAffinity = __scheduler_affinity::__sticky>
88-
class __default_task_context_impl
107+
class __default_task_context_impl : private __optional_scheduler_storage<_SchedulerAffinity>
89108
{
90109
template <class _ParentPromise>
91110
friend struct __default_awaiter_context;
92111

93-
static constexpr bool __with_scheduler = _SchedulerAffinity == __scheduler_affinity::__sticky;
112+
static constexpr bool __with_affinity = _SchedulerAffinity == __scheduler_affinity::__sticky;
94113

95-
STDEXEC_ATTRIBUTE(no_unique_address)
96-
__if_c<__with_scheduler, __any_scheduler, __ignore> __scheduler_{STDEXEC::inline_scheduler{}};
97-
inplace_stop_token __stop_token_;
114+
inplace_stop_token __stop_token_;
98115

99116
public:
100117
template <class _ParentPromise>
101118
constexpr explicit __default_task_context_impl(_ParentPromise& __parent) noexcept
102119
{
103-
if constexpr (_SchedulerAffinity == __scheduler_affinity::__sticky)
120+
if constexpr (__with_affinity && __parent_promise_has_start_scheduler<_ParentPromise>())
104121
{
105-
if constexpr (__check_parent_promise_has_scheduler<_ParentPromise>())
106-
{
107-
__scheduler_ = get_scheduler(get_env(__parent));
108-
}
122+
// get_start_scheduler is used here to get the parent's "current" scheduler,
123+
// which is the one on which this task has been started (i.e., co_await-ed).
124+
auto __parent_sched = get_start_scheduler(get_env(__parent));
125+
this->__scheduler_ = __parent_sched;
109126
}
110127
}
111128

112129
template <scheduler _Scheduler>
113-
constexpr explicit __default_task_context_impl(_Scheduler&& __scheduler)
114-
: __scheduler_{static_cast<_Scheduler&&>(__scheduler)}
130+
constexpr explicit __default_task_context_impl(_Scheduler&& __sched) noexcept
131+
: __optional_scheduler_storage<_SchedulerAffinity>{static_cast<_Scheduler&&>(__sched)}
115132
{}
116133

117134
[[nodiscard]]
118-
constexpr auto query(get_scheduler_t) const noexcept -> __any_scheduler const &
119-
requires(__with_scheduler)
135+
constexpr auto query(get_start_scheduler_t) const noexcept -> __any_scheduler const &
136+
requires(__with_affinity)
120137
{
121-
return __scheduler_;
138+
return this->__scheduler_;
122139
}
123140

124141
[[nodiscard]]
@@ -130,7 +147,7 @@ namespace experimental::execution
130147
[[nodiscard]]
131148
constexpr auto query(get_completion_behavior_t<set_value_t>) const noexcept
132149
{
133-
if constexpr (__with_scheduler)
150+
if constexpr (__with_affinity)
134151
{
135152
return completion_behavior::asynchronous_affine | completion_behavior::inline_completion;
136153
}
@@ -148,24 +165,24 @@ namespace experimental::execution
148165

149166
template <scheduler _Scheduler>
150167
constexpr void set_scheduler(_Scheduler&& __sched)
151-
requires(__with_scheduler)
168+
requires(__with_affinity)
152169
{
153-
__scheduler_ = static_cast<_Scheduler&&>(__sched);
170+
this->__scheduler_ = static_cast<_Scheduler&&>(__sched);
154171
}
155172

156173
template <class _ThisPromise>
157174
using promise_context_t = __default_task_context_impl;
158175

159176
template <class _ThisPromise, class _ParentPromise = void>
160-
requires(!__with_scheduler) || __indirect_scheduler_provider<_ParentPromise>
177+
requires(!__with_affinity) || __indirect_start_scheduler_provider<_ParentPromise>
161178
using awaiter_context_t = __default_awaiter_context<_ParentPromise>;
162179
};
163180

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

167184
template <class _Ty>
168-
using __raw_task_context = __default_task_context_impl<__scheduler_affinity::__none>;
185+
using inline_task_context = __default_task_context_impl<__scheduler_affinity::__none>;
169186

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

484501
private:
485502
using __scheduler_t =
486-
__call_result_or_t<get_scheduler_t, STDEXEC::inline_scheduler, _Context>;
503+
__call_result_or_t<get_start_scheduler_t, STDEXEC::inline_scheduler, _Context>;
487504

488505
struct __final_awaitable
489506
{
@@ -541,7 +558,7 @@ namespace experimental::execution
541558

542559
#ifndef __clang_analyzer__
543560
template <sender _CvSender>
544-
requires __scheduler_provider<_Context>
561+
requires __start_scheduler_provider<_Context>
545562
auto await_transform(_CvSender&& __sndr) noexcept -> decltype(auto)
546563
{
547564
if constexpr (__completes_where_it_starts<set_value_t,
@@ -553,13 +570,13 @@ namespace experimental::execution
553570
else
554571
{
555572
return STDEXEC::as_awaitable(continues_on(static_cast<_CvSender&&>(__sndr),
556-
get_scheduler(*__context_)),
573+
get_start_scheduler(*__context_)),
557574
*this);
558575
}
559576
}
560577

561578
template <class _Scheduler>
562-
requires __scheduler_provider<_Context>
579+
requires __start_scheduler_provider<_Context>
563580
auto await_transform(__reschedule_coroutine_on_t::__wrapper<_Scheduler> __box) noexcept
564581
-> decltype(auto)
565582
{
@@ -592,6 +609,11 @@ namespace experimental::execution
592609
template <class _ParentPromise>
593610
struct __task_awaiter
594611
{
612+
constexpr __task_awaiter(__std::coroutine_handle<__promise> __coro) noexcept
613+
: __coro_(__coro)
614+
{}
615+
STDEXEC_IMMOVABLE(__task_awaiter);
616+
595617
constexpr ~__task_awaiter()
596618
{
597619
if (__coro_)
@@ -631,7 +653,7 @@ namespace experimental::execution
631653
return std::move(__var::__get<0>(__coro_.promise().__data_));
632654
}
633655

634-
__std::coroutine_handle<__promise> __coro_;
656+
__std::coroutine_handle<__promise> __coro_{};
635657
__optional<awaiter_context_t<__promise, _ParentPromise>> __context_{};
636658
};
637659

@@ -640,7 +662,7 @@ namespace experimental::execution
640662
: __coro_(__coro)
641663
{}
642664

643-
__std::coroutine_handle<promise_type> __coro_;
665+
__std::coroutine_handle<promise_type> __coro_{};
644666
};
645667
} // namespace __task
646668

include/exec/trampoline_scheduler.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,12 @@ namespace experimental::execution
6363

6464
struct __attrs
6565
{
66-
template <__one_of<set_value_t, set_stopped_t> _Tag, __queryable_with<get_scheduler_t> _Env>
66+
template <__one_of<set_value_t, set_stopped_t> _Tag,
67+
__queryable_with<get_start_scheduler_t> _Env>
6768
[[nodiscard]]
6869
constexpr auto query(get_completion_scheduler_t<_Tag>, _Env const & __env) const noexcept
6970
{
70-
return get_scheduler(__env);
71+
return get_start_scheduler(__env);
7172
}
7273

7374
template <__one_of<set_value_t, set_stopped_t> _Tag, __queryable_with<get_domain_t> _Env>

0 commit comments

Comments
 (0)