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