]> code.delx.au - pulseaudio/commitdiff
reserve: Fix leaking NameLost signals after release+acquire
authorMikel Astiz <mikel.astiz@bmw-carit.de>
Wed, 30 Jan 2013 08:30:31 +0000 (09:30 +0100)
committerTanu Kaskinen <tanuk@iki.fi>
Thu, 31 Jan 2013 12:04:45 +0000 (14:04 +0200)
The use of the pseudo-blocking D-Bus calls leads to the problem that
NameLost signals are received after the reply to ReleaseName().

The problem with this is that a later acquisition of the same audio
device can potentially receive the NameLost signal corresponding to
the previous instance, due to the fact that the signal hasn't been
popped from the D-Bus message queue.

The simplest approach to solve this problem is to poll the actual name
owner from the D-Bus daemon, in order to make sure that we did really
lose the name.

The proposal uses a blocking call to GetNameOwner to avoid incosistent
states in the internal APIs: it would otherwise be possible to have a
"busy" device before the reservation has been lost, in the unlikely
case if some other process acquires the name before we got the
confirmation that the NameLost was actually true.

src/modules/reserve.c

index bbb6773141964249b04ff01f0784a6eb6776b5a2..f78805ed730e6662a51b499667cc132d15b46c16 100644 (file)
@@ -293,6 +293,7 @@ static DBusHandlerResult filter_handler(
 
        rd_device *d;
        DBusError error;
+       char *name_owner = NULL;
 
        dbus_error_init(&error);
 
@@ -310,6 +311,21 @@ static DBusHandlerResult filter_handler(
                        goto invalid;
 
                if (strcmp(name, d->service_name) == 0 && d->owning) {
+                       /* Verify the actual owner of the name to avoid leaked NameLost
+                        * signals from previous reservations. The D-Bus daemon will send
+                        * all messages asynchronously in the correct order, but we could
+                        * potentially process them too late due to the pseudo-blocking
+                        * call mechanism used during both acquisition and release. This
+                        * can happen if we release the device and immediately after
+                        * reacquire it before NameLost is processed. */
+                       if (!d->gave_up) {
+                               const char *un;
+
+                               if ((un = dbus_bus_get_unique_name(c)) && rd_dbus_get_name_owner(c, d->service_name, &name_owner, &error) == 0)
+                                       if (strcmp(name_owner, un) == 0)
+                                               goto invalid; /* Name still owned by us */
+                       }
+
                        d->owning = 0;
 
                        if (!d->gave_up)  {
@@ -326,6 +342,7 @@ static DBusHandlerResult filter_handler(
        }
 
 invalid:
+       free(name_owner);
        dbus_error_free(&error);
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;