include/boost/corosio/detail/scheduler.hpp
25.0% Lines (1/4)
25.0% List of functions (1/4)
-% Branches (0/0)
Functions (4)
Function
Calls
Lines
Blocks
boost::corosio::detail::scheduler::~scheduler()
:35
615x
100.0%
100.0%
boost::corosio::detail::scheduler::register_signal_reader(int)
:98
0
0.0%
0.0%
boost::corosio::detail::scheduler::scheduler_locking_disabled() const
:115
0
0.0%
0.0%
boost::corosio::detail::scheduler::configure_threading(boost::corosio::detail::scheduler::threading_config)
:118
0
0.0%
0.0%
| Line | TLA | Hits | Source Code |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2025 Vinnie Falco ([email protected]) | ||
| 3 | // Copyright (c) 2026 Steve Gerbino | ||
| 4 | // Copyright (c) 2026 Michael Vandeberg | ||
| 5 | // | ||
| 6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| 7 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 8 | // | ||
| 9 | // Official repository: https://github.com/cppalliance/corosio | ||
| 10 | // | ||
| 11 | |||
| 12 | #ifndef BOOST_COROSIO_DETAIL_SCHEDULER_HPP | ||
| 13 | #define BOOST_COROSIO_DETAIL_SCHEDULER_HPP | ||
| 14 | |||
| 15 | #include <boost/corosio/detail/config.hpp> | ||
| 16 | #include <boost/capy/continuation.hpp> | ||
| 17 | #include <coroutine> | ||
| 18 | |||
| 19 | #include <cstddef> | ||
| 20 | |||
| 21 | namespace boost::corosio::detail { | ||
| 22 | |||
| 23 | class scheduler_op; | ||
| 24 | |||
| 25 | /** Define the abstract interface for the event loop scheduler. | ||
| 26 | |||
| 27 | Concrete backends (epoll, IOCP, kqueue, select) derive from | ||
| 28 | this to implement the reactor/proactor event loop. The | ||
| 29 | @ref io_context delegates all scheduling operations here. | ||
| 30 | |||
| 31 | @see io_context | ||
| 32 | */ | ||
| 33 | struct BOOST_COROSIO_DECL scheduler | ||
| 34 | { | ||
| 35 | 615x | virtual ~scheduler() = default; | |
| 36 | |||
| 37 | /// Post a coroutine handle for deferred execution. | ||
| 38 | virtual void post(std::coroutine_handle<>) const = 0; | ||
| 39 | |||
| 40 | /// Post a scheduler operation for deferred execution. | ||
| 41 | virtual void post(scheduler_op*) const = 0; | ||
| 42 | |||
| 43 | /// Post a continuation for deferred execution (zero-allocation). | ||
| 44 | virtual void post(capy::continuation&) const = 0; | ||
| 45 | |||
| 46 | /// Increment the outstanding work count. | ||
| 47 | virtual void work_started() noexcept = 0; | ||
| 48 | |||
| 49 | /// Decrement the outstanding work count. | ||
| 50 | virtual void work_finished() noexcept = 0; | ||
| 51 | |||
| 52 | /// Check if the calling thread is running the event loop. | ||
| 53 | virtual bool running_in_this_thread() const noexcept = 0; | ||
| 54 | |||
| 55 | /// Signal the event loop to stop. | ||
| 56 | virtual void stop() = 0; | ||
| 57 | |||
| 58 | /// Check if the event loop has been stopped. | ||
| 59 | virtual bool stopped() const noexcept = 0; | ||
| 60 | |||
| 61 | /// Reset the stopped state so `run()` can be called again. | ||
| 62 | virtual void restart() = 0; | ||
| 63 | |||
| 64 | /// Run the event loop, blocking until all work completes. | ||
| 65 | virtual std::size_t run() = 0; | ||
| 66 | |||
| 67 | /// Run one handler, blocking until one completes. | ||
| 68 | virtual std::size_t run_one() = 0; | ||
| 69 | |||
| 70 | /** Run one handler, blocking up to @p usec microseconds. | ||
| 71 | |||
| 72 | @param usec Maximum wait time in microseconds. | ||
| 73 | |||
| 74 | @return The number of handlers executed (0 or 1). | ||
| 75 | */ | ||
| 76 | virtual std::size_t wait_one(long usec) = 0; | ||
| 77 | |||
| 78 | /// Run all ready handlers without blocking. | ||
| 79 | virtual std::size_t poll() = 0; | ||
| 80 | |||
| 81 | /// Run at most one ready handler without blocking. | ||
| 82 | virtual std::size_t poll_one() = 0; | ||
| 83 | |||
| 84 | /** Register the read end of the POSIX signal self-pipe. | ||
| 85 | |||
| 86 | Called once (by the first signal_set to register a signal) so the | ||
| 87 | backend's event loop watches @p read_fd for readability. When the | ||
| 88 | pipe becomes readable the backend drains it and calls | ||
| 89 | `posix_signal_service::deliver_signal` for each pending signal, in | ||
| 90 | normal thread context. This keeps the C signal handler | ||
| 91 | async-signal-safe: it only writes the signal number to the pipe. | ||
| 92 | |||
| 93 | POSIX backends override this; the default is a no-op (Windows/IOCP | ||
| 94 | uses synchronous C-runtime signal handling instead). | ||
| 95 | |||
| 96 | @param read_fd The read end of the global signal self-pipe. | ||
| 97 | */ | ||
| 98 | ✗ | virtual void register_signal_reader(int read_fd) { (void)read_fd; } | |
| 99 | |||
| 100 | /// Decomposed threading configuration applied via @ref configure_threading. | ||
| 101 | struct threading_config | ||
| 102 | { | ||
| 103 | /// Scheduler mutex/condvar enabled. Off only in the `unsafe` tier. | ||
| 104 | bool scheduler_locking = true; | ||
| 105 | /// Per-descriptor (reactor) or ring (io_uring) I/O lock enabled. | ||
| 106 | /// Off in the `unsafe_io` and `unsafe` tiers. | ||
| 107 | bool reactor_io_locking = true; | ||
| 108 | /// A single run thread is guaranteed (a lockless tier): elide | ||
| 109 | /// inter-run-thread wakeups. | ||
| 110 | bool one_thread = false; | ||
| 111 | }; | ||
| 112 | |||
| 113 | /// True in the fully-lockless (`unsafe`) tier. The resolver and POSIX | ||
| 114 | /// file services gate their `operation_not_supported` result on this. | ||
| 115 | ✗ | virtual bool scheduler_locking_disabled() const noexcept { return false; } | |
| 116 | |||
| 117 | /// Apply @ref threading_config. Default no-op. | ||
| 118 | ✗ | virtual void configure_threading(threading_config) noexcept {} | |
| 119 | }; | ||
| 120 | |||
| 121 | } // namespace boost::corosio::detail | ||
| 122 | |||
| 123 | #endif | ||
| 124 |