1 | // |
2 | // detail/strand_service.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
9 | // |
10 | |
11 | #ifndef BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP |
12 | #define BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | #include <boost/asio/io_service.hpp> |
20 | #include <boost/asio/detail/mutex.hpp> |
21 | #include <boost/asio/detail/op_queue.hpp> |
22 | #include <boost/asio/detail/operation.hpp> |
23 | #include <boost/asio/detail/scoped_ptr.hpp> |
24 | |
25 | #include <boost/asio/detail/push_options.hpp> |
26 | |
27 | namespace boost { |
28 | namespace asio { |
29 | namespace detail { |
30 | |
31 | // Default service implementation for a strand. |
32 | class strand_service |
33 | : public boost::asio::detail::service_base<strand_service> |
34 | { |
35 | private: |
36 | // Helper class to re-post the strand on exit. |
37 | struct on_do_complete_exit; |
38 | |
39 | // Helper class to re-post the strand on exit. |
40 | struct on_dispatch_exit; |
41 | |
42 | public: |
43 | |
44 | // The underlying implementation of a strand. |
45 | class strand_impl |
46 | : public operation |
47 | { |
48 | public: |
49 | strand_impl(); |
50 | |
51 | private: |
52 | // Only this service will have access to the internal values. |
53 | friend class strand_service; |
54 | friend struct on_do_complete_exit; |
55 | friend struct on_dispatch_exit; |
56 | |
57 | // Mutex to protect access to internal data. |
58 | boost::asio::detail::mutex mutex_; |
59 | |
60 | // Indicates whether the strand is currently "locked" by a handler. This |
61 | // means that there is a handler upcall in progress, or that the strand |
62 | // itself has been scheduled in order to invoke some pending handlers. |
63 | bool locked_; |
64 | |
65 | // The handlers that are waiting on the strand but should not be run until |
66 | // after the next time the strand is scheduled. This queue must only be |
67 | // modified while the mutex is locked. |
68 | op_queue<operation> waiting_queue_; |
69 | |
70 | // The handlers that are ready to be run. Logically speaking, these are the |
71 | // handlers that hold the strand's lock. The ready queue is only modified |
72 | // from within the strand and so may be accessed without locking the mutex. |
73 | op_queue<operation> ready_queue_; |
74 | }; |
75 | |
76 | typedef strand_impl* implementation_type; |
77 | |
78 | // Construct a new strand service for the specified io_service. |
79 | BOOST_ASIO_DECL explicit strand_service(boost::asio::io_service& io_service); |
80 | |
81 | // Destroy all user-defined handler objects owned by the service. |
82 | BOOST_ASIO_DECL void shutdown_service(); |
83 | |
84 | // Construct a new strand implementation. |
85 | BOOST_ASIO_DECL void construct(implementation_type& impl); |
86 | |
87 | // Request the io_service to invoke the given handler. |
88 | template <typename Handler> |
89 | void dispatch(implementation_type& impl, Handler& handler); |
90 | |
91 | // Request the io_service to invoke the given handler and return immediately. |
92 | template <typename Handler> |
93 | void post(implementation_type& impl, Handler& handler); |
94 | |
95 | // Determine whether the strand is running in the current thread. |
96 | BOOST_ASIO_DECL bool running_in_this_thread( |
97 | const implementation_type& impl) const; |
98 | |
99 | private: |
100 | // Helper function to dispatch a handler. Returns true if the handler should |
101 | // be dispatched immediately. |
102 | BOOST_ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op); |
103 | |
104 | // Helper fiunction to post a handler. |
105 | BOOST_ASIO_DECL void do_post(implementation_type& impl, |
106 | operation* op, bool is_continuation); |
107 | |
108 | BOOST_ASIO_DECL static void do_complete(io_service_impl* owner, |
109 | operation* base, const boost::system::error_code& ec, |
110 | std::size_t bytes_transferred); |
111 | |
112 | // The io_service implementation used to post completions. |
113 | io_service_impl& io_service_; |
114 | |
115 | // Mutex to protect access to the array of implementations. |
116 | boost::asio::detail::mutex mutex_; |
117 | |
118 | // Number of implementations shared between all strand objects. |
119 | #if defined(BOOST_ASIO_STRAND_IMPLEMENTATIONS) |
120 | enum { num_implementations = BOOST_ASIO_STRAND_IMPLEMENTATIONS }; |
121 | #else // defined(BOOST_ASIO_STRAND_IMPLEMENTATIONS) |
122 | enum { num_implementations = 193 }; |
123 | #endif // defined(BOOST_ASIO_STRAND_IMPLEMENTATIONS) |
124 | |
125 | // Pool of implementations. |
126 | scoped_ptr<strand_impl> implementations_[num_implementations]; |
127 | |
128 | // Extra value used when hashing to prevent recycled memory locations from |
129 | // getting the same strand implementation. |
130 | std::size_t salt_; |
131 | }; |
132 | |
133 | } // namespace detail |
134 | } // namespace asio |
135 | } // namespace boost |
136 | |
137 | #include <boost/asio/detail/pop_options.hpp> |
138 | |
139 | #include <boost/asio/detail/impl/strand_service.hpp> |
140 | #if defined(BOOST_ASIO_HEADER_ONLY) |
141 | # include <boost/asio/detail/impl/strand_service.ipp> |
142 | #endif // defined(BOOST_ASIO_HEADER_ONLY) |
143 | |
144 | #endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP |
145 | |