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

59  

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

73  

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

79  

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

82  

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

84  

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

89  

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

91  

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

97  

110  
    sp->next_ = head_;
98  
    sp->next_ = head_;
111  
    head_ = sp;
99  
    head_ = sp;
112 -
    if(f.slot0 < max_service_slots)
 
113 -
        slots_[f.slot0].store(sp, std::memory_order_release);
 
114 -
    if(f.slot0 != f.slot1 && f.slot1 < max_service_slots)
 
115 -
        slots_[f.slot1].store(sp, std::memory_order_release);
 
116 -

 
117  

100  

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

103  

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

115  

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

118  

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

125  

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

140  

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

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

143  

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

146  

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