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 : On each read-readiness edge the drain op completes without touching the
33 : pipe, and invoke_deferred_io runs it once the descriptor lock is
34 : released. Only then does it drain the pipe and deliver the signals:
35 : delivery posts into every context watching the pipe, and a post made
36 : under this descriptor's lock would order it before another context's
37 : scheduler lock, the reverse of that scheduler's own order. The op then
38 : parks itself again, draining once more if an edge arrived meanwhile.
39 : */
40 :
41 : namespace boost::corosio::detail {
42 :
43 : struct reactor_signal_pipe_reader
44 : {
45 : struct drain_op final : reactor_op_base
46 : {
47 : reactor_signal_pipe_reader* reader = nullptr;
48 :
49 HIT 940 : void perform_io() noexcept override
50 : {
51 940 : errn = 0;
52 940 : }
53 :
54 940 : void operator()() override
55 : {
56 940 : auto& desc = reader->desc;
57 : for (;;)
58 : {
59 941 : posix_signal_detail::drain_signal_pipe();
60 941 : conditionally_enabled_mutex::scoped_lock lock(desc.mutex);
61 : // An edge seen while unparked set read_ready instead.
62 941 : if (!desc.read_ready)
63 : {
64 940 : desc.read_op = this;
65 940 : break;
66 : }
67 1 : desc.read_ready = false;
68 942 : }
69 : // A select() started while this op was out ran without the
70 : // pipe in its read set.
71 940 : desc.scheduler_->notify_reparked();
72 : // Nothing counted this op as work; balance the decrement
73 : // that follows the inline run of a completed op.
74 940 : desc.scheduler_->compensating_work_started();
75 940 : }
76 :
77 MIS 0 : void destroy() override {}
78 : };
79 :
80 : reactor_descriptor_state desc;
81 : drain_op op;
82 :
83 : // Park the drain op and return the descriptor to hand to
84 : // scheduler::register_descriptor(read_fd, ...).
85 HIT 555 : reactor_descriptor_state* arm() noexcept
86 : {
87 555 : op.reader = this;
88 555 : desc.read_op = &op;
89 555 : return &desc;
90 : }
91 : };
92 :
93 : } // namespace boost::corosio::detail
94 :
95 : #endif // BOOST_COROSIO_POSIX
96 :
97 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SIGNAL_PIPE_HPP
|