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 9ab21f8a096426cdb3f7d3a549bd53e270762655..2821b21ca8b96bc4e0d596689473d6e7e7bfcf7d 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 3df694de912e5a9d6e85544b3a68e68168004e31..6f06673ce5aabc64728980ddfed259a65d417d53 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 dc9cd3952238b19e6c332cd5420ba995487acda4..bca03b2027492a211bdaa5fa02eeaa1b50878ae1 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 acb7aa6d06777863cccffe8a317749618b11060b..2088c8b4de2947c94c238b41a471c2ecb89914d5 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 4f1d5708f76e997ff8fc5ee477dd97d65a6b3785..dd0acdadec94384b5c62ea878b617be52ab02b0d 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 fb92beff81218b9554cb4339a4e1105cfaf2d151..69d27054a82fa0347fb8774053711fca77605325 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 eea1c93355c1461ada446942ef4d2d91f71cef46..52947b20610a6b26280755cf0ddb5125ac5ae8a2 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 fbc35e1a71c8983a5045ff8e0b7bc300f1dfb0ab..55eaf2eb0525d402dad6d3b47afb3e8b0241dad3 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 5ebcc4e41644f82a02f4e1519057e2b738de2061..46bb0e7359bf82acc4736dbb061eda5d7faf24f8 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