• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // detail/strand_executor_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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_EXECUTOR_SERVICE_HPP
12 #define BOOST_ASIO_DETAIL_STRAND_EXECUTOR_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/detail/atomic_count.hpp>
20 #include <boost/asio/detail/executor_op.hpp>
21 #include <boost/asio/detail/memory.hpp>
22 #include <boost/asio/detail/mutex.hpp>
23 #include <boost/asio/detail/op_queue.hpp>
24 #include <boost/asio/detail/scheduler_operation.hpp>
25 #include <boost/asio/detail/scoped_ptr.hpp>
26 #include <boost/asio/detail/type_traits.hpp>
27 #include <boost/asio/execution.hpp>
28 #include <boost/asio/execution_context.hpp>
29 
30 #include <boost/asio/detail/push_options.hpp>
31 
32 namespace boost {
33 namespace asio {
34 namespace detail {
35 
36 // Default service implementation for a strand.
37 class strand_executor_service
38   : public execution_context_service_base<strand_executor_service>
39 {
40 public:
41   // The underlying implementation of a strand.
42   class strand_impl
43   {
44   public:
45     BOOST_ASIO_DECL ~strand_impl();
46 
47   private:
48     friend class strand_executor_service;
49 
50     // Mutex to protect access to internal data.
51     mutex* mutex_;
52 
53     // Indicates whether the strand is currently "locked" by a handler. This
54     // means that there is a handler upcall in progress, or that the strand
55     // itself has been scheduled in order to invoke some pending handlers.
56     bool locked_;
57 
58     // Indicates that the strand has been shut down and will accept no further
59     // handlers.
60     bool shutdown_;
61 
62     // The handlers that are waiting on the strand but should not be run until
63     // after the next time the strand is scheduled. This queue must only be
64     // modified while the mutex is locked.
65     op_queue<scheduler_operation> waiting_queue_;
66 
67     // The handlers that are ready to be run. Logically speaking, these are the
68     // handlers that hold the strand's lock. The ready queue is only modified
69     // from within the strand and so may be accessed without locking the mutex.
70     op_queue<scheduler_operation> ready_queue_;
71 
72     // Pointers to adjacent handle implementations in linked list.
73     strand_impl* next_;
74     strand_impl* prev_;
75 
76     // The strand service in where the implementation is held.
77     strand_executor_service* service_;
78   };
79 
80   typedef shared_ptr<strand_impl> implementation_type;
81 
82   // Construct a new strand service for the specified context.
83   BOOST_ASIO_DECL explicit strand_executor_service(execution_context& context);
84 
85   // Destroy all user-defined handler objects owned by the service.
86   BOOST_ASIO_DECL void shutdown();
87 
88   // Create a new strand_executor implementation.
89   BOOST_ASIO_DECL implementation_type create_implementation();
90 
91   // Request invocation of the given function.
92   template <typename Executor, typename Function>
93   static void execute(const implementation_type& impl, Executor& ex,
94       BOOST_ASIO_MOVE_ARG(Function) function,
95       typename enable_if<
96         can_query<Executor, execution::allocator_t<void> >::value
97       >::type* = 0);
98 
99   // Request invocation of the given function.
100   template <typename Executor, typename Function>
101   static void execute(const implementation_type& impl, Executor& ex,
102       BOOST_ASIO_MOVE_ARG(Function) function,
103       typename enable_if<
104         !can_query<Executor, execution::allocator_t<void> >::value
105       >::type* = 0);
106 
107   // Request invocation of the given function.
108   template <typename Executor, typename Function, typename Allocator>
109   static void dispatch(const implementation_type& impl, Executor& ex,
110       BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a);
111 
112   // Request invocation of the given function and return immediately.
113   template <typename Executor, typename Function, typename Allocator>
114   static void post(const implementation_type& impl, Executor& ex,
115       BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a);
116 
117   // Request invocation of the given function and return immediately.
118   template <typename Executor, typename Function, typename Allocator>
119   static void defer(const implementation_type& impl, Executor& ex,
120       BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a);
121 
122   // Determine whether the strand is running in the current thread.
123   BOOST_ASIO_DECL static bool running_in_this_thread(
124       const implementation_type& impl);
125 
126 private:
127   friend class strand_impl;
128   template <typename F, typename Allocator> class allocator_binder;
129   template <typename Executor, typename = void> class invoker;
130 
131   // Adds a function to the strand. Returns true if it acquires the lock.
132   BOOST_ASIO_DECL static bool enqueue(const implementation_type& impl,
133       scheduler_operation* op);
134 
135   // Transfers waiting handlers to the ready queue. Returns true if one or more
136   // handlers were transferred.
137   BOOST_ASIO_DECL static bool push_waiting_to_ready(implementation_type& impl);
138 
139   // Invokes all ready-to-run handlers.
140   BOOST_ASIO_DECL static void run_ready_handlers(implementation_type& impl);
141 
142   // Helper function to request invocation of the given function.
143   template <typename Executor, typename Function, typename Allocator>
144   static void do_execute(const implementation_type& impl, Executor& ex,
145       BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a);
146 
147   // Mutex to protect access to the service-wide state.
148   mutex mutex_;
149 
150   // Number of mutexes shared between all strand objects.
151   enum { num_mutexes = 193 };
152 
153   // Pool of mutexes.
154   scoped_ptr<mutex> mutexes_[num_mutexes];
155 
156   // Extra value used when hashing to prevent recycled memory locations from
157   // getting the same mutex.
158   std::size_t salt_;
159 
160   // The head of a linked list of all implementations.
161   strand_impl* impl_list_;
162 };
163 
164 } // namespace detail
165 } // namespace asio
166 } // namespace boost
167 
168 #include <boost/asio/detail/pop_options.hpp>
169 
170 #include <boost/asio/detail/impl/strand_executor_service.hpp>
171 #if defined(BOOST_ASIO_HEADER_ONLY)
172 # include <boost/asio/detail/impl/strand_executor_service.ipp>
173 #endif // defined(BOOST_ASIO_HEADER_ONLY)
174 
175 #endif // BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
176