1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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  
}
58  
}
59  

59  

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

73  

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

79  

80  
    if(auto* p = find_impl(f.t0))
80  
    if(auto* p = find_impl(f.t0))
81  
        return *p;
81  
        return *p;
82  

82  

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

84  

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

89  

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

91  

92  
    if(auto* p = find_impl(f.t0))
92  
    if(auto* p = find_impl(f.t0))
93  
    {
93  
    {
94  
        delete sp;
94  
        delete sp;
95  
        return *p;
95  
        return *p;
96  
    }
96  
    }
97  

97  

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

100  

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

103  

104  
execution_context::service&
104  
execution_context::service&
105  
execution_context::
105  
execution_context::
106  
make_service_impl(factory& f)
106  
make_service_impl(factory& f)
107  
{
107  
{
108  
    {
108  
    {
109  
        std::lock_guard<std::mutex> lock(mutex_);
109  
        std::lock_guard<std::mutex> lock(mutex_);
110  
        if(find_impl(f.t0))
110  
        if(find_impl(f.t0))
111  
            detail::throw_invalid_argument();
111  
            detail::throw_invalid_argument();
112  
        if(f.t0 != f.t1 && find_impl(f.t1))
112  
        if(f.t0 != f.t1 && find_impl(f.t1))
113  
            detail::throw_invalid_argument();
113  
            detail::throw_invalid_argument();
114  
    }
114  
    }
115  

115  

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

118  

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

125  

126  
    p->t0_ = f.t0;
126  
    p->t0_ = f.t0;
127  
    if(f.t0 != f.t1)
127  
    if(f.t0 != f.t1)
128  
    {
128  
    {
129  
        if(find_impl(f.t1))
129  
        if(find_impl(f.t1))
130  
        {
130  
        {
131  
            delete p;
131  
            delete p;
132  
            detail::throw_invalid_argument();
132  
            detail::throw_invalid_argument();
133  
        }
133  
        }
134  
        p->t1_ = f.t1;
134  
        p->t1_ = f.t1;
135  
    }
135  
    }
136  
    else
136  
    else
137  
    {
137  
    {
138  
        p->t1_ = f.t0;
138  
        p->t1_ = f.t0;
139  
    }
139  
    }
140  

140  

141  
    p->next_ = head_;
141  
    p->next_ = head_;
142  
    head_ = p;
142  
    head_ = p;
143  

143  

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

146  

147  
} // namespace capy
147  
} // namespace capy
148  
} // namespace boost
148  
} // namespace boost