TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/corosio
8 : //
9 :
10 : #ifndef BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SIGNAL_PIPE_HPP
11 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SIGNAL_PIPE_HPP
12 :
13 : #include <boost/corosio/detail/platform.hpp>
14 :
15 : #if BOOST_COROSIO_POSIX
16 :
17 : #include <boost/corosio/native/detail/posix/posix_signal_service.hpp>
18 : #include <boost/corosio/native/detail/reactor/reactor_descriptor_state.hpp>
19 : #include <boost/corosio/native/detail/reactor/reactor_op_base.hpp>
20 :
21 : #include <errno.h>
22 :
23 : /*
24 : Reactor signal-pipe reader
25 : ==========================
26 :
27 : Bridges the global POSIX signal self-pipe (see posix_signal_service.hpp)
28 : to the reactor backends (epoll/kqueue/select). The concrete scheduler owns
29 : one of these for its lifetime and, in register_signal_reader(), parks the
30 : drain op as the descriptor's read_op then calls register_descriptor().
31 :
32 : The drain op never completes: on each read-readiness edge, invoke_deferred_io
33 : calls perform_io(), which drains the pipe and delivers the pending signals,
34 : then reports EAGAIN so the op stays parked and re-fires on the next edge —
35 : exactly the path a socket read op takes when the kernel has no more data.
36 : Because deliver_signal() runs here, in normal dispatch context (not in the
37 : signal handler and not under the reactor poll lock), its mutex locking is
38 : safe.
39 : */
40 :
41 : namespace boost::corosio::detail {
42 :
43 : struct reactor_signal_pipe_reader
44 : {
45 : // Parked read op: drains the self-pipe and re-arms via EAGAIN.
46 : struct drain_op final : reactor_op_base
47 : {
48 HIT 300 : void perform_io() noexcept override
49 : {
50 300 : posix_signal_detail::drain_signal_pipe();
51 : // Stay parked: EAGAIN tells invoke_deferred_io to keep this op
52 : // installed as read_op and re-run it on the next readiness edge.
53 300 : errn = EAGAIN;
54 300 : }
55 : };
56 :
57 : reactor_descriptor_state desc;
58 : drain_op op;
59 :
60 : // Park the drain op and return the descriptor to hand to
61 : // scheduler::register_descriptor(read_fd, ...).
62 82 : reactor_descriptor_state* arm() noexcept
63 : {
64 82 : desc.read_op = &op;
65 82 : return &desc;
66 : }
67 : };
68 :
69 : } // namespace boost::corosio::detail
70 :
71 : #endif // BOOST_COROSIO_POSIX
72 :
73 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SIGNAL_PIPE_HPP
|