From ac4e01ba1a2f302bf31dd511a7aff8da78660b15 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Mon, 7 Aug 2017 21:11:26 +0200 Subject: [PATCH] server: Cleanly shut down senders on exit. 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 | 1 + http_send.c | 1 + send.h | 2 ++ send_common.c | 6 ++++-- server.c | 26 +++++++++++++++++++++++--- server.h | 1 + udp_send.c | 15 +++++++++++++-- vss.c | 17 +++++++++++++++++ vss.h | 1 + 9 files changed, 63 insertions(+), 7 deletions(-) diff --git a/dccp_send.c b/dccp_send.c index 9ab21f8a..2821b21c 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -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, diff --git a/http_send.c b/http_send.c index 3df694de..6f06673c 100644 --- a/http_send.c +++ b/http_send.c @@ -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 dc9cd395..bca03b20 100644 --- 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. * diff --git a/send_common.c b/send_common.c index acb7aa6d..2088c8b4 100644 --- a/send_common.c +++ b/send_common.c @@ -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); diff --git a/server.c b/server.c index 4f1d5708..dd0acdad 100644 --- 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); diff --git a/server.h b/server.h index fb92beff..69d27054 100644 --- 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); diff --git a/udp_send.c b/udp_send.c index eea1c933..52947b20 100644 --- a/udp_send.c +++ b/udp_send.c @@ -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 fbc35e1a..55eaf2eb 100644 --- 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 5ebcc4e4..46bb0e73 100644 --- 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 -- 2.39.2