src/modules/reserve-monitor.c | 59 +-------------------------------- src/modules/reserve.c | 73 ++++++++++++++++++++++++++++++++++++++++++ src/modules/reserve.h | 9 +++++ 3 files changed, 84 insertions(+), 57 deletions(-)
New commits: commit 58def1fd1de0de7d5732519539503a7ad83f24a2 Author: Mikel Astiz <mikel.as...@bmw-carit.de> Date: Wed Jan 30 09:30:31 2013 +0100 reserve: Fix leaking NameLost signals after release+acquire 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. diff --git a/src/modules/reserve.c b/src/modules/reserve.c index bbb6773..f78805e 100644 --- a/src/modules/reserve.c +++ b/src/modules/reserve.c @@ -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; commit cb0f3d287857d5385f4a879f8ab565d71bc8f068 Author: Mikel Astiz <mikel.as...@bmw-carit.de> Date: Wed Jan 30 09:30:30 2013 +0100 reserve: Move get_name_owner() to the public rd_device API The function is interesting for both rd_device and rd_monitor so make it part of the rd_device public API to avoid duplicated code. The decision to move the function to reserve.c is motivated by the fact that other projects (i.e. jack) use reserve.c only. Therefore, adding a reserve->reserve-monitor dependency should be avoided. diff --git a/src/modules/reserve-monitor.c b/src/modules/reserve-monitor.c index 4aa4a2b..70de870 100644 --- a/src/modules/reserve-monitor.c +++ b/src/modules/reserve-monitor.c @@ -32,6 +32,7 @@ #include <assert.h> #include "reserve-monitor.h" +#include "reserve.h" struct rm_monitor { int ref; @@ -120,62 +121,6 @@ invalid: return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -static int get_name_owner( - DBusConnection *connection, - const char *name, - char **name_owner, - DBusError *error) { - - DBusMessage *msg, *reply; - int r; - - *name_owner = NULL; - - if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner"))) { - r = -ENOMEM; - goto fail; - } - - if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { - r = -ENOMEM; - goto fail; - } - - reply = dbus_connection_send_with_reply_and_block(connection, msg, DBUS_TIMEOUT_USE_DEFAULT, error); - dbus_message_unref(msg); - msg = NULL; - - if (reply) { - if (!dbus_message_get_args(reply, error, DBUS_TYPE_STRING, name_owner, DBUS_TYPE_INVALID)) { - dbus_message_unref(reply); - r = -EIO; - goto fail; - } - - *name_owner = strdup(*name_owner); - dbus_message_unref(reply); - - if (!*name_owner) { - r = -ENOMEM; - goto fail; - } - - } else if (dbus_error_has_name(error, "org.freedesktop.DBus.Error.NameHasNoOwner")) - dbus_error_free(error); - else { - r = -EIO; - goto fail; - } - - return 0; - -fail: - if (msg) - dbus_message_unref(msg); - - return r; -} - int rm_watch( rm_monitor **_m, DBusConnection *connection, @@ -243,7 +188,7 @@ int rm_watch( m->matching = 1; - if ((r = get_name_owner(m->connection, m->service_name, &name_owner, error)) < 0) + if ((r = rd_dbus_get_name_owner(m->connection, m->service_name, &name_owner, error)) < 0) goto fail; m->busy = get_busy(m->connection, name_owner); diff --git a/src/modules/reserve.c b/src/modules/reserve.c index b4c168c..bbb6773 100644 --- a/src/modules/reserve.c +++ b/src/modules/reserve.c @@ -606,3 +606,59 @@ void* rd_get_userdata(rd_device *d) { return d->userdata; } + +int rd_dbus_get_name_owner( + DBusConnection *connection, + const char *name, + char **name_owner, + DBusError *error) { + + DBusMessage *msg, *reply; + int r; + + *name_owner = NULL; + + if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner"))) { + r = -ENOMEM; + goto fail; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { + r = -ENOMEM; + goto fail; + } + + reply = dbus_connection_send_with_reply_and_block(connection, msg, DBUS_TIMEOUT_USE_DEFAULT, error); + dbus_message_unref(msg); + msg = NULL; + + if (reply) { + if (!dbus_message_get_args(reply, error, DBUS_TYPE_STRING, name_owner, DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + r = -EIO; + goto fail; + } + + *name_owner = strdup(*name_owner); + dbus_message_unref(reply); + + if (!*name_owner) { + r = -ENOMEM; + goto fail; + } + + } else if (dbus_error_has_name(error, "org.freedesktop.DBus.Error.NameHasNoOwner")) + dbus_error_free(error); + else { + r = -EIO; + goto fail; + } + + return 0; + +fail: + if (msg) + dbus_message_unref(msg); + + return r; +} diff --git a/src/modules/reserve.h b/src/modules/reserve.h index bc50870..6527bd7 100644 --- a/src/modules/reserve.h +++ b/src/modules/reserve.h @@ -72,6 +72,15 @@ void rd_set_userdata(rd_device *d, void *userdata); * userdata was set. */ void* rd_get_userdata(rd_device *d); +/* Helper function to get the unique connection name owning a given + * name. Returns 0 on success, a negative errno style return value on + * error. */ +int rd_dbus_get_name_owner( + DBusConnection *connection, + const char *name, + char **name_owner, + DBusError *error); + #ifdef __cplusplus } #endif _______________________________________________ pulseaudio-commits mailing list pulseaudio-commits@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pulseaudio-commits