5 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP
12 #define BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/push_options.hpp>
21 #include <boost/aligned_storage.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/detail/atomic_count.hpp>
24 #include <boost/intrusive_ptr.hpp>
25 #include <boost/asio/detail/pop_options.hpp>
27 #include <boost/asio/io_service.hpp>
28 #include <boost/asio/detail/bind_handler.hpp>
29 #include <boost/asio/detail/call_stack.hpp>
30 #include <boost/asio/detail/handler_alloc_helpers.hpp>
31 #include <boost/asio/detail/handler_invoke_helpers.hpp>
32 #include <boost/asio/detail/mutex.hpp>
33 #include <boost/asio/detail/noncopyable.hpp>
34 #include <boost/asio/detail/service_base.hpp>
40 // Default service implementation for a strand.
42 : public boost::asio::detail::service_base
<strand_service
>
46 class invoke_current_handler
;
47 class post_next_waiter_on_exit
;
49 // The underlying implementation of a strand.
52 #if defined (__BORLANDC__)
64 if (--ref_count_
== 0)
69 // Only this service will have access to the internal values.
70 friend class strand_service
;
71 friend class post_next_waiter_on_exit
;
72 friend class invoke_current_handler
;
74 strand_impl(strand_service
& owner
)
81 // Insert implementation into linked list of all implementations.
82 boost::asio::detail::mutex::scoped_lock
lock(owner_
.mutex_
);
83 next_
= owner_
.impl_list_
;
85 if (owner_
.impl_list_
)
86 owner_
.impl_list_
->prev_
= this;
87 owner_
.impl_list_
= this;
92 // Remove implementation from linked list of all implementations.
93 boost::asio::detail::mutex::scoped_lock
lock(owner_
.mutex_
);
94 if (owner_
.impl_list_
== this)
95 owner_
.impl_list_
= next_
;
104 if (current_handler_
)
106 current_handler_
->destroy();
109 while (first_waiter_
)
111 handler_base
* next
= first_waiter_
->next_
;
112 first_waiter_
->destroy();
113 first_waiter_
= next
;
117 // Mutex to protect access to internal data.
118 boost::asio::detail::mutex mutex_
;
120 // The service that owns this implementation.
121 strand_service
& owner_
;
123 // The handler that is ready to execute. If this pointer is non-null then it
124 // indicates that a handler holds the lock.
125 handler_base
* current_handler_
;
127 // The start of the list of waiting handlers for the strand.
128 handler_base
* first_waiter_
;
130 // The end of the list of waiting handlers for the strand.
131 handler_base
* last_waiter_
;
133 // Storage for posted handlers.
134 typedef boost::aligned_storage
<128> handler_storage_type
;
135 #if defined(__BORLANDC__)
136 boost::aligned_storage
<128> handler_storage_
;
138 handler_storage_type handler_storage_
;
141 // Pointers to adjacent socket implementations in linked list.
145 // The reference count on the strand implementation.
146 boost::detail::atomic_count ref_count_
;
148 #if !defined(__BORLANDC__)
149 friend void intrusive_ptr_add_ref(strand_impl
* p
)
154 friend void intrusive_ptr_release(strand_impl
* p
)
161 friend class strand_impl
;
163 typedef boost::intrusive_ptr
<strand_impl
> implementation_type
;
165 // Base class for all handler types.
169 typedef void (*invoke_func_type
)(handler_base
*,
170 strand_service
&, implementation_type
&);
171 typedef void (*destroy_func_type
)(handler_base
*);
173 handler_base(invoke_func_type invoke_func
, destroy_func_type destroy_func
)
175 invoke_func_(invoke_func
),
176 destroy_func_(destroy_func
)
180 void invoke(strand_service
& service_impl
, implementation_type
& impl
)
182 invoke_func_(this, service_impl
, impl
);
196 friend class strand_service
;
197 friend class strand_impl
;
198 friend class post_next_waiter_on_exit
;
200 invoke_func_type invoke_func_
;
201 destroy_func_type destroy_func_
;
204 // Helper class to allow handlers to be dispatched.
205 class invoke_current_handler
208 invoke_current_handler(strand_service
& service_impl
,
209 const implementation_type
& impl
)
210 : service_impl_(service_impl
),
217 impl_
->current_handler_
->invoke(service_impl_
, impl_
);
220 friend void* asio_handler_allocate(std::size_t size
,
221 invoke_current_handler
* this_handler
)
223 return this_handler
->do_handler_allocate(size
);
226 friend void asio_handler_deallocate(void*, std::size_t,
227 invoke_current_handler
*)
231 void* do_handler_allocate(std::size_t size
)
233 #if defined(__BORLANDC__)
234 BOOST_ASSERT(size
<= boost::aligned_storage
<128>::size
);
236 BOOST_ASSERT(size
<= strand_impl::handler_storage_type::size
);
239 return impl_
->handler_storage_
.address();
242 // The asio_handler_invoke hook is not defined here since the default one
243 // provides the correct behaviour, and including it here breaks MSVC 7.1
244 // in some situations.
247 strand_service
& service_impl_
;
248 implementation_type impl_
;
251 // Helper class to automatically enqueue next waiter on block exit.
252 class post_next_waiter_on_exit
255 post_next_waiter_on_exit(strand_service
& service_impl
,
256 implementation_type
& impl
)
257 : service_impl_(service_impl
),
263 ~post_next_waiter_on_exit()
267 boost::asio::detail::mutex::scoped_lock
lock(impl_
->mutex_
);
268 impl_
->current_handler_
= impl_
->first_waiter_
;
269 if (impl_
->current_handler_
)
271 impl_
->first_waiter_
= impl_
->first_waiter_
->next_
;
272 if (impl_
->first_waiter_
== 0)
273 impl_
->last_waiter_
= 0;
275 service_impl_
.get_io_service().post(
276 invoke_current_handler(service_impl_
, impl_
));
287 strand_service
& service_impl_
;
288 implementation_type
& impl_
;
292 // Class template for a waiter.
293 template <typename Handler
>
294 class handler_wrapper
295 : public handler_base
298 handler_wrapper(Handler handler
)
299 : handler_base(&handler_wrapper
<Handler
>::do_invoke
,
300 &handler_wrapper
<Handler
>::do_destroy
),
305 static void do_invoke(handler_base
* base
,
306 strand_service
& service_impl
, implementation_type
& impl
)
308 // Take ownership of the handler object.
309 typedef handler_wrapper
<Handler
> this_type
;
310 this_type
* h(static_cast<this_type
*>(base
));
311 typedef handler_alloc_traits
<Handler
, this_type
> alloc_traits
;
312 handler_ptr
<alloc_traits
> ptr(h
->handler_
, h
);
314 post_next_waiter_on_exit
p1(service_impl
, impl
);
316 // Make a copy of the handler so that the memory can be deallocated before
317 // the upcall is made.
318 Handler
handler(h
->handler_
);
320 // A handler object must still be valid when the next waiter is posted
321 // since destroying the last handler might cause the strand object to be
322 // destroyed. Therefore we create a second post_next_waiter_on_exit object
323 // that will be destroyed before the handler object.
325 post_next_waiter_on_exit
p2(service_impl
, impl
);
327 // Free the memory associated with the handler.
330 // Indicate that this strand is executing on the current thread.
331 call_stack
<strand_impl
>::context
ctx(impl
.get());
334 boost_asio_handler_invoke_helpers::invoke(handler
, &handler
);
337 static void do_destroy(handler_base
* base
)
339 // Take ownership of the handler object.
340 typedef handler_wrapper
<Handler
> this_type
;
341 this_type
* h(static_cast<this_type
*>(base
));
342 typedef handler_alloc_traits
<Handler
, this_type
> alloc_traits
;
343 handler_ptr
<alloc_traits
> ptr(h
->handler_
, h
);
345 // A sub-object of the handler may be the true owner of the memory
346 // associated with the handler. Consequently, a local copy of the handler
347 // is required to ensure that any owning sub-object remains valid until
348 // after we have deallocated the memory here.
349 Handler
handler(h
->handler_
);
352 // Free the memory associated with the handler.
360 // Construct a new strand service for the specified io_service.
361 explicit strand_service(boost::asio::io_service
& io_service
)
362 : boost::asio::detail::service_base
<strand_service
>(io_service
),
368 // Destroy all user-defined handler objects owned by the service.
369 void shutdown_service()
371 // Construct a list of all handlers to be destroyed.
372 boost::asio::detail::mutex::scoped_lock
lock(mutex_
);
373 strand_impl
* impl
= impl_list_
;
374 handler_base
* first_handler
= 0;
377 if (impl
->current_handler_
)
379 impl
->current_handler_
->next_
= first_handler
;
380 first_handler
= impl
->current_handler_
;
381 impl
->current_handler_
= 0;
383 if (impl
->first_waiter_
)
385 impl
->last_waiter_
->next_
= first_handler
;
386 first_handler
= impl
->first_waiter_
;
387 impl
->first_waiter_
= 0;
388 impl
->last_waiter_
= 0;
393 // Destroy all handlers without holding the lock.
395 while (first_handler
)
397 handler_base
* next
= first_handler
->next_
;
398 first_handler
->destroy();
399 first_handler
= next
;
403 // Construct a new strand implementation.
404 void construct(implementation_type
& impl
)
406 impl
= implementation_type(new strand_impl(*this));
409 // Destroy a strand implementation.
410 void destroy(implementation_type
& impl
)
412 implementation_type().swap(impl
);
415 // Request the io_service to invoke the given handler.
416 template <typename Handler
>
417 void dispatch(implementation_type
& impl
, Handler handler
)
419 if (call_stack
<strand_impl
>::contains(impl
.get()))
421 boost_asio_handler_invoke_helpers::invoke(handler
, &handler
);
425 // Allocate and construct an object to wrap the handler.
426 typedef handler_wrapper
<Handler
> value_type
;
427 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
428 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
429 handler_ptr
<alloc_traits
> ptr(raw_ptr
, handler
);
431 boost::asio::detail::mutex::scoped_lock
lock(impl
->mutex_
);
433 if (impl
->current_handler_
== 0)
435 // This handler now has the lock, so can be dispatched immediately.
436 impl
->current_handler_
= ptr
.release();
438 this->get_io_service().dispatch(invoke_current_handler(*this, impl
));
442 // Another handler already holds the lock, so this handler must join
443 // the list of waiters. The handler will be posted automatically when
445 if (impl
->last_waiter_
)
447 impl
->last_waiter_
->next_
= ptr
.get();
448 impl
->last_waiter_
= impl
->last_waiter_
->next_
;
452 impl
->first_waiter_
= ptr
.get();
453 impl
->last_waiter_
= ptr
.get();
460 // Request the io_service to invoke the given handler and return immediately.
461 template <typename Handler
>
462 void post(implementation_type
& impl
, Handler handler
)
464 // Allocate and construct an object to wrap the handler.
465 typedef handler_wrapper
<Handler
> value_type
;
466 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
467 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
468 handler_ptr
<alloc_traits
> ptr(raw_ptr
, handler
);
470 boost::asio::detail::mutex::scoped_lock
lock(impl
->mutex_
);
472 if (impl
->current_handler_
== 0)
474 // This handler now has the lock, so can be dispatched immediately.
475 impl
->current_handler_
= ptr
.release();
477 this->get_io_service().post(invoke_current_handler(*this, impl
));
481 // Another handler already holds the lock, so this handler must join the
482 // list of waiters. The handler will be posted automatically when its turn
484 if (impl
->last_waiter_
)
486 impl
->last_waiter_
->next_
= ptr
.get();
487 impl
->last_waiter_
= impl
->last_waiter_
->next_
;
491 impl
->first_waiter_
= ptr
.get();
492 impl
->last_waiter_
= ptr
.get();
499 // Mutex to protect access to the linked list of implementations.
500 boost::asio::detail::mutex mutex_
;
502 // The head of a linked list of all implementations.
503 strand_impl
* impl_list_
;
506 } // namespace detail
510 #if defined(__BORLANDC__)
514 inline void intrusive_ptr_add_ref(
515 boost::asio::detail::strand_service::strand_impl
* p
)
520 inline void intrusive_ptr_release(
521 boost::asio::detail::strand_service::strand_impl
* p
)
528 #endif // defined(__BORLANDC__)
530 #include <boost/asio/detail/pop_options.hpp>
532 #endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP