100.00% Lines (72/72) 100.00% Functions (7/7)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/capy 7   // Official repository: https://github.com/cppalliance/capy
8   // 8   //
9   9  
10   #include <boost/capy/ex/execution_context.hpp> 10   #include <boost/capy/ex/execution_context.hpp>
11   #include <boost/capy/ex/recycling_memory_resource.hpp> 11   #include <boost/capy/ex/recycling_memory_resource.hpp>
12   #include <boost/capy/detail/except.hpp> 12   #include <boost/capy/detail/except.hpp>
13   13  
14   namespace boost { 14   namespace boost {
15   namespace capy { 15   namespace capy {
16   16  
HITCBC 17   3640 execution_context:: 17   3606 execution_context::
HITCBC 18   3640 execution_context() 18   3606 execution_context()
HITCBC 19   3640 : frame_alloc_(get_recycling_memory_resource()) 19   3606 : frame_alloc_(get_recycling_memory_resource())
20   { 20   {
HITCBC 21   3640 } 21   3606 }
22   22  
HITCBC 23   3640 execution_context:: 23   3606 execution_context::
24   ~execution_context() 24   ~execution_context()
25   { 25   {
26   // A service created after a derived destructor destroyed the 26   // A service created after a derived destructor destroyed the
27   // services would be destroyed here, after the derived members it 27   // services would be destroyed here, after the derived members it
28   // may still reach. 28   // may still reach.
HITCBC 29   3640 BOOST_CAPY_ASSERT(!destroyed_ || !head_); 29   3606 BOOST_CAPY_ASSERT(!destroyed_ || !head_);
HITCBC 30   3640 shutdown(); 30   3606 shutdown();
HITCBC 31   3640 destroy(); 31   3606 destroy();
HITCBC 32   3640 } 32   3606 }
33   33  
34   void 34   void
HITCBC 35   7215 execution_context:: 35   7147 execution_context::
36   shutdown() noexcept 36   shutdown() noexcept
37   { 37   {
HITCBC 38   7215 if(shutdown_) 38   7147 if(shutdown_)
HITCBC 39   3575 return; 39   3541 return;
HITCBC 40   3640 shutdown_ = true; 40   3606 shutdown_ = true;
41   41  
HITCBC 42   3640 service* p = head_; 42   3606 service* p = head_;
HITCBC 43   4723 while(p) 43   4689 while(p)
44   { 44   {
HITCBC 45   1083 p->shutdown(); 45   1083 p->shutdown();
HITCBC 46   1083 p = p->next_; 46   1083 p = p->next_;
47   } 47   }
48   } 48   }
49   49  
50   void 50   void
HITCBC 51   6204 execution_context:: 51   6136 execution_context::
52   destroy() noexcept 52   destroy() noexcept
53   { 53   {
54   // One at a time, so a destructor can still find the services not 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. 55   // yet destroyed, and one it creates is destroyed in turn.
HITCBC 56   7293 while(service* p = head_) 56   7225 while(service* p = head_)
57   { 57   {
HITCBC 58   1089 head_ = p->next_; 58   1089 head_ = p->next_;
HITCBC 59   1089 delete p; 59   1089 delete p;
HITCBC 60   1089 } 60   1089 }
HITCBC 61   6204 destroyed_ = true; 61   6136 destroyed_ = true;
HITCBC 62   6204 } 62   6136 }
63   63  
64   execution_context::service* 64   execution_context::service*
HITCBC 65   13642 execution_context:: 65   13644 execution_context::
66   find_impl(detail::type_index ti) const noexcept 66   find_impl(detail::type_index ti) const noexcept
67   { 67   {
HITCBC 68   13642 auto p = head_; 68   13644 auto p = head_;
HITCBC 69   13668 while(p) 69   13670 while(p)
70   { 70   {
HITCBC 71   11477 if(p->t0_ == ti || p->t1_ == ti) 71   11477 if(p->t0_ == ti || p->t1_ == ti)
HITCBC 72   11451 break; 72   11451 break;
HITCBC 73   26 p = p->next_; 73   26 p = p->next_;
74   } 74   }
HITCBC 75   13642 return p; 75   13644 return p;
76   } 76   }
77   77  
78   execution_context::service& 78   execution_context::service&
HITCBC 79   12491 execution_context:: 79   12491 execution_context::
80   use_service_impl(factory& f) 80   use_service_impl(factory& f)
81   { 81   {
HITCBC 82   12491 std::unique_lock<std::mutex> lock(mutex_); 82   12491 std::unique_lock<std::mutex> lock(mutex_);
83   83  
HITCBC 84   12491 if(auto* p = find_impl(f.t0)) 84   12491 if(auto* p = find_impl(f.t0))
HITCBC 85   11426 return *p; 85   11424 return *p;
86   86  
HITCBC 87   1065 lock.unlock(); 87   1067 lock.unlock();
88   88  
89   // Create the service outside lock, enabling nested calls 89   // Create the service outside lock, enabling nested calls
HITCBC 90   1065 service* sp = f.create(*this); 90   1067 service* sp = f.create(*this);
HITCBC 91   1065 sp->t0_ = f.t0; 91   1067 sp->t0_ = f.t0;
HITCBC 92   1065 sp->t1_ = f.t1; 92   1067 sp->t1_ = f.t1;
93   93  
HITCBC 94   1065 lock.lock(); 94   1067 lock.lock();
95   95  
HITCBC 96   1065 if(auto* p = find_impl(f.t0)) 96   1067 if(auto* p = find_impl(f.t0))
97   { 97   {
98   delete sp; // LCOV_EXCL_LINE concurrent same-type registration race 98   delete sp; // LCOV_EXCL_LINE concurrent same-type registration race
99   return *p; // LCOV_EXCL_LINE concurrent same-type registration race 99   return *p; // LCOV_EXCL_LINE concurrent same-type registration race
100   } 100   }
101   101  
HITCBC 102   1065 sp->next_ = head_; 102   1065 sp->next_ = head_;
HITCBC 103   1065 head_ = sp; 103   1065 head_ = sp;
104   104  
HITCBC 105   1065 if(shutdown_) 105   1065 if(shutdown_)
106   { 106   {
107   // Created after the context shut down: it starts shut down, 107   // Created after the context shut down: it starts shut down,
108   // like the services that already were. 108   // like the services that already were.
HITCBC 109   3 lock.unlock(); 109   3 lock.unlock();
HITCBC 110   3 sp->shutdown(); 110   3 sp->shutdown();
111   } 111   }
HITCBC 112   1065 return *sp; 112   1065 return *sp;
HITCBC 113   12491 } 113   12491 }
114   114  
115   execution_context::service& 115   execution_context::service&
HITCBC 116   28 execution_context:: 116   28 execution_context::
117   make_service_impl(factory& f) 117   make_service_impl(factory& f)
118   { 118   {
119   { 119   {
HITCBC 120   28 std::lock_guard<std::mutex> lock(mutex_); 120   28 std::lock_guard<std::mutex> lock(mutex_);
HITCBC 121   28 if(find_impl(f.t0)) 121   28 if(find_impl(f.t0))
HITCBC 122   2 detail::throw_invalid_argument(); 122   2 detail::throw_invalid_argument();
HITCBC 123   26 if(f.t0 != f.t1 && find_impl(f.t1)) 123   26 if(f.t0 != f.t1 && find_impl(f.t1))
HITCBC 124   1 detail::throw_invalid_argument(); 124   1 detail::throw_invalid_argument();
HITCBC 125   28 } 125   28 }
126   126  
127   // Unlocked to allow nested service creation from constructor 127   // Unlocked to allow nested service creation from constructor
HITCBC 128   25 service* p = f.create(*this); 128   25 service* p = f.create(*this);
129   129  
HITCBC 130   25 std::unique_lock<std::mutex> lock(mutex_); 130   25 std::unique_lock<std::mutex> lock(mutex_);
HITCBC 131   25 if(find_impl(f.t0)) 131   25 if(find_impl(f.t0))
132   { 132   {
133   delete p; // LCOV_EXCL_LINE concurrent same-type registration race 133   delete p; // LCOV_EXCL_LINE concurrent same-type registration race
134   detail::throw_invalid_argument(); // LCOV_EXCL_LINE concurrent same-type registration race 134   detail::throw_invalid_argument(); // LCOV_EXCL_LINE concurrent same-type registration race
135   } 135   }
136   136  
HITCBC 137   25 p->t0_ = f.t0; 137   25 p->t0_ = f.t0;
HITCBC 138   25 if(f.t0 != f.t1) 138   25 if(f.t0 != f.t1)
139   { 139   {
HITCBC 140   3 if(find_impl(f.t1)) 140   3 if(find_impl(f.t1))
141   { 141   {
HITCBC 142   1 delete p; 142   1 delete p;
HITCBC 143   1 detail::throw_invalid_argument(); 143   1 detail::throw_invalid_argument();
144   } 144   }
HITCBC 145   2 p->t1_ = f.t1; 145   2 p->t1_ = f.t1;
146   } 146   }
147   else 147   else
148   { 148   {
HITCBC 149   22 p->t1_ = f.t0; 149   22 p->t1_ = f.t0;
150   } 150   }
151   151  
HITCBC 152   24 p->next_ = head_; 152   24 p->next_ = head_;
HITCBC 153   24 head_ = p; 153   24 head_ = p;
154   154  
HITCBC 155   24 if(shutdown_) 155   24 if(shutdown_)
156   { 156   {
157   // Created after the context shut down: it starts shut down, 157   // Created after the context shut down: it starts shut down,
158   // like the services that already were. 158   // like the services that already were.
HITCBC 159   3 lock.unlock(); 159   3 lock.unlock();
HITCBC 160   3 p->shutdown(); 160   3 p->shutdown();
161   } 161   }
HITCBC 162   24 return *p; 162   24 return *p;
HITCBC 163   25 } 163   25 }
164   164  
165   } // namespace capy 165   } // namespace capy
166   } // namespace boost 166   } // namespace boost