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