| // Copyright (c) Benjamin Kietzman (github.com/bkietz) |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef DBUS_QUEUE_HPP |
| #define DBUS_QUEUE_HPP |
| |
| #include <deque> |
| #include <functional> |
| #include <boost/asio.hpp> |
| #include <boost/asio/detail/mutex.hpp> |
| |
| namespace dbus { |
| namespace detail { |
| |
| template <typename Message> |
| class queue { |
| public: |
| typedef ::boost::asio::detail::mutex mutex_type; |
| typedef Message message_type; |
| typedef std::function<void(boost::system::error_code, Message)> handler_type; |
| |
| private: |
| boost::asio::io_service& io; |
| mutex_type mutex; |
| std::deque<message_type> messages; |
| std::deque<handler_type> handlers; |
| |
| public: |
| queue(boost::asio::io_service& io_service) : io(io_service) {} |
| |
| private: |
| class closure { |
| handler_type handler_; |
| message_type message_; |
| boost::system::error_code error_; |
| |
| public: |
| void operator()() { handler_(error_, message_); } |
| closure(BOOST_ASIO_MOVE_ARG(handler_type) h, Message m, |
| boost::system::error_code e = boost::system::error_code()) |
| : handler_(h), message_(m), error_(e) {} |
| }; |
| |
| public: |
| void push(message_type m) { |
| mutex_type::scoped_lock lock(mutex); |
| if (handlers.empty()) |
| messages.push_back(m); |
| else { |
| handler_type h = handlers.front(); |
| handlers.pop_front(); |
| |
| lock.unlock(); |
| |
| io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(h), m)); |
| } |
| } |
| |
| template <typename MessageHandler> |
| inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler, |
| void(boost::system::error_code, |
| message_type)) |
| async_pop(BOOST_ASIO_MOVE_ARG(MessageHandler) h) { |
| typedef ::boost::asio::detail::async_result_init< |
| MessageHandler, void(boost::system::error_code, message_type)> |
| init_type; |
| |
| mutex_type::scoped_lock lock(mutex); |
| if (messages.empty()) { |
| init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h)); |
| |
| handlers.push_back(init.handler); |
| |
| lock.unlock(); |
| |
| return init.result.get(); |
| |
| } else { |
| message_type m = messages.front(); |
| messages.pop_front(); |
| |
| lock.unlock(); |
| |
| init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h)); |
| |
| io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(init.handler), m)); |
| |
| return init.result.get(); |
| } |
| } |
| }; |
| |
| } // namespace detail |
| } // namespace dbus |
| |
| #endif // DBUS_QUEUE_HPP |