]> code.delx.au - pulseaudio/blobdiff - src/modules/module-zeroconf-publish.c
zeroconf-publish: Don't react to messages while shutting down
[pulseaudio] / src / modules / module-zeroconf-publish.c
index f96d4ce8fb1564e50510734b6bc55d7b2bb98c4a..db928507ab99aa6aaa4edba90b69e6f54cc97e53 100644 (file)
@@ -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,8 @@ 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;
 };
 
 /* Runs in PA mainloop context */
@@ -150,7 +152,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 +163,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 +441,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))
@@ -456,8 +458,11 @@ static pa_hook_result_t device_new_or_changed_cb(pa_core *c, pa_object *o, struc
     pa_assert(c);
     pa_object_assert_ref(o);
 
-    if (!shall_ignore(o))
+    if (!shall_ignore(o)) {
+        pa_threaded_mainloop_lock(u->mainloop);
         pa_mainloop_api_once(u->api, publish_service, get_service(u, o));
+        pa_threaded_mainloop_unlock(u->mainloop);
+    }
 
     return PA_HOOK_OK;
 }
@@ -575,12 +580,18 @@ static int publish_all_services(struct userdata *u) {
     pa_log_debug("Publishing services in Zeroconf");
 
     for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx)))
-        if (!shall_ignore(PA_OBJECT(sink)))
+        if (!shall_ignore(PA_OBJECT(sink))) {
+            pa_threaded_mainloop_lock(u->mainloop);
             pa_mainloop_api_once(u->api, publish_service, get_service(u, PA_OBJECT(sink)));
+            pa_threaded_mainloop_unlock(u->mainloop);
+        }
 
     for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx)))
-        if (!shall_ignore(PA_OBJECT(source)))
+        if (!shall_ignore(PA_OBJECT(source))) {
+            pa_threaded_mainloop_lock(u->mainloop);
             pa_mainloop_api_once(u->api, publish_service, get_service(u, PA_OBJECT(source)));
+            pa_threaded_mainloop_unlock(u->mainloop);
+        }
 
     if (publish_main_service(u) < 0)
         goto fail;
@@ -592,7 +603,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;
 
@@ -629,6 +640,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);
@@ -638,10 +654,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();
     }
@@ -666,7 +678,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:
@@ -675,12 +687,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);
                 }
             }
 
@@ -736,7 +748,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);
@@ -755,7 +767,10 @@ int pa__init(pa_module*m) {
 
     pa_threaded_mainloop_set_name(u->mainloop, "avahi-ml");
     pa_threaded_mainloop_start(u->mainloop);
+
+    pa_threaded_mainloop_lock(u->mainloop);
     pa_mainloop_api_once(u->api, create_client, u);
+    pa_threaded_mainloop_unlock(u->mainloop);
 
     pa_modargs_free(ma);
 
@@ -774,7 +789,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);
@@ -785,7 +800,7 @@ 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);
 }
 
 void pa__done(pa_module*m) {
@@ -795,7 +810,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);