X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/e1e154c7377779377fa1a36655a10effd693f7b5..b75a20db10c8605d98324a7782a7da6483ae9f14:/src/modules/module-zeroconf-publish.c diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index b76a215c..be8806e3 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -53,7 +53,7 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher"); PA_MODULE_VERSION(PACKAGE_VERSION); -PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_LOAD_ONCE(true); #define SERVICE_TYPE_SINK "_pulse-sink._tcp" #define SERVICE_TYPE_SOURCE "_pulse-source._tcp" @@ -141,6 +141,9 @@ struct userdata { pa_hook_slot *sink_new_slot, *source_new_slot, *sink_unlink_slot, *source_unlink_slot, *sink_changed_slot, *source_changed_slot; pa_native_protocol *native; + + bool shutting_down; /* Used in the main thread. */ + bool client_freed; /* Used in the Avahi thread. */ }; /* Runs in PA mainloop context */ @@ -150,7 +153,7 @@ static void get_service_data(struct service *s, pa_object *device) { if (pa_sink_isinstance(device)) { pa_sink *sink = PA_SINK(device); - s->is_sink = TRUE; + s->is_sink = true; s->service_type = SERVICE_TYPE_SINK; s->ss = sink->sample_spec; s->cm = sink->channel_map; @@ -161,7 +164,7 @@ static void get_service_data(struct service *s, pa_object *device) { } else if (pa_source_isinstance(device)) { pa_source *source = PA_SOURCE(device); - s->is_sink = FALSE; + s->is_sink = false; s->service_type = SERVICE_TYPE_SOURCE; s->ss = source->sample_spec; s->cm = source->channel_map; @@ -439,7 +442,7 @@ static void service_free(struct service *s) { } /* Runs in PA mainloop context */ -static pa_bool_t shall_ignore(pa_object *o) { +static bool shall_ignore(pa_object *o) { pa_object_assert_ref(o); if (pa_sink_isinstance(o)) @@ -601,7 +604,7 @@ fail: } /* Runs in Avahi mainloop context */ -static void unpublish_all_services(struct userdata *u, pa_bool_t rem) { +static void unpublish_all_services(struct userdata *u, bool rem) { void *state = NULL; struct service *s; @@ -638,6 +641,11 @@ static void unpublish_all_services(struct userdata *u, pa_bool_t rem) { static int avahi_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = (struct userdata *) data; + pa_assert(u); + + if (u->shutting_down) + return 0; + switch (code) { case AVAHI_MESSAGE_PUBLISH_ALL: publish_all_services(u); @@ -647,10 +655,6 @@ static int avahi_process_msg(pa_msgobject *o, int code, void *data, int64_t offs pa_module_unload(u->core, u->module, true); break; - case AVAHI_MESSAGE_SHUTDOWN_COMPLETE: - /* pa__done() is waiting for this */ - break; - default: pa_assert_not_reached(); } @@ -675,7 +679,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda case AVAHI_CLIENT_S_COLLISION: pa_log_debug("Host name collision"); - unpublish_all_services(u, FALSE); + unpublish_all_services(u, false); break; case AVAHI_CLIENT_FAILURE: @@ -684,12 +688,12 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda pa_log_debug("Avahi daemon disconnected."); - unpublish_all_services(u, TRUE); + unpublish_all_services(u, true); avahi_client_free(u->client); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { pa_log("avahi_client_new() failed: %s", avahi_strerror(error)); - pa_module_unload_request(u->module, TRUE); + pa_module_unload_request(u->module, true); } } @@ -704,6 +708,16 @@ static void create_client(pa_mainloop_api *api PA_GCC_UNUSED, void *userdata) { struct userdata *u = (struct userdata *) userdata; int error; + /* create_client() and client_free() are called via defer events. If the + * two defer events are created very quickly one after another, we can't + * assume that the defer event that runs create_client() will be dispatched + * before the defer event that runs client_free() (at the time of writing, + * pa_mainloop actually always dispatches queued defer events in reverse + * creation order). For that reason we must be prepared for the case where + * client_free() has already been called. */ + if (u->client_freed) + return; + pa_thread_mq_install(&u->thread_mq); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { @@ -730,7 +744,7 @@ int pa__init(pa_module*m) { goto fail; } - m->userdata = u = pa_xnew(struct userdata, 1); + m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; u->native = pa_native_protocol_get(u->core); @@ -745,7 +759,7 @@ int pa__init(pa_module*m) { u->avahi_poll = pa_avahi_poll_new(u->api); - u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + u->services = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) service_free); u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); @@ -754,8 +768,6 @@ int pa__init(pa_module*m) { u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u); - u->main_entry_group = NULL; - un = pa_get_user_name_malloc(); hn = pa_get_host_name_malloc(); u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", un, hn), AVAHI_LABEL_MAX-1); @@ -786,7 +798,7 @@ fail: static void client_free(pa_mainloop_api *api PA_GCC_UNUSED, void *userdata) { struct userdata *u = (struct userdata *) userdata; - pa_hashmap_free(u->services, (pa_free_cb_t) service_free); + pa_hashmap_free(u->services); if (u->main_entry_group) avahi_entry_group_free(u->main_entry_group); @@ -797,7 +809,9 @@ static void client_free(pa_mainloop_api *api PA_GCC_UNUSED, void *userdata) { if (u->avahi_poll) pa_avahi_poll_free(u->avahi_poll); - pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->msg), AVAHI_MESSAGE_SHUTDOWN_COMPLETE, NULL, 0, NULL, NULL); + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->msg), AVAHI_MESSAGE_SHUTDOWN_COMPLETE, u, 0, NULL, NULL); + + u->client_freed = true; } void pa__done(pa_module*m) { @@ -807,7 +821,11 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; + u->shutting_down = true; + + pa_threaded_mainloop_lock(u->mainloop); pa_mainloop_api_once(u->api, client_free, u); + pa_threaded_mainloop_unlock(u->mainloop); pa_asyncmsgq_wait_for(u->thread_mq.outq, AVAHI_MESSAGE_SHUTDOWN_COMPLETE); pa_threaded_mainloop_stop(u->mainloop);