dbus: clean up sources and connections

Set source user data for all dbus sources and set a destroy notify
when removed.
Remove the dbus user data to remove the source user data.
Clean up remaining sources when destoying a connection
Clean up remaining connections when freeing the dbus plugins.

Fixes #1114
This commit is contained in:
Wim Taymans 2021-05-01 09:33:06 +02:00
parent 85b136d8ce
commit ebe5fa7809

View file

@ -50,6 +50,12 @@ struct impl {
struct spa_list connection_list;
};
struct source_data {
struct spa_list link;
struct spa_source *source;
struct connection *conn;
};
struct connection {
struct spa_list link;
@ -57,8 +63,20 @@ struct connection {
struct impl *impl;
DBusConnection *conn;
struct spa_source *dispatch_event;
struct spa_list source_list;
};
static void source_data_free(void *data)
{
struct source_data *d = data;
struct connection *conn = d->conn;
struct impl *impl = conn->impl;
spa_list_remove(&d->link);
spa_loop_utils_destroy_source(impl->utils, d->source);
free(d);
}
static void dispatch_cb(void *userdata)
{
struct connection *conn = userdata;
@ -128,17 +146,20 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *userdata)
{
struct connection *conn = userdata;
struct impl *impl = conn->impl;
struct spa_source *source;
struct source_data *data;
spa_log_debug(impl->log, "add watch %p %d", watch, dbus_watch_get_unix_fd(watch));
data = calloc(1, sizeof(struct source_data));
data->conn = conn;
/* we dup because dbus tends to add the same fd multiple times and our epoll
* implementation does not like that */
source = spa_loop_utils_add_io(impl->utils,
data->source = spa_loop_utils_add_io(impl->utils,
dup(dbus_watch_get_unix_fd(watch)),
dbus_to_io(watch), true, handle_io_event, watch);
spa_list_append(&conn->source_list, &data->link);
dbus_watch_set_data(watch, source, NULL);
dbus_watch_set_data(watch, data, source_data_free);
return TRUE;
}
@ -146,39 +167,29 @@ static void remove_watch(DBusWatch *watch, void *userdata)
{
struct connection *conn = userdata;
struct impl *impl = conn->impl;
struct spa_source *source;
spa_log_debug(impl->log, "remove watch %p", watch);
if ((source = dbus_watch_get_data(watch)))
spa_loop_utils_destroy_source(conn->impl->utils, source);
dbus_watch_set_data(watch, NULL, NULL);
}
static void toggle_watch(DBusWatch *watch, void *userdata)
{
struct connection *conn = userdata;
struct impl *impl = conn->impl;
struct spa_source *source;
struct source_data *data;
spa_log_debug(impl->log, "toggle watch %p", watch);
source = dbus_watch_get_data(watch);
spa_loop_utils_update_io(impl->utils, source, dbus_to_io(watch));
if ((data = dbus_watch_get_data(watch)) != NULL)
spa_loop_utils_update_io(impl->utils, data->source, dbus_to_io(watch));
}
struct timeout_data {
struct spa_source *source;
struct connection *conn;
};
static void
handle_timer_event(void *userdata, uint64_t expirations)
{
DBusTimeout *timeout = userdata;
uint64_t t;
struct timespec ts;
struct timeout_data *data = dbus_timeout_get_data(timeout);
struct source_data *data = dbus_timeout_get_data(timeout);
struct connection *conn = data->conn;
struct impl *impl = conn->impl;
@ -199,7 +210,7 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
struct connection *conn = userdata;
struct impl *impl = conn->impl;
struct timespec ts;
struct timeout_data *data;
struct source_data *data;
uint64_t t;
if (!dbus_timeout_get_enabled(timeout))
@ -207,10 +218,12 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
spa_log_debug(impl->log, "add timeout %p conn:%p impl:%p", timeout, conn, impl);
data = calloc(1, sizeof(struct timeout_data));
data = calloc(1, sizeof(struct source_data));
data->conn = conn;
data->source = spa_loop_utils_add_timer(impl->utils, handle_timer_event, timeout);
dbus_timeout_set_data(timeout, data, NULL);
spa_list_append(&conn->source_list, &data->link);
dbus_timeout_set_data(timeout, data, source_data_free);
t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
ts.tv_sec = t / SPA_NSEC_PER_SEC;
@ -224,21 +237,15 @@ static void remove_timeout(DBusTimeout *timeout, void *userdata)
{
struct connection *conn = userdata;
struct impl *impl = conn->impl;
struct timeout_data *data;
spa_log_debug(impl->log, "remove timeout %p conn:%p impl:%p", timeout, conn, impl);
if ((data = dbus_timeout_get_data(timeout))) {
spa_loop_utils_destroy_source(impl->utils, data->source);
free(data);
}
dbus_timeout_set_data(timeout, NULL, NULL);
}
static void toggle_timeout(DBusTimeout *timeout, void *userdata)
{
struct connection *conn = userdata;
struct impl *impl = conn->impl;
struct timeout_data *data;
struct source_data *data;
struct timespec ts, *tsp;
data = dbus_timeout_get_data(timeout);
@ -271,6 +278,24 @@ impl_connection_get(struct spa_dbus_connection *conn)
return this->conn;
}
static void connection_free(struct connection *conn)
{
struct impl *impl = conn->impl;
struct source_data *data;
spa_list_remove(&conn->link);
dbus_connection_close(conn->conn);
dbus_connection_unref(conn->conn);
spa_list_consume(data, &conn->source_list, link)
source_data_free(data);
spa_loop_utils_destroy_source(impl->utils, conn->dispatch_event);
free(conn);
}
static void
impl_connection_destroy(struct spa_dbus_connection *conn)
{
@ -278,15 +303,7 @@ impl_connection_destroy(struct spa_dbus_connection *conn)
struct impl *impl = this->impl;
spa_log_debug(impl->log, "destroy conn %p", this);
dbus_connection_close(this->conn);
dbus_connection_unref(this->conn);
spa_loop_utils_destroy_source(impl->utils, this->dispatch_event);
spa_list_remove(&this->link);
free(this);
connection_free(this);
}
static const struct spa_dbus_connection impl_connection = {
@ -318,6 +335,8 @@ impl_get_connection(void *object,
if (conn->dispatch_event == NULL)
goto no_event;
spa_list_init(&conn->source_list);
dbus_connection_set_exit_on_disconnect(conn->conn, false);
dbus_connection_set_dispatch_status_function(conn->conn, dispatch_status, conn, NULL);
dbus_connection_set_watch_functions(conn->conn, add_watch, remove_watch, toggle_watch, conn,
@ -375,7 +394,13 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
static int impl_clear(struct spa_handle *handle)
{
struct impl *impl = (struct impl *) handle;
struct connection *conn;
spa_return_val_if_fail(handle != NULL, -EINVAL);
spa_list_consume(conn, &impl->connection_list, link)
connection_free(conn);
return 0;
}