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 3630 : execution_context::
18 3630 : execution_context()
19 3630 : : frame_alloc_(get_recycling_memory_resource())
20 : {
21 3630 : }
22 :
23 3630 : execution_context::
24 : ~execution_context()
25 : {
26 3630 : shutdown();
27 3630 : destroy();
28 3630 : }
29 :
30 : void
31 7195 : execution_context::
32 : shutdown() noexcept
33 : {
34 7195 : if(shutdown_)
35 3565 : return;
36 3630 : shutdown_ = true;
37 :
38 3630 : service* p = head_;
39 4710 : while(p)
40 : {
41 1080 : p->shutdown();
42 1080 : p = p->next_;
43 : }
44 : }
45 :
46 : void
47 6192 : 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 7278 : while(service* p = head_)
53 : {
54 1086 : head_ = p->next_;
55 1086 : delete p;
56 1086 : }
57 6192 : }
58 :
59 : execution_context::service*
60 13636 : execution_context::
61 : find_impl(detail::type_index ti) const noexcept
62 : {
63 13636 : auto p = head_;
64 13650 : while(p)
65 : {
66 11465 : if(p->t0_ == ti || p->t1_ == ti)
67 11451 : break;
68 14 : p = p->next_;
69 : }
70 13636 : return p;
71 : }
72 :
73 : execution_context::service&
74 12490 : execution_context::
75 : use_service_impl(factory& f)
76 : {
77 12490 : std::unique_lock<std::mutex> lock(mutex_);
78 :
79 12490 : if(auto* p = find_impl(f.t0))
80 11426 : return *p;
81 :
82 1064 : lock.unlock();
83 :
84 : // Create the service outside lock, enabling nested calls
85 1064 : service* sp = f.create(*this);
86 1064 : sp->t0_ = f.t0;
87 1064 : sp->t1_ = f.t1;
88 :
89 1064 : lock.lock();
90 :
91 1064 : 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 1064 : sp->next_ = head_;
98 1064 : head_ = sp;
99 :
100 1064 : if(shutdown_)
101 : {
102 : // Created after the context shut down: it starts shut down,
103 : // like the services that already were.
104 3 : lock.unlock();
105 3 : sp->shutdown();
106 : }
107 1064 : return *sp;
108 12490 : }
109 :
110 : execution_context::service&
111 26 : execution_context::
112 : make_service_impl(factory& f)
113 : {
114 : {
115 26 : std::lock_guard<std::mutex> lock(mutex_);
116 26 : if(find_impl(f.t0))
117 2 : detail::throw_invalid_argument();
118 24 : if(f.t0 != f.t1 && find_impl(f.t1))
119 1 : detail::throw_invalid_argument();
120 26 : }
121 :
122 : // Unlocked to allow nested service creation from constructor
123 23 : service* p = f.create(*this);
124 :
125 23 : std::unique_lock<std::mutex> lock(mutex_);
126 23 : 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 23 : p->t0_ = f.t0;
133 23 : if(f.t0 != f.t1)
134 : {
135 3 : if(find_impl(f.t1))
136 : {
137 1 : delete p;
138 1 : detail::throw_invalid_argument();
139 : }
140 2 : p->t1_ = f.t1;
141 : }
142 : else
143 : {
144 20 : p->t1_ = f.t0;
145 : }
146 :
147 22 : p->next_ = head_;
148 22 : head_ = p;
149 :
150 22 : if(shutdown_)
151 : {
152 : // Created after the context shut down: it starts shut down,
153 : // like the services that already were.
154 3 : lock.unlock();
155 3 : p->shutdown();
156 : }
157 22 : return *p;
158 23 : }
159 :
160 : } // namespace capy
161 : } // namespace boost
|