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