1  
//
1  
//
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2022 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/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#include <boost/http/application.hpp>
10  
#include <boost/http/application.hpp>
11  
#include <boost/http/detail/except.hpp>
11  
#include <boost/http/detail/except.hpp>
12  
#include <boost/assert.hpp>
12  
#include <boost/assert.hpp>
13  
#include <mutex>
13  
#include <mutex>
14  
#include <vector>
14  
#include <vector>
15  

15  

16  
namespace boost {
16  
namespace boost {
17  
namespace http {
17  
namespace http {
18  

18  

19  
enum application::state : char
19  
enum application::state : char
20  
{
20  
{
21  
    none,
21  
    none,
22  
    starting,
22  
    starting,
23  
    running,
23  
    running,
24  
    stopping,
24  
    stopping,
25  
    stopped
25  
    stopped
26  
};
26  
};
27  

27  

28  
struct application::impl
28  
struct application::impl
29  
{
29  
{
30  
    std::mutex m;
30  
    std::mutex m;
31  
    state st = state::none;
31  
    state st = state::none;
32  
};
32  
};
33  

33  

34  
application::
34  
application::
35  
~application()
35  
~application()
36  
{
36  
{
37  
    {
37  
    {
38  
        std::lock_guard<std::mutex> lock(impl_->m);
38  
        std::lock_guard<std::mutex> lock(impl_->m);
39  
        if( impl_->st != state::stopped &&
39  
        if( impl_->st != state::stopped &&
40  
            impl_->st != state::none)
40  
            impl_->st != state::none)
41  
        {
41  
        {
42  
            // stop() hasn't returned yet
42  
            // stop() hasn't returned yet
43  
            detail::throw_invalid_argument();
43  
            detail::throw_invalid_argument();
44  
        }
44  
        }
45  
    }
45  
    }
46  
    delete impl_;
46  
    delete impl_;
47  
}
47  
}
48  

48  

49  
application::
49  
application::
50  
application()
50  
application()
51  
    : impl_(new impl)
51  
    : impl_(new impl)
52  
{
52  
{
53  
}
53  
}
54  

54  

55  
void
55  
void
56  
application::
56  
application::
57  
start()
57  
start()
58  
{
58  
{
59  
    struct action
59  
    struct action
60  
    {
60  
    {
61  
        action(application& self)
61  
        action(application& self)
62  
            : self_(self)
62  
            : self_(self)
63  
        {
63  
        {
64  
            std::lock_guard<
64  
            std::lock_guard<
65  
                std::mutex> lock(self_.impl_->m);
65  
                std::mutex> lock(self_.impl_->m);
66  
            // can't call twice
66  
            // can't call twice
67  
            if(self_.impl_->st != state::none)
67  
            if(self_.impl_->st != state::none)
68  
                detail::throw_invalid_argument();
68  
                detail::throw_invalid_argument();
69  
            self_.impl_->st = state::starting;
69  
            self_.impl_->st = state::starting;
70  
        }
70  
        }
71  

71  

72  
        ~action()
72  
        ~action()
73  
        {
73  
        {
74  
            if(n_ == 0)
74  
            if(n_ == 0)
75  
                return;
75  
                return;
76  
            {
76  
            {
77  
                std::lock_guard<
77  
                std::lock_guard<
78  
                    std::mutex> lock(self_.impl_->m);
78  
                    std::mutex> lock(self_.impl_->m);
79  
                BOOST_ASSERT(
79  
                BOOST_ASSERT(
80  
                    self_.impl_->st == state::stopping);
80  
                    self_.impl_->st == state::stopping);
81  
                self_.impl_->st = state::stopping;
81  
                self_.impl_->st = state::stopping;
82  
            }
82  
            }
83  
            // stop what we started
83  
            // stop what we started
84  
            auto v = self_.get_elements();
84  
            auto v = self_.get_elements();
85  
            while(n_-- > 0)
85  
            while(n_-- > 0)
86  
                v[n_].stop();
86  
                v[n_].stop();
87  
            {
87  
            {
88  
                std::lock_guard<std::mutex> lock(
88  
                std::lock_guard<std::mutex> lock(
89  
                    self_.impl_->m);
89  
                    self_.impl_->m);
90  
                self_.impl_->st = state::stopped;
90  
                self_.impl_->st = state::stopped;
91  
            }
91  
            }
92  
        }
92  
        }
93  

93  

94  
        void apply()
94  
        void apply()
95  
        {
95  
        {
96  
            auto v = self_.get_elements();
96  
            auto v = self_.get_elements();
97  
            while(n_ < v.size())
97  
            while(n_ < v.size())
98  
            {
98  
            {
99  
                v[n_].start();
99  
                v[n_].start();
100  
                ++n_;
100  
                ++n_;
101  
            }
101  
            }
102  
            n_ = 0;
102  
            n_ = 0;
103  
            std::lock_guard<
103  
            std::lock_guard<
104  
                std::mutex> lock(self_.impl_->m);
104  
                std::mutex> lock(self_.impl_->m);
105  
            self_.impl_->st = state::running;
105  
            self_.impl_->st = state::running;
106  
        }
106  
        }
107  

107  

108  
    private:
108  
    private:
109  
        application& self_;
109  
        application& self_;
110  
        std::size_t n_ = 0;
110  
        std::size_t n_ = 0;
111  
    };
111  
    };
112  

112  

113  
    action(*this).apply();
113  
    action(*this).apply();
114  
}
114  
}
115  

115  

116  
void
116  
void
117  
application::
117  
application::
118  
stop()
118  
stop()
119  
{
119  
{
120  
    {
120  
    {
121  
        std::lock_guard<std::mutex> lock(impl_->m);
121  
        std::lock_guard<std::mutex> lock(impl_->m);
122  
        if(impl_->st != state::running)
122  
        if(impl_->st != state::running)
123  
            detail::throw_invalid_argument();
123  
            detail::throw_invalid_argument();
124  
        impl_->st = state::stopping;
124  
        impl_->st = state::stopping;
125  
    }
125  
    }
126  

126  

127  
    auto v = get_elements();
127  
    auto v = get_elements();
128  
    for(std::size_t i = v.size(); i--;)
128  
    for(std::size_t i = v.size(); i--;)
129  
        v[i].stop();
129  
        v[i].stop();
130  

130  

131  
    {
131  
    {
132  
        std::lock_guard<std::mutex> lock(impl_->m);
132  
        std::lock_guard<std::mutex> lock(impl_->m);
133  
        impl_->st = state::stopped;
133  
        impl_->st = state::stopped;
134  
    }
134  
    }
135  
}
135  
}
136  

136  

137  
} // http
137  
} // http
138  
} // boost
138  
} // boost