// 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_ASYNC_SEND_OP_HPP #define DBUS_ASYNC_SEND_OP_HPP #include #include #include #include namespace dbus { namespace detail { template struct async_send_op { typedef async_send_op op_type; io_service& io_; message message_; MessageHandler handler_; async_send_op(io_service& io, BOOST_ASIO_MOVE_ARG(MessageHandler) handler); static void callback(DBusPendingCall *p, void *userdata); // for C API void operator()(DBusConnection *& c, message& m); // initiate operation void operator()(); // bound completion handler form }; template async_send_op::async_send_op(io_service& io, BOOST_ASIO_MOVE_ARG(MessageHandler) handler) : io_(io), handler_(BOOST_ASIO_MOVE_CAST(MessageHandler)(handler)) { } template void async_send_op::operator()(DBusConnection *& c, message& m) { DBusPendingCall *p; dbus_connection_send_with_reply(c, m, &p, -1); // We have to throw this onto the heap so that the // C API can store it as `void *userdata` async_send_op *op = new async_send_op( BOOST_ASIO_MOVE_CAST(async_send_op)(*this)); dbus_pending_call_set_notify(p, &callback, op, NULL); //FIXME Race condition: another thread might have // processed the pending call's reply before a notify // function could be set. If so, the notify function // will never trigger, so it must be called manually: if(dbus_pending_call_get_completed(p)) { //TODO: does this work, or might it call the notify // function too many times? Might have to use steal_reply //callback(p, op); } } template void async_send_op::callback(DBusPendingCall *p, void *userdata) { boost::scoped_ptr op( static_cast(userdata)); op->message_ = dbus_pending_call_steal_reply(p); dbus_pending_call_unref(p); op->io_.post(BOOST_ASIO_MOVE_CAST(async_send_op)(*op)); } template void async_send_op::operator()() { handler_(error(message_).error_code(), message_); } } // namespace detail } // namespace dbus #endif // DBUS_ASYNC_SEND_OP_HPP