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 <functional> 11 #include <boost/asio.hpp> 12 #include <boost/asio/detail/mutex.hpp> 13 14 namespace dbus { 15 namespace detail { 16 17 template <typename Message> 18 class queue { 19 public: 20 typedef ::boost::asio::detail::mutex mutex_type; 21 typedef Message message_type; 22 typedef std::function<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 queue(boost::asio::io_service& io_service) : io(io_service) {} 32 33 private: 34 class closure { 35 handler_type handler_; 36 message_type message_; 37 boost::system::error_code error_; 38 39 public: 40 void operator()() { handler_(error_, message_); } 41 closure(handler_type h, Message m, 42 boost::system::error_code e = boost::system::error_code()) 43 : handler_(h), message_(m), error_(e) {} 44 }; 45 46 public: 47 void push(message_type m) { 48 mutex_type::scoped_lock lock(mutex); 49 if (handlers.empty()) 50 messages.push_back(m); 51 else { 52 handler_type h = handlers.front(); 53 handlers.pop_front(); 54 55 lock.unlock(); 56 57 io.post(closure(h, m)); 58 } 59 } 60 61 template <typename MessageHandler> 62 inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler, 63 void(boost::system::error_code, 64 message_type)) 65 async_pop(BOOST_ASIO_MOVE_ARG(MessageHandler) h) { 66 typedef ::boost::asio::detail::async_result_init< 67 MessageHandler, void(boost::system::error_code, message_type)> 68 init_type; 69 70 mutex_type::scoped_lock lock(mutex); 71 if (messages.empty()) { 72 init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h)); 73 74 handlers.push_back(init.handler); 75 76 lock.unlock(); 77 78 return init.result.get(); 79 80 } else { 81 message_type m = messages.front(); 82 messages.pop_front(); 83 84 lock.unlock(); 85 86 init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h)); 87 88 io.post(closure(init.handler, m)); 89 90 return init.result.get(); 91 } 92 } 93 }; 94 95 } // namespace detail 96 } // namespace dbus 97 98 #endif // DBUS_QUEUE_HPP 99