Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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 107 : execution_context::
18 107 : execution_context()
19 107 : : frame_alloc_(get_recycling_memory_resource())
20 : {
21 107 : }
22 :
23 107 : execution_context::
24 : ~execution_context()
25 : {
26 107 : shutdown();
27 107 : destroy();
28 107 : }
29 :
30 : void
31 165 : execution_context::
32 : shutdown() noexcept
33 : {
34 165 : if(shutdown_)
35 58 : return;
36 107 : shutdown_ = true;
37 :
38 107 : service* p = head_;
39 142 : while(p)
40 : {
41 35 : p->shutdown();
42 35 : p = p->next_;
43 : }
44 : }
45 :
46 : void
47 165 : execution_context::
48 : destroy() noexcept
49 : {
50 165 : service* p = head_;
51 165 : head_ = nullptr;
52 200 : while(p)
53 : {
54 35 : service* next = p->next_;
55 35 : delete p;
56 35 : p = next;
57 : }
58 165 : }
59 :
60 : execution_context::service*
61 113 : execution_context::
62 : find_impl(detail::type_index ti) const noexcept
63 : {
64 113 : auto p = head_;
65 120 : while(p)
66 : {
67 43 : if(p->t0_ == ti || p->t1_ == ti)
68 36 : break;
69 7 : p = p->next_;
70 : }
71 113 : return p;
72 : }
73 :
74 : execution_context::service&
75 42 : execution_context::
76 : use_service_impl(factory& f)
77 : {
78 42 : std::unique_lock<std::mutex> lock(mutex_);
79 :
80 42 : if(auto* p = find_impl(f.t0))
81 14 : return *p;
82 :
83 28 : lock.unlock();
84 :
85 : // Create the service outside lock, enabling nested calls
86 28 : service* sp = f.create(*this);
87 28 : sp->t0_ = f.t0;
88 28 : sp->t1_ = f.t1;
89 :
90 28 : lock.lock();
91 :
92 28 : if(auto* p = find_impl(f.t0))
93 : {
94 0 : delete sp;
95 0 : return *p;
96 : }
97 :
98 28 : sp->next_ = head_;
99 28 : head_ = sp;
100 :
101 28 : return *sp;
102 42 : }
103 :
104 : execution_context::service&
105 10 : execution_context::
106 : make_service_impl(factory& f)
107 : {
108 : {
109 10 : std::lock_guard<std::mutex> lock(mutex_);
110 10 : if(find_impl(f.t0))
111 2 : detail::throw_invalid_argument();
112 8 : if(f.t0 != f.t1 && find_impl(f.t1))
113 1 : detail::throw_invalid_argument();
114 10 : }
115 :
116 : // Unlocked to allow nested service creation from constructor
117 7 : service* p = f.create(*this);
118 :
119 7 : std::lock_guard<std::mutex> lock(mutex_);
120 7 : if(find_impl(f.t0))
121 : {
122 0 : delete p;
123 0 : detail::throw_invalid_argument();
124 : }
125 :
126 7 : p->t0_ = f.t0;
127 7 : if(f.t0 != f.t1)
128 : {
129 1 : if(find_impl(f.t1))
130 : {
131 0 : delete p;
132 0 : detail::throw_invalid_argument();
133 : }
134 1 : p->t1_ = f.t1;
135 : }
136 : else
137 : {
138 6 : p->t1_ = f.t0;
139 : }
140 :
141 7 : p->next_ = head_;
142 7 : head_ = p;
143 :
144 7 : return *p;
145 7 : }
146 :
147 : } // namespace capy
148 : } // namespace boost
|