Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
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/beast2
8 : //
9 :
10 : #include <boost/beast2/asio_io_context.hpp>
11 : #include <boost/beast2/application.hpp>
12 : #include <boost/beast2/server/call_mf.hpp>
13 : #include <boost/asio/executor_work_guard.hpp>
14 : #include <boost/asio/signal_set.hpp>
15 : #include <thread>
16 : #include <vector>
17 :
18 : namespace boost {
19 : namespace beast2 {
20 :
21 : namespace {
22 :
23 : /** Asio's io_context as an application part
24 : */
25 : class asio_io_context_impl
26 : : public asio_io_context
27 : {
28 : public:
29 : using key_type = asio_io_context;
30 :
31 0 : ~asio_io_context_impl()
32 0 : {
33 0 : }
34 :
35 0 : asio_io_context_impl(
36 : application& app,
37 : int num_threads)
38 0 : : app_(app)
39 0 : , num_threads_(num_threads)
40 0 : , ioc_(num_threads)
41 0 : , sigs_(ioc_.get_executor(), SIGINT, SIGTERM)
42 0 : , work_(ioc_.get_executor())
43 : {
44 0 : if(num_threads > 1)
45 0 : vt_.resize(num_threads - 1);
46 0 : }
47 :
48 : executor_type
49 0 : get_executor() noexcept override
50 : {
51 0 : return ioc_.get_executor();
52 : }
53 :
54 : std::size_t
55 0 : concurrency() const noexcept override
56 : {
57 0 : return num_threads_;
58 : }
59 :
60 0 : void attach() override
61 : {
62 : // VFALCO exception catcher?
63 0 : ioc_.run();
64 :
65 : // VFALCO can't figure out where to put this
66 0 : for(auto& t : vt_)
67 0 : t.join();
68 0 : }
69 :
70 0 : void start() override
71 : {
72 : // Capture SIGINT and SIGTERM to
73 : // perform a clean shutdown
74 0 : sigs_.async_wait(call_mf(
75 : &asio_io_context_impl::on_signal, this));
76 :
77 0 : for(auto& t : vt_)
78 : {
79 0 : t = std::thread(
80 0 : [&]
81 : {
82 : // VFALCO exception catcher?
83 0 : ioc_.run();
84 0 : });
85 : }
86 0 : }
87 :
88 0 : void stop() override
89 : {
90 0 : system::error_code ec;
91 0 : sigs_.cancel(ec); // VFALCO should we use the 0-arg overload?
92 0 : work_.reset();
93 0 : }
94 :
95 : private:
96 : void
97 0 : on_signal(
98 : system::error_code const& ec, int)
99 : {
100 0 : if(ec == asio::error::operation_aborted)
101 0 : return;
102 0 : app_.stop();
103 : }
104 :
105 : application& app_;
106 : int num_threads_;
107 : asio::io_context ioc_;
108 : asio::signal_set sigs_;
109 : asio::executor_work_guard<
110 : asio::io_context::executor_type> work_;
111 : std::vector<std::thread> vt_;
112 : };
113 :
114 : } // (anon)
115 :
116 : //------------------------------------------------
117 :
118 0 : asio_io_context::
119 : ~asio_io_context() = default;
120 :
121 : auto
122 0 : install_single_threaded_asio_io_context(
123 : application& app) ->
124 : asio_io_context&
125 : {
126 : return app.emplace<
127 0 : asio_io_context_impl>(app, 1);
128 : }
129 :
130 : auto
131 0 : install_multi_threaded_asio_io_context(
132 : application& app,
133 : int num_threads) ->
134 : asio_io_context&
135 : {
136 : return app.emplace<
137 0 : asio_io_context_impl>(app, num_threads);
138 : }
139 :
140 : } // beast2
141 : } // boost
|