[pulseaudio-discuss] [PATCH v3 04/18] sink, source: Simplify pa_sink/source_new() error handling
Tanu Kaskinen
tanu.kaskinen at linux.intel.com
Wed Jul 3 04:09:07 PDT 2013
Now the only exit from the function is either via "goto fail" or
normal success. I changed pa_hook_fire() return value checking into
assertions, because it's simpler (and I verified that none of the
hooks can ever fail in the current code base). I also changed all
pa_return_null_if_fail() calls into assertions.
Further simplification could be achieved if adding the sinks and
sources to the idxsets in pa_core were moved to _put() and if
unregistering the sink and source names was moved to _free(). Then
_new() wouldn't have to call _unlink() and _unlink() would have fewer
things to worry about.
The pa_sink/pa_source field initialization order was changed somewhat,
because _unlink() and _unref() rely on certain fields to be
initialized, so they had to be initialized before the first "goto
fail" line in _new().
---
src/pulsecore/sink.c | 89 ++++++++++++++++++++++++--------------------------
src/pulsecore/source.c | 66 ++++++++++++++++++-------------------
2 files changed, 73 insertions(+), 82 deletions(-)
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 0386580..6dd745f 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -185,33 +185,29 @@ pa_sink* pa_sink_new(
pa_assert_ctl_context();
s = pa_msgobject_new(pa_sink);
+ s->state = PA_SINK_INIT;
+ s->parent.parent.free = sink_free;
+ s->parent.process_msg = pa_sink_process_msg;
+ s->core = core;
+ s->inputs = pa_idxset_new(NULL, NULL);
if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
- pa_log_debug("Failed to register name %s.", data->name);
- pa_xfree(s);
- return NULL;
+ pa_log("Failed to register name %s.", data->name);
+ goto fail;
}
+ s->name = pa_xstrdup(name);
pa_sink_new_data_set_name(data, name);
- if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
- pa_xfree(s);
- pa_namereg_unregister(core, name);
- return NULL;
- }
-
- /* FIXME, need to free s here on failure */
-
- pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
- pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
+ pa_assert_se(pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) >= 0);
- pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
+ pa_assert(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
if (!data->channel_map_is_set)
- pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
+ pa_assert_se(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
- pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
- pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
+ pa_assert(pa_channel_map_valid(&data->channel_map));
+ pa_assert(data->channel_map.channels == data->sample_spec.channels);
/* FIXME: There should probably be a general function for checking whether
* the sink volume is allowed to be set, like there is for sink inputs. */
@@ -222,8 +218,8 @@ pa_sink* pa_sink_new(
data->save_volume = FALSE;
}
- pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
- pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
+ pa_assert(pa_cvolume_valid(&data->volume));
+ pa_assert(pa_cvolume_compatible(&data->volume, &data->sample_spec));
if (!data->muted_is_set)
data->muted = FALSE;
@@ -235,22 +231,12 @@ pa_sink* pa_sink_new(
pa_device_init_icon(data->proplist, TRUE);
pa_device_init_intended_roles(data->proplist);
- if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
- pa_xfree(s);
- pa_namereg_unregister(core, name);
- return NULL;
- }
+ pa_assert_se(pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) >= 0);
- s->parent.parent.free = sink_free;
- s->parent.process_msg = pa_sink_process_msg;
-
- s->core = core;
- s->state = PA_SINK_INIT;
s->flags = flags;
s->priority = 0;
s->suspend_cause = data->suspend_cause;
pa_sink_set_mixer_dirty(s, FALSE);
- s->name = pa_xstrdup(name);
s->proplist = pa_proplist_copy(data->proplist);
s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
s->module = data->module;
@@ -272,7 +258,6 @@ pa_sink* pa_sink_new(
s->alternate_sample_rate = 0;
}
- s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->input_to_master = NULL;
@@ -352,15 +337,6 @@ pa_sink* pa_sink_new(
if (s->card)
pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
- pt = pa_proplist_to_string_sep(s->proplist, "\n ");
- pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
- s->index,
- s->name,
- pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
- pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
- pt);
- pa_xfree(pt);
-
pa_source_new_data_init(&source_data);
pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
@@ -381,9 +357,8 @@ pa_sink* pa_sink_new(
pa_source_new_data_done(&source_data);
if (!s->monitor_source) {
- pa_sink_unlink(s);
- pa_sink_unref(s);
- return NULL;
+ pa_log("Failed to create a monitor source for sink %s.", s->name);
+ goto fail;
}
s->monitor_source->monitor_of = s;
@@ -392,7 +367,22 @@ pa_sink* pa_sink_new(
pa_source_set_fixed_latency(s->monitor_source, s->thread_info.fixed_latency);
pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
+ pt = pa_proplist_to_string_sep(s->proplist, "\n ");
+ pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
+ s->index,
+ s->name,
+ pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
+ pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
+ pt);
+ pa_xfree(pt);
+
return s;
+
+fail:
+ pa_sink_unlink(s);
+ pa_sink_unref(s);
+
+ return NULL;
}
/* Called from main context */
@@ -682,8 +672,9 @@ void pa_sink_unlink(pa_sink* s) {
if (linked)
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
- if (s->state != PA_SINK_UNLINKED)
+ if (s->state != PA_SINK_UNLINKED && s->name)
pa_namereg_unregister(s->core, s->name);
+
pa_idxset_remove_by_data(s->core->sinks, s, NULL);
if (s->card)
@@ -722,15 +713,19 @@ static void sink_free(pa_object *o) {
if (PA_SINK_IS_LINKED(s->state))
pa_sink_unlink(s);
- pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
+ if (s->state != PA_SINK_INIT)
+ pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
if (s->monitor_source) {
pa_source_unref(s->monitor_source);
s->monitor_source = NULL;
}
- pa_idxset_free(s->inputs, NULL);
- pa_hashmap_free(s->thread_info.inputs, (pa_free_cb_t) pa_sink_input_unref);
+ if (s->inputs)
+ pa_idxset_free(s->inputs, NULL);
+
+ if (s->thread_info.inputs)
+ pa_hashmap_free(s->thread_info.inputs, (pa_free_cb_t) pa_sink_input_unref);
if (s->silence.memblock)
pa_memblock_unref(s->silence.memblock);
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index c239360..dffa0d4 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -172,33 +172,29 @@ pa_source* pa_source_new(
pa_assert_ctl_context();
s = pa_msgobject_new(pa_source);
+ s->state = PA_SOURCE_INIT;
+ s->parent.parent.free = source_free;
+ s->parent.process_msg = pa_source_process_msg;
+ s->core = core;
+ s->outputs = pa_idxset_new(NULL, NULL);
if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
- pa_log_debug("Failed to register name %s.", data->name);
- pa_xfree(s);
- return NULL;
+ pa_log("Failed to register name %s.", data->name);
+ goto fail;
}
+ s->name = pa_xstrdup(name);
pa_source_new_data_set_name(data, name);
- if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
- pa_xfree(s);
- pa_namereg_unregister(core, name);
- return NULL;
- }
-
- /* FIXME, need to free s here on failure */
-
- pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
- pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
+ pa_assert_se(pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) >= 0);
- pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
+ pa_assert(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
if (!data->channel_map_is_set)
- pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
+ pa_assert_se(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
- pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
- pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
+ pa_assert(pa_channel_map_valid(&data->channel_map));
+ pa_assert(data->channel_map.channels == data->sample_spec.channels);
/* FIXME: There should probably be a general function for checking whether
* the source volume is allowed to be set, like there is for source outputs. */
@@ -209,8 +205,8 @@ pa_source* pa_source_new(
data->save_volume = FALSE;
}
- pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
- pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
+ pa_assert(pa_cvolume_valid(&data->volume));
+ pa_assert(pa_cvolume_compatible(&data->volume, &data->sample_spec));
if (!data->muted_is_set)
data->muted = FALSE;
@@ -222,22 +218,12 @@ pa_source* pa_source_new(
pa_device_init_icon(data->proplist, FALSE);
pa_device_init_intended_roles(data->proplist);
- if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
- pa_xfree(s);
- pa_namereg_unregister(core, name);
- return NULL;
- }
+ pa_assert_se(pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) >= 0);
- s->parent.parent.free = source_free;
- s->parent.process_msg = pa_source_process_msg;
-
- s->core = core;
- s->state = PA_SOURCE_INIT;
s->flags = flags;
s->priority = 0;
s->suspend_cause = data->suspend_cause;
pa_source_set_mixer_dirty(s, FALSE);
- s->name = pa_xstrdup(name);
s->proplist = pa_proplist_copy(data->proplist);
s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
s->module = data->module;
@@ -259,7 +245,6 @@ pa_source* pa_source_new(
s->alternate_sample_rate = 0;
}
- s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->monitor_of = NULL;
s->output_from_master = NULL;
@@ -347,6 +332,12 @@ pa_source* pa_source_new(
pa_xfree(pt);
return s;
+
+fail:
+ pa_source_unlink(s);
+ pa_source_unref(s);
+
+ return NULL;
}
/* Called from main context */
@@ -620,8 +611,9 @@ void pa_source_unlink(pa_source *s) {
if (linked)
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
- if (s->state != PA_SOURCE_UNLINKED)
+ if (s->state != PA_SOURCE_UNLINKED && s->name)
pa_namereg_unregister(s->core, s->name);
+
pa_idxset_remove_by_data(s->core->sources, s, NULL);
if (s->card)
@@ -657,10 +649,14 @@ static void source_free(pa_object *o) {
if (PA_SOURCE_IS_LINKED(s->state))
pa_source_unlink(s);
- pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
+ if (s->state != PA_SOURCE_INIT)
+ pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
+
+ if (s->outputs)
+ pa_idxset_free(s->outputs, NULL);
- pa_idxset_free(s->outputs, NULL);
- pa_hashmap_free(s->thread_info.outputs, (pa_free_cb_t) pa_source_output_unref);
+ if (s->thread_info.outputs)
+ pa_hashmap_free(s->thread_info.outputs, (pa_free_cb_t) pa_source_output_unref);
if (s->silence.memblock)
pa_memblock_unref(s->silence.memblock);
--
1.8.1.2
More information about the pulseaudio-discuss
mailing list