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