1 // Copyright (c) Benjamin Kietzman (github.com/bkietz)
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef DBUS_QUEUE_HPP
7 #define DBUS_QUEUE_HPP
8 
9 #include <deque>
10 #include <boost/asio.hpp>
11 #include <boost/asio/detail/mutex.hpp>
12 
13 #include <dbus/functional.hpp>
14 
15 
16 namespace dbus {
17 namespace detail {
18 
19 template<typename Message>
20 class queue
21 {
22 public:
23   typedef ::boost::asio::detail::mutex mutex_type;
24   typedef Message message_type;
25   typedef function<
26     void(boost::system::error_code, Message)> handler_type;
27 
28 private:
29   boost::asio::io_service& io;
30   mutex_type mutex;
31   std::deque<message_type> messages;
32   std::deque<handler_type> handlers;
33 
34 public:
35 
36   queue(boost::asio::io_service& io_service)
37     : io(io_service)
38   {}
39 
40 private:
41   class closure
42   {
43     handler_type handler_;
44     message_type message_;
45     boost::system::error_code error_;
46 
47   public:
48     void operator()() { handler_(error_, message_); }
49     closure(
50 	BOOST_ASIO_MOVE_ARG(handler_type) h,
51 	Message m,
52         boost::system::error_code e = boost::system::error_code())
53       : handler_(h),
54         message_(m),
55         error_(e)
56     {}
57   };
58 
59 public:
60 
61   void push(message_type m)
62   {
63     mutex_type::scoped_lock lock(mutex);
64     if(handlers.empty())
65       messages.push_back(m);
66     else
67     {
68       handler_type h = handlers.front();
69       handlers.pop_front();
70 
71       lock.unlock();
72 
73       io.post(
74         closure(BOOST_ASIO_MOVE_CAST(handler_type)(h), m));
75     }
76   }
77 
78   template<typename MessageHandler>
79   inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
80       void(boost::system::error_code, message_type))
81   async_pop(BOOST_ASIO_MOVE_ARG(MessageHandler) h)
82   {
83     typedef ::boost::asio::detail::async_result_init<
84       MessageHandler, void(boost::system::error_code, message_type)> init_type;
85 
86     mutex_type::scoped_lock lock(mutex);
87     if(messages.empty())
88     {
89       init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));
90 
91       handlers.push_back(init.handler);
92 
93       lock.unlock();
94 
95       return init.result.get();
96 
97     } else {
98       message_type m = messages.front();
99       messages.pop_front();
100 
101       lock.unlock();
102 
103       init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));
104 
105       io.post(closure(
106         BOOST_ASIO_MOVE_CAST(handler_type)(init.handler), m));
107 
108       return init.result.get();
109     }
110   }
111 };
112 
113 
114 } // namespace detail
115 } // namespace dbus
116 
117 #endif // DBUS_QUEUE_HPP
118