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_)
58  
    for(auto& s : slots_)
59  
        s.store(nullptr, std::memory_order_relaxed);
59  
        s.store(nullptr, std::memory_order_relaxed);
60  
}
60  
}
61  

61  

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

75  

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

81  

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

90  

91  
    lock.unlock();
91  
    lock.unlock();
92  

92  

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

97  

98  
    lock.lock();
98  
    lock.lock();
99  

99  

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

109  

110  
    sp->next_ = head_;
110  
    sp->next_ = head_;
111  
    head_ = sp;
111  
    head_ = sp;
112  

112  

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

117  

118  
    return *sp;
118  
    return *sp;
119  
}
119  
}
120  

120  

121  
execution_context::service&
121  
execution_context::service&
122  
execution_context::
122  
execution_context::
123  
make_service_impl(factory& f)
123  
make_service_impl(factory& f)
124  
{
124  
{
125  
    {
125  
    {
126  
        std::lock_guard<std::mutex> lock(mutex_);
126  
        std::lock_guard<std::mutex> lock(mutex_);
127  
        if(find_impl(f.t0))
127  
        if(find_impl(f.t0))
128  
            detail::throw_invalid_argument();
128  
            detail::throw_invalid_argument();
129  
        if(f.t0 != f.t1 && find_impl(f.t1))
129  
        if(f.t0 != f.t1 && find_impl(f.t1))
130  
            detail::throw_invalid_argument();
130  
            detail::throw_invalid_argument();
131  
    }
131  
    }
132  

132  

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

135  

136  
    std::lock_guard<std::mutex> lock(mutex_);
136  
    std::lock_guard<std::mutex> lock(mutex_);
137  
    if(find_impl(f.t0))
137  
    if(find_impl(f.t0))
138  
    {
138  
    {
139  
        delete p;
139  
        delete p;
140  
        detail::throw_invalid_argument();
140  
        detail::throw_invalid_argument();
141  
    }
141  
    }
142  

142  

143  
    p->t0_ = f.t0;
143  
    p->t0_ = f.t0;
144  
    if(f.t0 != f.t1)
144  
    if(f.t0 != f.t1)
145  
    {
145  
    {
146  
        if(find_impl(f.t1))
146  
        if(find_impl(f.t1))
147  
        {
147  
        {
148  
            delete p;
148  
            delete p;
149  
            detail::throw_invalid_argument();
149  
            detail::throw_invalid_argument();
150  
        }
150  
        }
151  
        p->t1_ = f.t1;
151  
        p->t1_ = f.t1;
152  
    }
152  
    }
153  
    else
153  
    else
154  
    {
154  
    {
155  
        p->t1_ = f.t0;
155  
        p->t1_ = f.t0;
156  
    }
156  
    }
157  

157  

158  
    p->next_ = head_;
158  
    p->next_ = head_;
159  
    head_ = p;
159  
    head_ = p;
160  

160  

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

165  

166  
    return *p;
166  
    return *p;
167  
}
167  
}
168  

168  

169  
} // namespace capy
169  
} // namespace capy
170  
} // namespace boost
170  
} // namespace boost