1 //
2 // detail/scheduler.hpp
3 // ~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 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 ASIO_DETAIL_SCHEDULER_HPP
12 #define ASIO_DETAIL_SCHEDULER_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include "asio/detail/config.hpp"
19 
20 #include "asio/error_code.hpp"
21 #include "asio/execution_context.hpp"
22 #include "asio/detail/atomic_count.hpp"
23 #include "asio/detail/conditionally_enabled_event.hpp"
24 #include "asio/detail/conditionally_enabled_mutex.hpp"
25 #include "asio/detail/op_queue.hpp"
26 #include "asio/detail/reactor_fwd.hpp"
27 #include "asio/detail/scheduler_operation.hpp"
28 #include "asio/detail/thread_context.hpp"
29 
30 #include "asio/detail/push_options.hpp"
31 
32 namespace asio {
33 namespace detail {
34 
35 struct scheduler_thread_info;
36 
37 class scheduler
38   : public execution_context_service_base<scheduler>,
39     public thread_context
40 {
41 public:
42   typedef scheduler_operation operation;
43 
44   // Constructor. Specifies the number of concurrent threads that are likely to
45   // run the scheduler. If set to 1 certain optimisation are performed.
46   ASIO_DECL scheduler(asio::execution_context& ctx,
47       int concurrency_hint = 0);
48 
49   // Destroy all user-defined handler objects owned by the service.
50   ASIO_DECL void shutdown();
51 
52   // Initialise the task, if required.
53   ASIO_DECL void init_task();
54 
55   // Run the event loop until interrupted or no more work.
56   ASIO_DECL std::size_t run(asio::error_code& ec);
57 
58   // Run until interrupted or one operation is performed.
59   ASIO_DECL std::size_t run_one(asio::error_code& ec);
60 
61   // Run until timeout, interrupted, or one operation is performed.
62   ASIO_DECL std::size_t wait_one(
63       long usec, asio::error_code& ec);
64 
65   // Poll for operations without blocking.
66   ASIO_DECL std::size_t poll(asio::error_code& ec);
67 
68   // Poll for one operation without blocking.
69   ASIO_DECL std::size_t poll_one(asio::error_code& ec);
70 
71   // Interrupt the event processing loop.
72   ASIO_DECL void stop();
73 
74   // Determine whether the scheduler is stopped.
75   ASIO_DECL bool stopped() const;
76 
77   // Restart in preparation for a subsequent run invocation.
78   ASIO_DECL void restart();
79 
80   // Notify that some work has started.
work_started()81   void work_started()
82   {
83     ++outstanding_work_;
84   }
85 
86   // Used to compensate for a forthcoming work_finished call. Must be called
87   // from within a scheduler-owned thread.
88   ASIO_DECL void compensating_work_started();
89 
90   // Notify that some work has finished.
work_finished()91   void work_finished()
92   {
93     if (--outstanding_work_ == 0)
94       stop();
95   }
96 
97   // Return whether a handler can be dispatched immediately.
can_dispatch()98   bool can_dispatch()
99   {
100     return thread_call_stack::contains(this) != 0;
101   }
102 
103   // Request invocation of the given operation and return immediately. Assumes
104   // that work_started() has not yet been called for the operation.
105   ASIO_DECL void post_immediate_completion(
106       operation* op, bool is_continuation);
107 
108   // Request invocation of the given operation and return immediately. Assumes
109   // that work_started() was previously called for the operation.
110   ASIO_DECL void post_deferred_completion(operation* op);
111 
112   // Request invocation of the given operations and return immediately. Assumes
113   // that work_started() was previously called for each operation.
114   ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
115 
116   // Enqueue the given operation following a failed attempt to dispatch the
117   // operation for immediate invocation.
118   ASIO_DECL void do_dispatch(operation* op);
119 
120   // Process unfinished operations as part of a shutdownoperation. Assumes that
121   // work_started() was previously called for the operations.
122   ASIO_DECL void abandon_operations(op_queue<operation>& ops);
123 
124   // Get the concurrency hint that was used to initialise the scheduler.
concurrency_hint() const125   int concurrency_hint() const
126   {
127     return concurrency_hint_;
128   }
129 
130 private:
131   // The mutex type used by this scheduler.
132   typedef conditionally_enabled_mutex mutex;
133 
134   // The event type used by this scheduler.
135   typedef conditionally_enabled_event event;
136 
137   // Structure containing thread-specific data.
138   typedef scheduler_thread_info thread_info;
139 
140   // Run at most one operation. May block.
141   ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,
142       thread_info& this_thread, const asio::error_code& ec);
143 
144   // Run at most one operation with a timeout. May block.
145   ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock,
146       thread_info& this_thread, long usec, const asio::error_code& ec);
147 
148   // Poll for at most one operation.
149   ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,
150       thread_info& this_thread, const asio::error_code& ec);
151 
152   // Stop the task and all idle threads.
153   ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
154 
155   // Wake a single idle thread, or the task, and always unlock the mutex.
156   ASIO_DECL void wake_one_thread_and_unlock(
157       mutex::scoped_lock& lock);
158 
159   // Helper class to perform task-related operations on block exit.
160   struct task_cleanup;
161   friend struct task_cleanup;
162 
163   // Helper class to call work-related operations on block exit.
164   struct work_cleanup;
165   friend struct work_cleanup;
166 
167   // Whether to optimise for single-threaded use cases.
168   const bool one_thread_;
169 
170   // Mutex to protect access to internal data.
171   mutable mutex mutex_;
172 
173   // Event to wake up blocked threads.
174   event wakeup_event_;
175 
176   // The task to be run by this service.
177   reactor* task_;
178 
179   // Operation object to represent the position of the task in the queue.
180   struct task_operation : operation
181   {
task_operationasio::detail::scheduler::task_operation182     task_operation() : operation(0) {}
183   } task_operation_;
184 
185   // Whether the task has been interrupted.
186   bool task_interrupted_;
187 
188   // The count of unfinished work.
189   atomic_count outstanding_work_;
190 
191   // The queue of handlers that are ready to be delivered.
192   op_queue<operation> op_queue_;
193 
194   // Flag to indicate that the dispatcher has been stopped.
195   bool stopped_;
196 
197   // Flag to indicate that the dispatcher has been shut down.
198   bool shutdown_;
199 
200   // The concurrency hint used to initialise the scheduler.
201   const int concurrency_hint_;
202 };
203 
204 } // namespace detail
205 } // namespace asio
206 
207 #include "asio/detail/pop_options.hpp"
208 
209 #if defined(ASIO_HEADER_ONLY)
210 # include "asio/detail/impl/scheduler.ipp"
211 #endif // defined(ASIO_HEADER_ONLY)
212 
213 #endif // ASIO_DETAIL_SCHEDULER_HPP
214