src/ex/execution_context.cpp

100.0% Lines (70 / 70, 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 3631x execution_context::
18 3631x execution_context()
19 3631x : frame_alloc_(get_recycling_memory_resource())
20 {
21 3631x }
22
23 3631x execution_context::
24 ~execution_context()
25 {
26 3631x shutdown();
27 3631x destroy();
28 3631x }
29
30 void
31 7197x execution_context::
32 shutdown() noexcept
33 {
34 7197x if(shutdown_)
35 3566x return;
36 3631x shutdown_ = true;
37
38 3631x service* p = head_;
39 4711x while(p)
40 {
41 1080x p->shutdown();
42 1080x p = p->next_;
43 }
44 }
45
46 void
47 6194x execution_context::
48 destroy() noexcept
49 {
50 // One at a time, so a destructor can still find the services not
51 // yet destroyed, and one it creates is destroyed in turn.
52 7280x while(service* p = head_)
53 {
54 1086x head_ = p->next_;
55 1086x delete p;
56 1086x }
57 6194x }
58
59 execution_context::service*
60 13636x execution_context::
61 find_impl(detail::type_index ti) const noexcept
62 {
63 13636x auto p = head_;
64 13650x while(p)
65 {
66 11465x if(p->t0_ == ti || p->t1_ == ti)
67 11451x break;
68 14x p = p->next_;
69 }
70 13636x return p;
71 }
72
73 execution_context::service&
74 12490x execution_context::
75 use_service_impl(factory& f)
76 {
77 12490x std::unique_lock<std::mutex> lock(mutex_);
78
79 12490x if(auto* p = find_impl(f.t0))
80 11426x return *p;
81
82 1064x lock.unlock();
83
84 // Create the service outside lock, enabling nested calls
85 1064x service* sp = f.create(*this);
86 1064x sp->t0_ = f.t0;
87 1064x sp->t1_ = f.t1;
88
89 1064x lock.lock();
90
91 1064x if(auto* p = find_impl(f.t0))
92 {
93 − delete sp; // LCOV_EXCL_LINE concurrent same-type registration race
94 − return *p; // LCOV_EXCL_LINE concurrent same-type registration race
95 }
96
97 1064x sp->next_ = head_;
98 1064x head_ = sp;
99
100 1064x if(shutdown_)
101 {
102 // Created after the context shut down: it starts shut down,
103 // like the services that already were.
104 3x lock.unlock();
105 3x sp->shutdown();
106 }
107 1064x return *sp;
108 12490x }
109
110 execution_context::service&
111 26x execution_context::
112 make_service_impl(factory& f)
113 {
114 {
115 26x std::lock_guard<std::mutex> lock(mutex_);
116 26x if(find_impl(f.t0))
117 2x detail::throw_invalid_argument();
118 24x if(f.t0 != f.t1 && find_impl(f.t1))
119 1x detail::throw_invalid_argument();
120 26x }
121
122 // Unlocked to allow nested service creation from constructor
123 23x service* p = f.create(*this);
124
125 23x std::unique_lock<std::mutex> lock(mutex_);
126 23x if(find_impl(f.t0))
127 {
128 − delete p; // LCOV_EXCL_LINE concurrent same-type registration race
129 − detail::throw_invalid_argument(); // LCOV_EXCL_LINE concurrent same-type registration race
130 }
131
132 23x p->t0_ = f.t0;
133 23x if(f.t0 != f.t1)
134 {
135 3x if(find_impl(f.t1))
136 {
137 1x delete p;
138 1x detail::throw_invalid_argument();
139 }
140 2x p->t1_ = f.t1;
141 }
142 else
143 {
144 20x p->t1_ = f.t0;
145 }
146
147 22x p->next_ = head_;
148 22x head_ = p;
149
150 22x if(shutdown_)
151 {
152 // Created after the context shut down: it starts shut down,
153 // like the services that already were.
154 3x lock.unlock();
155 3x p->shutdown();
156 }
157 22x return *p;
158 23x }
159
160 } // namespace capy
161 } // namespace boost
162