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
1 change: 1 addition & 0 deletions test/exec/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set(exec_test_sources
$<$<BOOL:${STDEXEC_ENABLE_IO_URING}>:test_io_uring_context.cpp>
$<$<BOOL:${STDEXEC_ENABLE_WINDOWS_THREAD_POOL}>:test_windows_thread_pool_context.cpp>
test_trampoline_scheduler.cpp
test_scheduler_concept.cpp
test_sequence_senders.cpp
test_static_thread_pool.cpp
test_just_from.cpp
Expand Down
4 changes: 4 additions & 0 deletions test/exec/test_io_uring_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ namespace
{
STATIC_REQUIRE(timed_scheduler<io_uring_scheduler>);
STATIC_REQUIRE_FALSE(std::is_move_assignable_v<io_uring_context>);

// regression guard for issue #2134: per [exec.sched], schedulers must
// provide the scheduler_concept nested alias
STATIC_REQUIRE(std::same_as<io_uring_scheduler::scheduler_concept, STDEXEC::scheduler_tag>);
}

TEST_CASE("io_uring_context Schedule runs in io thread", "[types][io_uring][schedulers]")
Expand Down
8 changes: 8 additions & 0 deletions test/exec/test_libdispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,12 @@ namespace
REQUIRE(result.has_value());
CHECK(std::get<0>(*result) == 42);
}

TEST_CASE("libdispatch scheduler provides scheduler_concept", "[types][libdispatch][schedulers]")
{
// regression guard for issue #2134: per [exec.sched], schedulers must
// provide the scheduler_concept nested alias
STATIC_REQUIRE(
std::same_as<exec::libdispatch_scheduler::scheduler_concept, STDEXEC::scheduler_tag>);
}
} // namespace
100 changes: 100 additions & 0 deletions test/exec/test_scheduler_concept.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2026 NVIDIA Corporation
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <test_common/catch2.hpp>

#include <stdexec/execution.hpp>

#include <exec/reschedule.hpp>
#include <exec/static_thread_pool.hpp>
#include <exec/thread_pool_base.hpp>
#include <exec/timed_thread_scheduler.hpp>
#include <exec/trampoline_scheduler.hpp>

#if STDEXEC_USE_MODULES()
import std;
#else
# include <concepts>
# include <type_traits>
#endif

// Regression tests for issue #2134: per [exec.sched], a scheduler type must
// define a nested `scheduler_concept` alias derived from `scheduler_tag`.
// These tests fail to compile if a scheduler in stdexec forgets it.

namespace ex = STDEXEC;

namespace
{
template <class Sch>
concept has_scheduler_concept = requires {
typename Sch::scheduler_concept;
requires std::derived_from<typename Sch::scheduler_concept, ex::scheduler_tag>;
};

#if !STDEXEC_NO_STDCPP_EXCEPTIONS()
class inline_test_thread_pool : public exec::thread_pool_base<inline_test_thread_pool>
{
public:
[[nodiscard]]
auto available_parallelism() const noexcept -> std::uint32_t
{
return 1;
}

[[nodiscard]]
static constexpr auto forward_progress_guarantee() noexcept -> ex::forward_progress_guarantee
{
return ex::forward_progress_guarantee::parallel;
}

void enqueue(exec::_pool_::task_base* task, std::uint32_t tid = 0) noexcept
{
++enqueued_;
task->execute_(task, tid);
}

std::uint32_t enqueued_ = 0;
};
#endif

TEST_CASE("schedulers provide the scheduler_concept nested alias",
"[types][schedulers][scheduler_concept]")
{
STATIC_REQUIRE(has_scheduler_concept<ex::inline_scheduler>);
STATIC_REQUIRE(has_scheduler_concept<ex::run_loop::scheduler>);
STATIC_REQUIRE(has_scheduler_concept<ex::task_scheduler>);
STATIC_REQUIRE(has_scheduler_concept<ex::parallel_scheduler>);
STATIC_REQUIRE(has_scheduler_concept<exec::static_thread_pool::scheduler>);
#if !STDEXEC_NO_STDCPP_EXCEPTIONS()
STATIC_REQUIRE(has_scheduler_concept<inline_test_thread_pool::scheduler>);
#endif
STATIC_REQUIRE(has_scheduler_concept<exec::timed_thread_scheduler>);
STATIC_REQUIRE(has_scheduler_concept<exec::trampoline_scheduler>);
STATIC_REQUIRE(has_scheduler_concept<exec::__resched::__scheduler>);
}

TEST_CASE("schedulers satisfy the stdexec scheduler concept",
"[types][schedulers][scheduler_concept]")
{
STATIC_REQUIRE(ex::scheduler<ex::inline_scheduler>);
STATIC_REQUIRE(ex::scheduler<ex::run_loop::scheduler>);
STATIC_REQUIRE(ex::scheduler<ex::task_scheduler>);
STATIC_REQUIRE(ex::scheduler<ex::parallel_scheduler>);
STATIC_REQUIRE(ex::scheduler<exec::static_thread_pool::scheduler>);
STATIC_REQUIRE(ex::scheduler<exec::trampoline_scheduler>);
}
} // namespace
9 changes: 9 additions & 0 deletions test/exec/test_windows_thread_pool_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@

using namespace std::chrono_literals;

TEST_CASE("windows_thread_pool scheduler provides scheduler_concept",
"[types][windows_thread_pool][schedulers]")
{
// regression guard for issue #2134: per [exec.sched], schedulers must
// provide the scheduler_concept nested alias
STATIC_REQUIRE(
std::same_as<exec::windows_thread_pool::scheduler::scheduler_concept, STDEXEC::scheduler_tag>);
}

TEST_CASE("windows_thread_pool: construct_destruct", "[types][windows_thread_pool][schedulers]")
{
exec::windows_thread_pool tp;
Expand Down
13 changes: 13 additions & 0 deletions test/nvexec/scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,17 @@ namespace
CHECK_FALSE(normal == low);
CHECK_FALSE(high == low);
}

TEST_CASE("nvexec stream schedulers provide scheduler_concept", "[cuda][stream][scheduler]")
{
// regression guard for issue #2134: per [exec.sched], schedulers must
// provide the scheduler_concept nested alias
STATIC_REQUIRE(
std::same_as<nvexec::stream_scheduler::scheduler_concept, STDEXEC::scheduler_tag>);
STATIC_REQUIRE(
std::same_as<nvexec::multi_gpu_stream_scheduler::scheduler_concept, STDEXEC::scheduler_tag>);

nvexec::stream_context stream_ctx{};
STATIC_REQUIRE(std::same_as<decltype(stream_ctx.get_scheduler()), nvexec::stream_scheduler>);
}
} // namespace
Loading