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 3002 : execution_context::
18 3002 : execution_context()
19 3002 : : frame_alloc_(get_recycling_memory_resource())
20 : {
21 3002 : }
22 :
23 3002 : execution_context::
24 : ~execution_context()
25 : {
26 3002 : shutdown();
27 3002 : destroy();
28 3002 : }
29 :
30 : void
31 3159 : execution_context::
32 : shutdown() noexcept
33 : {
34 3159 : if(shutdown_)
35 157 : return;
36 3002 : shutdown_ = true;
37 :
38 3002 : service* p = head_;
39 3065 : while(p)
40 : {
41 63 : p->shutdown();
42 63 : p = p->next_;
43 : }
44 : }
45 :
46 : void
47 3159 : execution_context::
48 : destroy() noexcept
49 : {
50 3159 : service* p = head_;
51 3159 : head_ = nullptr;
52 3222 : while(p)
53 : {
54 63 : service* next = p->next_;
55 63 : delete p;
56 63 : p = next;
57 : }
58 104247 : for(auto& s : slots_)
59 101088 : s.store(nullptr, std::memory_order_relaxed);
60 3159 : }
61 :
62 : execution_context::service*
63 144 : execution_context::
64 : find_impl(detail::type_index ti) const noexcept
65 : {
66 144 : auto p = head_;
67 148 : while(p)
68 : {
69 10 : if(p->t0_ == ti || p->t1_ == ti)
70 6 : break;
71 4 : p = p->next_;
72 : }
73 144 : return p;
74 : }
75 :
76 : execution_context::service&
77 57 : execution_context::
78 : use_service_impl(factory& f)
79 : {
80 57 : std::unique_lock<std::mutex> lock(mutex_);
81 :
82 57 : if(auto* p = find_impl(f.t0))
83 : {
84 MIS 0 : if(f.slot0 < max_service_slots)
85 0 : slots_[f.slot0].store(p, std::memory_order_release);
86 0 : if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
87 0 : slots_[f.slot1].store(p, std::memory_order_release);
88 0 : return *p;
89 : }
90 :
91 HIT 57 : lock.unlock();
92 :
93 : // Create the service outside lock, enabling nested calls
94 57 : service* sp = f.create(*this);
95 57 : sp->t0_ = f.t0;
96 57 : sp->t1_ = f.t1;
97 :
98 57 : lock.lock();
99 :
100 57 : if(auto* p = find_impl(f.t0))
101 : {
102 3 : if(f.slot0 < max_service_slots)
103 3 : slots_[f.slot0].store(p, std::memory_order_release);
104 3 : if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
105 MIS 0 : slots_[f.slot1].store(p, std::memory_order_release);
106 HIT 3 : delete sp;
107 3 : return *p;
108 : }
109 :
110 54 : sp->next_ = head_;
111 54 : head_ = sp;
112 :
113 54 : if(f.slot0 < max_service_slots)
114 54 : slots_[f.slot0].store(sp, std::memory_order_release);
115 54 : if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
116 1 : slots_[f.slot1].store(sp, std::memory_order_release);
117 :
118 54 : return *sp;
119 57 : }
120 :
121 : execution_context::service&
122 12 : execution_context::
123 : make_service_impl(factory& f)
124 : {
125 : {
126 12 : std::lock_guard<std::mutex> lock(mutex_);
127 12 : if(find_impl(f.t0))
128 2 : detail::throw_invalid_argument();
129 10 : if(f.t0 != f.t1 && find_impl(f.t1))
130 1 : detail::throw_invalid_argument();
131 12 : }
132 :
133 : // Unlocked to allow nested service creation from constructor
134 9 : service* p = f.create(*this);
135 :
136 9 : std::lock_guard<std::mutex> lock(mutex_);
137 9 : if(find_impl(f.t0))
138 : {
139 MIS 0 : delete p;
140 0 : detail::throw_invalid_argument();
141 : }
142 :
143 HIT 9 : p->t0_ = f.t0;
144 9 : if(f.t0 != f.t1)
145 : {
146 2 : if(find_impl(f.t1))
147 : {
148 MIS 0 : delete p;
149 0 : detail::throw_invalid_argument();
150 : }
151 HIT 2 : p->t1_ = f.t1;
152 : }
153 : else
154 : {
155 7 : p->t1_ = f.t0;
156 : }
157 :
158 9 : p->next_ = head_;
159 9 : head_ = p;
160 :
161 9 : if(f.slot0 < max_service_slots)
162 9 : slots_[f.slot0].store(p, std::memory_order_release);
163 9 : if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
164 2 : slots_[f.slot1].store(p, std::memory_order_release);
165 :
166 9 : return *p;
167 9 : }
168 :
169 : } // namespace capy
170 : } // namespace boost
|