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