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