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  

17  
execution_context::
17  
execution_context::
18  
execution_context()
18  
execution_context()
19  
    : frame_alloc_(get_recycling_memory_resource())
19  
    : frame_alloc_(get_recycling_memory_resource())
20  
{
20  
{
21  
}
21  
}
22  

22  

23  
execution_context::
23  
execution_context::
24  
~execution_context()
24  
~execution_context()
25  
{
25  
{
26  
    shutdown();
26  
    shutdown();
27  
    destroy();
27  
    destroy();
28  
}
28  
}
29  

29  

30  
void
30  
void
31  
execution_context::
31  
execution_context::
32  
shutdown() noexcept
32  
shutdown() noexcept
33  
{
33  
{
34  
    if(shutdown_)
34  
    if(shutdown_)
35  
        return;
35  
        return;
36  
    shutdown_ = true;
36  
    shutdown_ = true;
37  

37  

38  
    service* p = head_;
38  
    service* p = head_;
39  
    while(p)
39  
    while(p)
40  
    {
40  
    {
41  
        p->shutdown();
41  
        p->shutdown();
42  
        p = p->next_;
42  
        p = p->next_;
43  
    }
43  
    }
44  
}
44  
}
45  

45  

46  
void
46  
void
47  
execution_context::
47  
execution_context::
48  
destroy() noexcept
48  
destroy() noexcept
49  
{
49  
{
50  
    service* p = head_;
50  
    service* p = head_;
51  
    head_ = nullptr;
51  
    head_ = nullptr;
52  
    while(p)
52  
    while(p)
53  
    {
53  
    {
54  
        service* next = p->next_;
54  
        service* next = p->next_;
55  
        delete p;
55  
        delete p;
56  
        p = next;
56  
        p = next;
57  
    }
57  
    }
 
58 +
    for(auto& s : slots_)
 
59 +
        s.store(nullptr, std::memory_order_relaxed);
58  
}
60  
}
59  

61  

60  
execution_context::service*
62  
execution_context::service*
61  
execution_context::
63  
execution_context::
62  
find_impl(detail::type_index ti) const noexcept
64  
find_impl(detail::type_index ti) const noexcept
63  
{
65  
{
64  
    auto p = head_;
66  
    auto p = head_;
65  
    while(p)
67  
    while(p)
66  
    {
68  
    {
67  
        if(p->t0_ == ti || p->t1_ == ti)
69  
        if(p->t0_ == ti || p->t1_ == ti)
68  
            break;
70  
            break;
69  
        p = p->next_;
71  
        p = p->next_;
70  
    }
72  
    }
71  
    return p;
73  
    return p;
72  
}
74  
}
73  

75  

74  
execution_context::service&
76  
execution_context::service&
75  
execution_context::
77  
execution_context::
76  
use_service_impl(factory& f)
78  
use_service_impl(factory& f)
77  
{
79  
{
78  
    std::unique_lock<std::mutex> lock(mutex_);
80  
    std::unique_lock<std::mutex> lock(mutex_);
79  

81  

80  
    if(auto* p = find_impl(f.t0))
82  
    if(auto* p = find_impl(f.t0))
 
83 +
    {
 
84 +
        if(f.slot0 < max_service_slots)
 
85 +
            slots_[f.slot0].store(p, std::memory_order_release);
 
86 +
        if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
 
87 +
            slots_[f.slot1].store(p, std::memory_order_release);
81  
        return *p;
88  
        return *p;
 
89 +
    }
82  

90  

83  
    lock.unlock();
91  
    lock.unlock();
84  

92  

85  
    // Create the service outside lock, enabling nested calls
93  
    // Create the service outside lock, enabling nested calls
86  
    service* sp = f.create(*this);
94  
    service* sp = f.create(*this);
87  
    sp->t0_ = f.t0;
95  
    sp->t0_ = f.t0;
88  
    sp->t1_ = f.t1;
96  
    sp->t1_ = f.t1;
89  

97  

90  
    lock.lock();
98  
    lock.lock();
91  

99  

92  
    if(auto* p = find_impl(f.t0))
100  
    if(auto* p = find_impl(f.t0))
93  
    {
101  
    {
 
102 +
        if(f.slot0 < max_service_slots)
 
103 +
            slots_[f.slot0].store(p, std::memory_order_release);
 
104 +
        if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
 
105 +
            slots_[f.slot1].store(p, std::memory_order_release);
94  
        delete sp;
106  
        delete sp;
95  
        return *p;
107  
        return *p;
96  
    }
108  
    }
97  

109  

98  
    sp->next_ = head_;
110  
    sp->next_ = head_;
99  
    head_ = sp;
111  
    head_ = sp;
100  

112  

 
113 +
    if(f.slot0 < max_service_slots)
 
114 +
        slots_[f.slot0].store(sp, std::memory_order_release);
 
115 +
    if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
 
116 +
        slots_[f.slot1].store(sp, std::memory_order_release);
 
117 +

101  
    return *sp;
118  
    return *sp;
102  
}
119  
}
103  

