As described in D-Bus documentation, all IPC calls considered as asynchronous. When Qt calls remote D-Bus object through QDBusAbstractInterface, there's QBusPendingCall<T> which is fully async and provide signalling when call ran to completion.
In my application design I want to implement async call on my object adaptor, but current Qt/DBus implementation assumes, that all method calls are blocking.
So, there's a question: is there proper way to implement handling D-Bus method call asynchronously?
This is explained pretty well in Declaring Slots in D-Bus Adaptors.
We do this by writing a slot that stores the request data in a persistent structure, indicating to the caller using QDBusMessage::setDelayedReply(true)
that the response will be sent later.
struct RequestData
{
QString request;
QString processedData;
QDBusMessage reply;
};
QString processRequest(const QString &request, const QDBusMessage &message)
{
RequestData *data = new RequestData;
data->request = request;
message.setDelayedReply(true);
data->reply = message.createReply();
QDBusConnection::sessionBus().send(data->reply);
appendRequest(data);
return QString();
}
The use of QDBusConnection::sessionBus().send(data->reply)
is needed to explicitly inform the caller that the response will be delayed. In this case, the return value is unimportant; we return an arbitrary value to satisfy the compiler.
When the request is processed and a reply is available, it should be sent using the QDBusMessage
object that was obtained. In our example, the reply code could be something as follows:
void sendReply(RequestData *data)
{
// data->processedData has been initialized with the request's reply
QDBusMessage &reply = &data->reply;
// send the reply over D-Bus:
reply << data->processedData;
QDBusConnection::sessionBus().send(reply);
// dispose of the transaction data
delete data;
}
As can be seen in the example, when a delayed reply is in place, the return value(s) from the slot will be ignored by Qt D-Bus. They are used only to determine the slot's signature when communicating the adaptor's description to remote applications, or in case the code in the slot decides not to use a delayed reply.
The delayed reply itself is requested from Qt D-Bus by calling QDBusMessage::reply()
on the original message. It then becomes the responsibility of the called code to eventually send a reply to the caller.
Warning: When a caller places a method call and waits for a reply, it will only wait for a limited amount of time. Slots intending to take a long time to complete should make that fact clear in documentation so that callers properly set higher timeouts.