Skip to content

Commit b089bba

Browse files
authored
Merge pull request #2248 from Cra3z/fix-starts_on
Fix starts_on's sender-attributes
2 parents 1b73ba4 + 99b8133 commit b089bba

3 files changed

Lines changed: 77 additions & 23 deletions

File tree

‎include/stdexec/__detail/__starts_on.hpp‎

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -65,32 +65,9 @@ namespace STDEXEC
6565
, __attr_(__attr)
6666
{}
6767

68-
// Query for completion scheduler to use for algorithm dispatching.
69-
// NOT TO SPEC
70-
template <class... _Env>
71-
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
72-
constexpr auto query(get_completion_domain_t<>, _Env&&...) const noexcept
73-
-> __completion_domain_of_t<set_value_t, _Scheduler, _Env...>
74-
{
75-
return {};
76-
}
77-
78-
// Query for completion scheduler
79-
template <class _SetTag, class... _Env>
80-
requires __completes_where_it_starts<_SetTag, env_of_t<_Child>, __env2_t<_Env>...>
81-
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
82-
constexpr auto query(get_completion_scheduler_t<_SetTag>, _Env&&...) const noexcept
83-
-> _Scheduler
84-
{
85-
// If the child completes where it starts, then starts_on(Sch,Child) completes on
86-
// scheduler Sch.
87-
return __sched_;
88-
}
89-
9068
// Query for completion scheduler - delegates to child's env with augmented
9169
// environment
9270
template <class _SetTag, class... _Env>
93-
requires(!__completes_where_it_starts<_SetTag, env_of_t<_Child>, __env2_t<_Env>...>)
9471
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
9572
constexpr auto query(get_completion_scheduler_t<_SetTag> __query,
9673
_Env&&... __env) const noexcept

‎test/stdexec/algos/adaptors/test_starts_on.cpp‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,58 @@ namespace
319319
ex::sender auto snd = ex::starts_on(is, ex::just()) | ex::then([] {});
320320
ex::sync_wait(std::move(snd));
321321
}
322+
323+
// A sender that completes asynchronously on the same execution context that started it
324+
struct affine_sender
325+
{
326+
using sender_concept = ex::sender_tag;
327+
using completion_signatures = ex::completion_signatures<ex::set_value_t()>;
328+
329+
struct attrs
330+
{
331+
template <class Tag, class... Env>
332+
static auto query(ex::__get_completion_behavior_t<Tag>, Env&&...) noexcept
333+
{
334+
return ex::__completion_behavior::__asynchronous_affine;
335+
}
336+
};
337+
338+
template <class Receiver>
339+
static auto connect(Receiver rcvr)
340+
{
341+
return ex::connect(ex::just(), static_cast<Receiver&&>(rcvr));
342+
}
343+
344+
[[nodiscard]]
345+
static auto get_env() noexcept -> attrs
346+
{
347+
return {};
348+
}
349+
};
350+
351+
TEST_CASE("starts_on completion domain agrees with its completion scheduler when the child "
352+
"completes where it starts",
353+
"[adaptors][starts_on]")
354+
{
355+
exec::static_thread_pool pool{1};
356+
auto sched = pool.get_scheduler();
357+
using sched_t = decltype(sched);
358+
using sched_domain_t =
359+
ex::__call_result_t<ex::get_completion_domain_t<ex::set_value_t>, sched_t, ex::env<>>;
360+
361+
auto snd = ex::starts_on(sched, affine_sender{});
362+
using attrs_t = ex::env_of_t<decltype(snd)>;
363+
364+
using cmpl_sched_t =
365+
ex::__call_result_t<ex::get_completion_scheduler_t<ex::set_value_t>, attrs_t, ex::env<>>;
366+
using cmpl_domain_t =
367+
ex::__call_result_t<ex::get_completion_domain_t<ex::set_value_t>, attrs_t, ex::env<>>;
368+
STATIC_REQUIRE(std::same_as<cmpl_sched_t, sched_t>);
369+
STATIC_REQUIRE(std::same_as<cmpl_domain_t, sched_domain_t>);
370+
CHECK(ex::get_completion_scheduler<ex::set_value_t>(ex::get_env(snd), ex::env<>{}) == sched);
371+
372+
ex::sync_wait(std::move(snd));
373+
}
322374
} // namespace
323375

324376
STDEXEC_PRAGMA_POP()

‎test/stdexec/types/test_task.cpp‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,31 @@ namespace
425425
CHECK(i == 42);
426426
}
427427

428+
auto noop_task() -> ex::task<>
429+
{
430+
co_return;
431+
}
432+
433+
auto test_task_awaits_starts_on_task() -> ex::task<>
434+
{
435+
auto sched = co_await ex::read_env(ex::get_start_scheduler);
436+
co_await ex::starts_on(sched, noop_task());
437+
}
438+
439+
TEST_CASE("test starts_on(task_scheduler, task) advertises task_scheduler_domain and can be "
440+
"sync_wait'ed",
441+
"[types][task]")
442+
{
443+
exec::single_thread_context ctx;
444+
ex::task_scheduler sched{ctx.get_scheduler()};
445+
auto snd = ex::starts_on(sched, test_task_awaits_starts_on_task());
446+
using attrs_t = ex::env_of_t<decltype(snd)>;
447+
using domain_t =
448+
ex::__call_result_t<ex::get_completion_domain_t<ex::set_value_t>, attrs_t, ex::env<>>;
449+
STATIC_REQUIRE(std::same_as<domain_t, ex::task_scheduler_domain>);
450+
CHECK(ex::sync_wait(std::move(snd)).has_value());
451+
}
452+
428453
// Test affinity with a run_loop scheduler, which is infallible but not inline:
429454
struct test_env2
430455
{

0 commit comments

Comments
 (0)