src/ex/execution_context.cpp

100.0% Lines (72 / 72, 4 excl) 87.5% Functions (7 / 8)
execution_context.cpp
f(x) Functions (8)
Line TLA Hits 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 3641x execution_context::
18 3641x execution_context()
19 3641x : frame_alloc_(get_recycling_memory_resource())
20 {
21 3641x }
22
23 3641x 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 3641x BOOST_CAPY_ASSERT(!destroyed_ || !head_);
30 3641x shutdown();
31 3641x destroy();
32 3641x }
33
34 void
35 7217x execution_context::
36 shutdown() noexcept
37 {
38 7217x if(shutdown_)
39 3576x return;
40 3641x shutdown_ = true;
41
42 3641x service* p = head_;
43 4724x while(p)
44 {
45 1083x p->shutdown();
46 1083x p = p->next_;
47 }
48 }
49
50 void
51 6206x 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 7295x while(service* p = head_)
57 {
58 1089x head_ = p->next_;
59 1089x delete p;
60 1089x }
61 6206x destroyed_ = true;
62 6206x }
63
64 execution_context::service*
65 13642x execution_context::
66 find_impl(detail::type_index ti) const noexcept
67 {
68 13642x auto p = head_;
69 13668x while(p)
70 {
71 11477x if(p->t0_ == ti || p->t1_ == ti)
72 11451x break;
73 26x p = p->next_;
74 }
75 13642x return p;
76 }
77
78 execution_context::service&
79 12491x execution_context::
80 use_service_impl(factory& f)
81 {
82 12491x std::unique_lock<std::mutex> lock(mutex_);
83
84 12491x if(auto* p = find_impl(f.t0))
85 11426x return *p;
86
87 1065x lock.unlock();
88
89 // Create the service outside lock, enabling nested calls
90 1065x service* sp = f.create(*this);
91 1065x sp->t0_ = f.t0;
92 1065x sp->t1_ = f.t1;
93
94 1065x lock.lock();
95
96 1065x 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 1065x sp->next_ = head_;
103 1065x head_ = sp;
104
105 1065x if(shutdown_)
106 {
107 // Created after the context shut down: it starts shut down,
108 // like the services that already were.
109 3x lock.unlock();
110 3x sp->shutdown();
111 }
112 1065x return *sp;
113 12491x }
114
115 execution_context::service&
116 28x execution_context::
117 make_service_impl(factory& f)
118 {
119 {
120 28x std::lock_guard<std::mutex> lock(mutex_);
121 28x if(find_impl(f.t0))
122 2x detail::throw_invalid_argument();
123 26x if(f.t0 != f.t1 && find_impl(f.t1))
124 1x detail::throw_invalid_argument();
125 28x }
126
127 // Unlocked to allow nested service creation from constructor
128 25x service* p = f.create(*this);
129
130 25x std::unique_lock<std::mutex> lock(mutex_);
131 25x 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 25x p->t0_ = f.t0;
138 25x if(f.t0 != f.t1)
139 {
140 3x if(find_impl(f.t1))
141 {
142 1x delete p;
143 1x detail::throw_invalid_argument();
144 }
145 2x p->t1_ = f.t1;
146 }
147 else
148 {
149 22x p->t1_ = f.t0;
150 }
151
152 24x p->next_ = head_;
153 24x head_ = p;
154
155 24x if(shutdown_)
156 {
157 // Created after the context shut down: it starts shut down,
158 // like the services that already were.
159 3x lock.unlock();
160 3x p->shutdown();
161 }
162 24x return *p;
163 25x }
164
165 } // namespace capy
166 } // namespace boost
167