Commit d3e03eb5 authored by Manish Narang's avatar Manish Narang Committed by Simon McVittie

DBusPendingCall: Only update ->completed under the connection lock

If one thread is blocking on a pending call, and another thread is
dispatching the connection, then we need them to agree on the value
of the completed flag by protecting all accesses with a lock. Reads
for this member seem to have the connection lock already, so it's
sufficient to make sure that the only write also happens under the
connection lock.

We already set the completed flag before calling the callback, so it
seems OK to stretch it to meaning that some thread has merely *taken
responsibility for* calling the callback.

The completed flag shares a bitfield with timeout_added, but that
flag is protected by the connection lock already.

Based on suggestions from Simon McVittie on
<https://bugs.freedesktop.org/show_bug.cgi?id=102839>.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=102839
[smcv: Revert indentation changes; add commit message]
Reviewed-by: Simon McVittie's avatarSimon McVittie <smcv@collabora.com>
parent 30f8a38b
......@@ -2325,10 +2325,11 @@ complete_pending_call_and_unlock (DBusConnection *connection,
{
_dbus_pending_call_set_reply_unlocked (pending, message);
_dbus_pending_call_ref_unlocked (pending); /* in case there's no app with a ref held */
_dbus_pending_call_start_completion_unlocked(pending);
_dbus_connection_detach_pending_call_and_unlock (connection, pending);
/* Must be called unlocked since it invokes app callback */
_dbus_pending_call_complete (pending);
_dbus_pending_call_finish_completion (pending);
dbus_pending_call_unref (pending);
}
......
......@@ -41,7 +41,10 @@ void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCal
DBusConnection * _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending);
DBusConnection * _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending);
dbus_bool_t _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending);
void _dbus_pending_call_complete (DBusPendingCall *pending);
void _dbus_pending_call_start_completion_unlocked (DBusPendingCall *pending);
void _dbus_pending_call_finish_completion (DBusPendingCall *pending);
void _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
DBusMessage *message);
void _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
......
......@@ -194,18 +194,27 @@ _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
}
/**
* Calls notifier function for the pending call
* and sets the call to completed.
* Sets the pending call to completed
*
* @param pending the pending call
*
*/
void
_dbus_pending_call_complete (DBusPendingCall *pending)
_dbus_pending_call_start_completion_unlocked (DBusPendingCall *pending)
{
_dbus_assert (!pending->completed);
pending->completed = TRUE;
}
/**
* Call the notifier function for the pending call.
*
* @param pending the pending call
*/
void
_dbus_pending_call_finish_completion (DBusPendingCall *pending)
{
_dbus_assert (pending->completed);
if (pending->function)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment