server: Cleanly shut down senders on exit.
authorAndre Noll <maan@tuebingen.mpg.de>
Mon, 7 Aug 2017 19:11:26 +0000 (21:11 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 13 Mar 2018 02:28:10 +0000 (03:28 +0100)
This introduces ->shutdown for struct sender. Each of the three senders
implements the new method to close file descriptors and to deallocate
the resources occupied by the sender. The method is only called on
exit via the new vss_shutdown() from both server and command handler
context after schedule() returns.

We need to introduce another helper, process_is_command_handler(), to
distinguish between the two callers.

dccp_send.c
http_send.c
send.h
send_common.c
server.c
server.h
udp_send.c
vss.c
vss.h

index 9ab21f8..2821b21 100644 (file)
@@ -241,6 +241,7 @@ static void dccp_send_init(void)
 const struct sender dccp_sender = {
        .name = "dccp",
        .init = dccp_send_init,
+       .shutdown = dccp_shutdown_clients,
        .pre_select = dccp_pre_select,
        .post_select = dccp_post_select,
        .shutdown_clients = dccp_shutdown_clients,
index 3df694d..6f06673 100644 (file)
@@ -266,6 +266,7 @@ static void http_send_init(void)
 const struct sender http_sender = {
        .name = "http",
        .init = http_send_init,
+       .shutdown = http_shutdown_clients,
        .pre_select = http_pre_select,
        .post_select = http_post_select,
        .send = http_send,
diff --git a/send.h b/send.h
index dc9cd39..bca03b2 100644 (file)
--- a/send.h
+++ b/send.h
@@ -85,6 +85,8 @@ struct sender {
         * the clients aware of the end-of-file condition.
         */
        void (*shutdown_clients)(void);
+       /** Dellocate all resources. Only called on exit. */
+       void (*shutdown)(void);
        /**
         * Array of function pointers for the sender subcommands.
         *
index acb7aa6..2088c8b 100644 (file)
@@ -74,8 +74,10 @@ void shutdown_client(struct sender_client *sc, struct sender_status *ss)
 {
        PARA_INFO_LOG("shutting down %s on fd %d\n", sc->name, sc->fd);
        free(sc->name);
-       close(sc->fd);
-       del_close_on_fork_list(sc->fd);
+       if (!process_is_command_handler()) {
+               close(sc->fd);
+               del_close_on_fork_list(sc->fd);
+       }
        cq_destroy(sc->cq);
        list_del(&sc->node);
        free(sc->private_data);
index 4f1d570..dd0acda 100644 (file)
--- a/server.c
+++ b/server.c
@@ -106,6 +106,24 @@ static struct signal_task *signal_task;
 /** The process id of the audio file selector process. */
 pid_t afs_pid = 0;
 
+/* The the main server process (parent of afs and the command handlers). */
+static pid_t server_pid;
+
+/**
+ * Tell whether the executing process is a command handler.
+ *
+ * Cleanup on exit must be performed differently for command handlers.
+ *
+ * \return True if the pid of the executing process is neither the server pid
+ * nor the afs pid.
+ */
+bool process_is_command_handler(void)
+{
+       pid_t pid = getpid();
+
+       return pid != afs_pid && pid != server_pid;
+}
+
 /** The task responsible for server command handling. */
 struct server_command_task {
        /** TCP port on which para_server listens for connections. */
@@ -532,6 +550,7 @@ static void server_init(int argc, char **argv, struct server_command_task *sct)
        /* become daemon */
        if (OPT_GIVEN(DAEMON))
                daemon_pipe = daemonize(true /* parent waits for SIGTERM */);
+       server_pid = getpid();
        init_random_seed_or_die();
        daemon_log_welcome("server");
        init_ipc_or_die(); /* init mmd struct and mmd->lock */
@@ -632,12 +651,12 @@ int main(int argc, char *argv[])
        ret = schedule(&sched);
        sched_shutdown(&sched);
        signal_shutdown(signal_task);
-       if (sct->child_fd < 0) { /* parent (server) */
+       if (!process_is_command_handler()) { /* parent (server) */
                if (ret < 0)
                        PARA_EMERG_LOG("%s\n", para_strerror(-ret));
-       } else { /* child (command handler) */
+       } else {
                /*
-                * We hold the lock: it was re-acquired in server_select()
+                * We hold the mmd lock: it was re-acquired in server_select()
                 * after the select call.
                 */
                mutex_unlock(mmd_mutex);
@@ -645,6 +664,7 @@ int main(int argc, char *argv[])
                close_listed_fds();
                ret = handle_connect(sct->child_fd);
        }
+       vss_shutdown();
        lls_free_parse_result(server_lpr, CMD_PTR);
        if (server_lpr != cmdline_lpr)
                lls_free_parse_result(cmdline_lpr, CMD_PTR);
index fb92bef..69d2705 100644 (file)
--- a/server.h
+++ b/server.h
@@ -116,3 +116,4 @@ extern struct lls_parse_result *server_lpr;
 int handle_connect(int fd);
 void parse_config_or_die(bool reload);
 char *server_get_tasks(void);
+bool process_is_command_handler(void);
index eea1c93..52947b2 100644 (file)
@@ -72,8 +72,11 @@ static void udp_delete_target(struct sender_client *sc, const char *msg)
 
        PARA_NOTICE_LOG("deleting %s (%s) from list\n", sc->name, msg);
        udp_close_target(sc);
-       close(sc->fd);
-       del_close_on_fork_list(sc->fd);
+       /* command handlers already called close_listed_fds() */
+       if (!process_is_command_handler()) {
+               close(sc->fd);
+               del_close_on_fork_list(sc->fd);
+       }
        vss_del_fec_client(ut->fc);
        list_del(&sc->node);
        free(sc->name);
@@ -164,6 +167,13 @@ static void udp_shutdown_targets(void)
                udp_close_target(sc);
 }
 
+static void udp_shutdown(void)
+{
+       struct sender_client *sc, *tmp;
+       list_for_each_entry_safe(sc, tmp, &targets, node)
+               udp_delete_target(sc, "shutdown");
+}
+
 static int udp_resolve_target(const char *url, struct sender_command_data *scd)
 {
        const char *result;
@@ -435,6 +445,7 @@ static void udp_send_init(void)
 const struct sender udp_sender = {
        .name = "udp",
        .init = udp_send_init,
+       .shutdown = udp_shutdown,
        .shutdown_clients = udp_shutdown_targets,
        .resolve_target = udp_resolve_target,
        .client_cmds = {
diff --git a/vss.c b/vss.c
index fbc35e1..55eaf2e 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -1188,3 +1188,20 @@ void vss_init(int afs_socket, struct sched *s)
                .context = vsst,
        }, s);
 }
+
+/**
+ * Turn off the virtual streaming system.
+ *
+ * This is only executed on exit. It calls the ->shutdowwn method of all senders.
+ */
+void vss_shutdown(void)
+{
+       int i;
+
+       FOR_EACH_SENDER(i) {
+               if (!senders[i]->shutdown)
+                       continue;
+               PARA_NOTICE_LOG("shutting down %s sender\n", senders[i]->name);
+               senders[i]->shutdown();
+       }
+}
diff --git a/vss.h b/vss.h
index 5ebcc4e..46bb0e7 100644 (file)
--- a/vss.h
+++ b/vss.h
@@ -9,6 +9,7 @@ unsigned int vss_repos(void);
 unsigned int vss_paused(void);
 unsigned int vss_stopped(void);
 struct timeval *vss_chunk_time(void);
+void vss_shutdown(void);
 
 /** Stop playing after current audio file. */
 #define VSS_NOMORE 1