120  

104  
execution_context::service&
121  
execution_context::service&
105  
execution_context::
122  
execution_context::
106  
make_service_impl(factory& f)
123  
make_service_impl(factory& f)
107  
{
124  
{
108  
    {
125  
    {
109  
        std::lock_guard<std::mutex> lock(mutex_);
126  
        std::lock_guard<std::mutex> lock(mutex_);
110  
        if(find_impl(f.t0))
127  
        if(find_impl(f.t0))
111  
            detail::throw_invalid_argument();
128  
            detail::throw_invalid_argument();
112  
        if(f.t0 != f.t1 && find_impl(f.t1))
129  
        if(f.t0 != f.t1 && find_impl(f.t1))
113  
            detail::throw_invalid_argument();
130  
            detail::throw_invalid_argument();
114  
    }
131  
    }
115  

132  

116  
    // Unlocked to allow nested service creation from constructor
133  
    // Unlocked to allow nested service creation from constructor
117  
    service* p = f.create(*this);
134  
    service* p = f.create(*this);
118  

135  

119  
    std::lock_guard<std::mutex> lock(mutex_);
136  
    std::lock_guard<std::mutex> lock(mutex_);
120  
    if(find_impl(f.t0))
137  
    if(find_impl(f.t0))
121  
    {
138  
    {
122  
        delete p;
139  
        delete p;
123  
        detail::throw_invalid_argument();
140  
        detail::throw_invalid_argument();
124  
    }
141  
    }
125  

142  

126  
    p->t0_ = f.t0;
143  
    p->t0_ = f.t0;
127  
    if(f.t0 != f.t1)
144  
    if(f.t0 != f.t1)
128  
    {
145  
    {
129  
        if(find_impl(f.t1))
146  
        if(find_impl(f.t1))
130  
        {
147  
        {
131  
            delete p;
148  
            delete p;
132  
            detail::throw_invalid_argument();
149  
            detail::throw_invalid_argument();
133  
        }
150  
        }
134  
        p->t1_ = f.t1;
151  
        p->t1_ = f.t1;
135  
    }
152  
    }
136  
    else
153  
    else
137  
    {
154  
    {
138  
        p->t1_ = f.t0;
155  
        p->t1_ = f.t0;
139  
    }
156  
    }
140  

157  

141  
    p->next_ = head_;
158  
    p->next_ = head_;
142  
    head_ = p;
159  
    head_ = p;
 
160 +

 
161 +
    if(f.slot0 < max_service_slots)
 
162 +
        slots_[f.slot0].store(p, std::memory_order_release);
 
163 +
    if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
 
164 +
        slots_[f.slot1].store(p, std::memory_order_release);
143  

165  

144  
    return *p;
166  
    return *p;
145  
}
167  
}
146  

168  

147  
} // namespace capy
169  
} // namespace capy
148  
} // namespace boost
170  
} // namespace boost