[pulseaudio-discuss] [PATCH 13/13] Remove refcounting from ports, sinks and sources
Tanu Kaskinen
tanuk at iki.fi
Tue Feb 12 11:37:03 PST 2013
Well, refcounting is not completely removed from sinks and sources,
because they are still subclasses of pa_object, which implies
refcounting, but the only ones that have a reference to a sink or
source are the sink and source implementors themselves, so in practice
there's no recounting being used. (Actually, pa_asyncmsgq also holds
a reference to a sink or source when the IO thread sends a message to
the sink or source. To avoid problems with this, the messages have to
be dispatched using pa_thread_mq_done() after shutting down the IO
thread, but before unreffing the sink or source.)
This should fix an issue reported by Luiz von Dentz: freeing the
profiles hashmap of pa_device_port accessed already freed memory,
because the hashmap uses the string stored at pa_card_profile.name
as the key, and the profiles are freed when cards are freed. Card
ports might not be freed at that time, because they are (were)
refcounted.
I first tried to fix this by removing the profiles from
pa_device_port.profiles when the profiles are removed, but there are
more things that would have to be updated too on a port when it's not
connected to a card anymore, notably the card pointer. It looked like
the card pointer could not be safely set to NULL without a significant
amount of work, and since I dislike refcounting, I decided to spend
the effort on removing the refcounting from ports instead. That
required removing it also from sinks and sources.
Ports are now owned solely by cards, except if a sink or source
doesn't belong to a card, in which case the sink or source owns its
ports. Currently there aren't any instances where a sink or source
would have port but not be a part of a card, though. So, when a card
is removed, all its sinks, sources and ports are removed too. To avoid
stale pointers, other code is expected to use the card/sink/source
unlink hooks to drop references before the objects get freed.
A note about the removed pa_sink_ref() and pa_source_ref() calls in
module-bluetooth-device: things probably break badly if the SCO sink
or source is removed while being in the "SCO over PCM" mode, but I
don't think that mode has ever worked properly if the SCO sink or
source can disappear at runtime. On the systems that I know are
using the "SCO over PCM" mode, the SCO devices stay loaded all the
time. If this seems unacceptable, I can add some code to
module-bluetooth-device to better track the SCO sink and source
existence.
---
src/modules/alsa/alsa-mixer.c | 4 +---
src/modules/alsa/alsa-ucm.c | 4 +---
src/modules/bluetooth/module-bluetooth-device.c | 8 +-------
src/modules/dbus/iface-device.c | 13 +++++--------
src/modules/module-suspend-on-idle.c | 9 ++-------
src/pulsecore/card.c | 13 +++++++++----
src/pulsecore/device-port.c | 15 +++------------
src/pulsecore/device-port.h | 5 +----
src/pulsecore/sink.c | 20 ++------------------
src/pulsecore/source.c | 4 ++--
10 files changed, 27 insertions(+), 68 deletions(-)
diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 97f25af..a47b810 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -4473,10 +4473,8 @@ static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
if (cp)
pa_hashmap_put(p->profiles, cp->name, cp);
- if (extra) {
+ if (extra)
pa_hashmap_put(extra, p->name, p);
- pa_device_port_ref(p);
- }
return p;
}
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index e01721f..61595e0 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -713,10 +713,8 @@ static void ucm_add_port_combination(
pa_hashmap_put(port->profiles, cp->name, cp);
}
- if (hash) {
+ if (hash)
pa_hashmap_put(hash, port->name, port);
- pa_device_port_ref(port);
- }
}
static int ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink) {
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 06fe0be..33b4b16 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -1548,13 +1548,11 @@ static void connect_ports(struct userdata *u, void *sink_or_source_new_data, pa_
case PROFILE_A2DP:
pa_assert_se(port = pa_hashmap_get(u->card->ports, "bluetooth-output"));
pa_assert_se(pa_hashmap_put(data.sink_new_data->ports, port->name, port) >= 0);
- pa_device_port_ref(port);
break;
case PROFILE_A2DP_SOURCE:
pa_assert_se(port = pa_hashmap_get(u->card->ports, "a2dp-input"));
pa_assert_se(pa_hashmap_put(data.source_new_data->ports, port->name, port) >= 0);
- pa_device_port_ref(port);
break;
case PROFILE_HSP:
@@ -1565,7 +1563,6 @@ static void connect_ports(struct userdata *u, void *sink_or_source_new_data, pa_
pa_assert_se(port = pa_hashmap_get(u->card->ports, "hsp-input"));
pa_assert_se(pa_hashmap_put(data.source_new_data->ports, port->name, port) >= 0);
}
- pa_device_port_ref(port);
break;
case PROFILE_HFGW:
@@ -1576,7 +1573,6 @@ static void connect_ports(struct userdata *u, void *sink_or_source_new_data, pa_
pa_assert_se(port = pa_hashmap_get(u->card->ports, "hfgw-input"));
pa_assert_se(pa_hashmap_put(data.source_new_data->ports, port->name, port) >= 0);
}
- pa_device_port_ref(port);
break;
default:
@@ -2023,8 +2019,6 @@ static int start_thread(struct userdata *u) {
return -1;
}
- pa_sink_ref(u->sink);
- pa_source_ref(u->source);
/* FIXME: monitor stream_fd error */
return 0;
}
@@ -2432,7 +2426,7 @@ static pa_hook_result_t uuid_added_cb(pa_bluetooth_discovery *y, const struct pa
pa_card_add_ports(u->card, new_ports);
- pa_hashmap_free(new_ports, (pa_free_cb_t) pa_device_port_unref);
+ pa_hashmap_free(new_ports, NULL);
return PA_HOOK_OK;
}
diff --git a/src/modules/dbus/iface-device.c b/src/modules/dbus/iface-device.c
index 888d407..bc8255f 100644
--- a/src/modules/dbus/iface-device.c
+++ b/src/modules/dbus/iface-device.c
@@ -1208,7 +1208,7 @@ pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_si
d = pa_xnew0(pa_dbusiface_device, 1);
d->core = core;
- d->sink = pa_sink_ref(sink);
+ d->sink = sink;
d->type = PA_DEVICE_TYPE_SINK;
d->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, SINK_OBJECT_NAME, sink->index);
d->volume = *pa_sink_get_volume(sink, FALSE);
@@ -1242,7 +1242,7 @@ pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_
d = pa_xnew0(pa_dbusiface_device, 1);
d->core = core;
- d->source = pa_source_ref(source);
+ d->source = source;
d->type = PA_DEVICE_TYPE_SOURCE;
d->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, SOURCE_OBJECT_NAME, source->index);
d->volume = *pa_source_get_volume(source, FALSE);
@@ -1271,14 +1271,11 @@ void pa_dbusiface_device_free(pa_dbusiface_device *d) {
pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, device_interface_info.name) >= 0);
- if (d->type == PA_DEVICE_TYPE_SINK) {
+ if (d->type == PA_DEVICE_TYPE_SINK)
pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, sink_interface_info.name) >= 0);
- pa_sink_unref(d->sink);
-
- } else {
+ else
pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, source_interface_info.name) >= 0);
- pa_source_unref(d->source);
- }
+
pa_hashmap_free(d->ports, (pa_free_cb_t) pa_dbusiface_device_port_free);
pa_proplist_free(d->proplist);
pa_dbus_protocol_unref(d->dbus_protocol);
diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c
index 02a6b91..2325308 100644
--- a/src/modules/module-suspend-on-idle.c
+++ b/src/modules/module-suspend-on-idle.c
@@ -344,8 +344,8 @@ static pa_hook_result_t device_new_hook_cb(pa_core *c, pa_object *o, struct user
d = pa_xnew(struct device_info, 1);
d->userdata = u;
- d->source = source ? pa_source_ref(source) : NULL;
- d->sink = sink ? pa_sink_ref(sink) : NULL;
+ d->source = source;
+ d->sink = sink;
d->time_event = pa_core_rttime_new(c, PA_USEC_INVALID, timeout_cb, d);
pa_hashmap_put(u->device_infos, o, d);
@@ -359,11 +359,6 @@ static pa_hook_result_t device_new_hook_cb(pa_core *c, pa_object *o, struct user
static void device_info_free(struct device_info *d) {
pa_assert(d);
- if (d->source)
- pa_source_unref(d->source);
- if (d->sink)
- pa_sink_unref(d->sink);
-
d->userdata->core->mainloop->time_free(d->time_event);
pa_xfree(d);
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index c05fc7a..aa7f58a 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -125,12 +125,14 @@ void pa_card_new_data_done(pa_card_new_data *data) {
pa_proplist_free(data->proplist);
+ /* Ports must be freed before profiles, because the profiles hashmap in
+ * pa_device_port uses profile names as keys. */
+ if (data->ports)
+ pa_hashmap_free(data->ports, (pa_free_cb_t) pa_device_port_free);
+
if (data->profiles)
pa_hashmap_free(data->profiles, (pa_free_cb_t) pa_card_profile_free);
- if (data->ports)
- pa_hashmap_free(data->ports, (pa_free_cb_t) pa_device_port_unref);
-
pa_xfree(data->name);
pa_xfree(data->active_profile);
}
@@ -237,7 +239,10 @@ void pa_card_free(pa_card *c) {
pa_assert(pa_idxset_isempty(c->sources));
pa_idxset_free(c->sources, NULL);
- pa_hashmap_free(c->ports, (pa_free_cb_t) pa_device_port_unref);
+ /* Ports must be freed before profiles, because the profiles hashmap in
+ * pa_device_port uses profile names as keys. */
+ if (c->ports)
+ pa_hashmap_free(c->ports, (pa_free_cb_t) pa_device_port_free);
if (c->profiles)
pa_hashmap_free(c->profiles, (pa_free_cb_t) pa_card_profile_free);
diff --git a/src/pulsecore/device-port.c b/src/pulsecore/device-port.c
index e0f9560..5e5d48a 100644
--- a/src/pulsecore/device-port.c
+++ b/src/pulsecore/device-port.c
@@ -24,10 +24,7 @@
#include "device-port.h"
#include <pulsecore/card.h>
-PA_DEFINE_PUBLIC_CLASS(pa_device_port, pa_object);
-
-void pa_device_port_set_available(pa_device_port *p, pa_port_available_t status)
-{
+void pa_device_port_set_available(pa_device_port *p, pa_port_available_t status) {
pa_core *core;
pa_assert(p);
@@ -48,11 +45,8 @@ void pa_device_port_set_available(pa_device_port *p, pa_port_available_t status)
pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
}
-static void device_port_free(pa_object *o) {
- pa_device_port *p = PA_DEVICE_PORT(o);
-
+void pa_device_port_free(pa_device_port *p) {
pa_assert(p);
- pa_assert(pa_device_port_refcnt(p) == 0);
if (p->proplist)
pa_proplist_free(p->proplist);
@@ -65,15 +59,12 @@ static void device_port_free(pa_object *o) {
pa_xfree(p);
}
-
pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, size_t extra) {
pa_device_port *p;
pa_assert(name);
- p = PA_DEVICE_PORT(pa_object_new_internal(PA_ALIGN(sizeof(pa_device_port)) + extra, pa_device_port_type_id, pa_device_port_check_type));
- p->parent.free = device_port_free;
-
+ p = pa_xmalloc0(PA_ALIGN(sizeof(pa_device_port)) + extra);
p->name = pa_xstrdup(name);
p->description = pa_xstrdup(description);
p->core = c;
diff --git a/src/pulsecore/device-port.h b/src/pulsecore/device-port.h
index 40306f5..ac41bc0 100644
--- a/src/pulsecore/device-port.h
+++ b/src/pulsecore/device-port.h
@@ -39,7 +39,6 @@ typedef struct pa_device_port pa_device_port;
#include <pulsecore/card.h>
struct pa_device_port {
- pa_object parent; /* Needed for reference counting */
pa_core *core;
pa_card *card;
@@ -58,12 +57,10 @@ struct pa_device_port {
/* .. followed by some implementation specific data */
};
-PA_DECLARE_PUBLIC_CLASS(pa_device_port);
-#define PA_DEVICE_PORT(s) (pa_device_port_cast(s))
-
#define PA_DEVICE_PORT_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_device_port))))
pa_device_port *pa_device_port_new(pa_core *c, const char *name, const char *description, size_t extra);
+void pa_device_port_free(pa_device_port *p);
/* The port's available status has changed */
void pa_device_port_set_available(pa_device_port *p, pa_port_available_t available);
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index e0039fa..3bbc661 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -141,7 +141,7 @@ void pa_sink_new_data_done(pa_sink_new_data *data) {
pa_proplist_free(data->proplist);
if (data->ports)
- pa_hashmap_free(data->ports, (pa_free_cb_t) pa_device_port_unref);
+ pa_hashmap_free(data->ports, data->card ? NULL : (pa_free_cb_t) pa_device_port_free);
pa_xfree(data->name);
pa_xfree(data->active_port);
@@ -742,7 +742,7 @@ static void sink_free(pa_object *o) {
pa_proplist_free(s->proplist);
if (s->ports)
- pa_hashmap_free(s->ports, (pa_free_cb_t) pa_device_port_unref);
+ pa_hashmap_free(s->ports, s->card ? NULL : (pa_free_cb_t) pa_device_port_free);
pa_xfree(s);
}
@@ -1109,8 +1109,6 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
return;
}
- pa_sink_ref(s);
-
if (length <= 0)
length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
@@ -1168,8 +1166,6 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
}
inputs_drop(s, info, n, result);
-
- pa_sink_unref(s);
}
/* Called from IO thread context */
@@ -1194,8 +1190,6 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
return;
}
- pa_sink_ref(s);
-
length = target->length;
block_size_max = pa_mempool_block_size_max(s->core->mempool);
if (length > block_size_max)
@@ -1253,8 +1247,6 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
}
inputs_drop(s, info, n, target);
-
- pa_sink_unref(s);
}
/* Called from IO thread context */
@@ -1278,8 +1270,6 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
return;
}
- pa_sink_ref(s);
-
l = target->length;
d = 0;
while (l > 0) {
@@ -1292,8 +1282,6 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
d += chunk.length;
l -= chunk.length;
}
-
- pa_sink_unref(s);
}
/* Called from IO thread context */
@@ -1308,8 +1296,6 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
- pa_sink_ref(s);
-
pa_sink_render(s, length, result);
if (result->length < length) {
@@ -1325,8 +1311,6 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
result->length = length;
}
-
- pa_sink_unref(s);
}
/* Called from main thread */
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 972113d..8f0ba68 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -133,7 +133,7 @@ void pa_source_new_data_done(pa_source_new_data *data) {
pa_proplist_free(data->proplist);
if (data->ports)
- pa_hashmap_free(data->ports, (pa_free_cb_t) pa_device_port_unref);
+ pa_hashmap_free(data->ports, data->card ? NULL : (pa_free_cb_t) pa_device_port_free);
pa_xfree(data->name);
pa_xfree(data->active_port);
@@ -672,7 +672,7 @@ static void source_free(pa_object *o) {
pa_proplist_free(s->proplist);
if (s->ports)
- pa_hashmap_free(s->ports, (pa_free_cb_t) pa_device_port_unref);
+ pa_hashmap_free(s->ports, s->card ? NULL : (pa_free_cb_t) pa_device_port_free);
pa_xfree(s);
}
--
1.7.10.4
More information about the pulseaudio-discuss
mailing list