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