TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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/capy
8 : //
9 :
10 : #include <boost/capy/ex/execution_context.hpp>
11 : #include <boost/capy/ex/recycling_memory_resource.hpp>
12 : #include <boost/capy/detail/except.hpp>
13 :
14 : namespace boost {
15 : namespace capy {
16 :
17 HIT 3641 : execution_context::
18 3641 : execution_context()
19 3641 : : frame_alloc_(get_recycling_memory_resource())
20 : {
21 3641 : }
22 :
23 3641 : execution_context::
24 : ~execution_context()
25 : {
26 : // A service created after a derived destructor destroyed the
27 : // services would be destroyed here, after the derived members it
28 : // may still reach.
29 3641 : BOOST_CAPY_ASSERT(!destroyed_ || !head_);
30 3641 : shutdown();
31 3641 : destroy();
32 3641 : }
33 :
34 : void
35 7217 : execution_context::
36 : shutdown() noexcept
37 : {
38 7217 : if(shutdown_)
39 3576 : return;
40 3641 : shutdown_ = true;
41 :
42 3641 : service* p = head_;
43 4724 : while(p)
44 : {
45 1083 : p->shutdown();
46 1083 : p = p->next_;
47 : }
48 : }
49 :
50 : void
51 6206 : execution_context::
52 : destroy() noexcept
53 : {
54 : // One at a time, so a destructor can still find the services not
55 : // yet destroyed, and one it creates is destroyed in turn.
56 7295 : while(service* p = head_)
57 : {
58 1089 : head_ = p->next_;
59 1089 : delete p;
60 1089 : }
61 6206 : destroyed_ = true;
62 6206 : }
63 :
64 : execution_context::service*
65 13642 : execution_context::
66 : find_impl(detail::type_index ti) const noexcept
67 : {
68 13642 : auto p = head_;
69 13668 : while(p)
70 : {
71 11477 : if(p->t0_ == ti || p->t1_ == ti)
72 11451 : break;
73 26 : p = p->next_;
74 : }
75 13642 : return p;
76 : }
77 :
78 : execution_context::service&
79 12491 : execution_context::
80 : use_service_impl(factory& f)
81 : {
82 12491 : std::unique_lock<std::mutex> lock(mutex_);
83 :
84 12491 : if(auto* p = find_impl(f.t0))
85 11426 : return *p;
86 :
87 1065 : lock.unlock();
88 :
89 : // Create the service outside lock, enabling nested calls
90 1065 : service* sp = f.create(*this);
91 1065 : sp->t0_ = f.t0;
92 1065 : sp->t1_ = f.t1;
93 :
94 1065 : lock.lock();
95 :
96 1065 : if(auto* p = find_impl(f.t0))
97 : {
98 : delete sp; // LCOV_EXCL_LINE concurrent same-type registration race
99 : return *p; // LCOV_EXCL_LINE concurrent same-type registration race
100 : }
101 :
102 1065 : sp->next_ = head_;
103 1065 : head_ = sp;
104 :
105 1065 : if(shutdown_)
106 : {
107 : // Created after the context shut down: it starts shut down,
108 : // like the services that already were.
109 3 : lock.unlock();
110 3 : sp->shutdown();
111 : }
112 1065 : return *sp;
113 12491 : }
114 :
115 : execution_context::service&
116 28 : execution_context::
117 : make_service_impl(factory& f)
118 : {
119 : {
120 28 : std::lock_guard<std::mutex> lock(mutex_);
121 28 : if(find_impl(f.t0))
122 2 : detail::throw_invalid_argument();
123 26 : if(f.t0 != f.t1 && find_impl(f.t1))
124 1 : detail::throw_invalid_argument();
125 28 : }
126 :
127 : // Unlocked to allow nested service creation from constructor
128 25 : service* p = f.create(*this);
129 :
130 25 : std::unique_lock<std::mutex> lock(mutex_);
131 25 : if(find_impl(f.t0))
132 : {
133 : delete p; // LCOV_EXCL_LINE concurrent same-type registration race
134 : detail::throw_invalid_argument(); // LCOV_EXCL_LINE concurrent same-type registration race
135 : }
136 :
137 25 : p->t0_ = f.t0;
138 25 : if(f.t0 != f.t1)
139 : {
140 3 : if(find_impl(f.t1))
141 : {
142 1 : delete p;
143 1 : detail::throw_invalid_argument();
144 : }
145 2 : p->t1_ = f.t1;
146 : }
147 : else
148 : {
149 22 : p->t1_ = f.t0;
150 : }
151 :
152 24 : p->next_ = head_;
153 24 : head_ = p;
154 :
155 24 : if(shutdown_)
156 : {
157 : // Created after the context shut down: it starts shut down,
158 : // like the services that already were.
159 3 : lock.unlock();
160 3 : p->shutdown();
161 : }
162 24 : return *p;
163 25 : }
164 :
165 : } // namespace capy
166 : } // namespace boost
|