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.
const struct sender dccp_sender = {
.name = "dccp",
.init = dccp_send_init,
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,
.pre_select = dccp_pre_select,
.post_select = dccp_post_select,
.shutdown_clients = dccp_shutdown_clients,
const struct sender http_sender = {
.name = "http",
.init = http_send_init,
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,
.pre_select = http_pre_select,
.post_select = http_post_select,
.send = http_send,
* the clients aware of the end-of-file condition.
*/
void (*shutdown_clients)(void);
* 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.
*
/**
* Array of function pointers for the sender subcommands.
*
{
PARA_INFO_LOG("shutting down %s on fd %d\n", sc->name, sc->fd);
free(sc->name);
{
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);
cq_destroy(sc->cq);
list_del(&sc->node);
free(sc->private_data);
/** The process id of the audio file selector process. */
pid_t afs_pid = 0;
/** 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. */
/** The task responsible for server command handling. */
struct server_command_task {
/** TCP port on which para_server listens for connections. */
/* become daemon */
if (OPT_GIVEN(DAEMON))
daemon_pipe = daemonize(true /* parent waits for SIGTERM */);
/* become daemon */
if (OPT_GIVEN(DAEMON))
daemon_pipe = daemonize(true /* parent waits for SIGTERM */);
init_random_seed_or_die();
daemon_log_welcome("server");
init_ipc_or_die(); /* init mmd struct and mmd->lock */
init_random_seed_or_die();
daemon_log_welcome("server");
init_ipc_or_die(); /* init mmd struct and mmd->lock */
ret = schedule(&sched);
sched_shutdown(&sched);
signal_shutdown(signal_task);
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));
if (ret < 0)
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
- } else { /* child (command handler) */
- * 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);
* after the select call.
*/
mutex_unlock(mmd_mutex);
close_listed_fds();
ret = handle_connect(sct->child_fd);
}
close_listed_fds();
ret = handle_connect(sct->child_fd);
}
lls_free_parse_result(server_lpr, CMD_PTR);
if (server_lpr != cmdline_lpr)
lls_free_parse_result(cmdline_lpr, CMD_PTR);
lls_free_parse_result(server_lpr, CMD_PTR);
if (server_lpr != cmdline_lpr)
lls_free_parse_result(cmdline_lpr, CMD_PTR);
int handle_connect(int fd);
void parse_config_or_die(bool reload);
char *server_get_tasks(void);
int handle_connect(int fd);
void parse_config_or_die(bool reload);
char *server_get_tasks(void);
+bool process_is_command_handler(void);
PARA_NOTICE_LOG("deleting %s (%s) from list\n", sc->name, msg);
udp_close_target(sc);
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);
vss_del_fec_client(ut->fc);
list_del(&sc->node);
free(sc->name);
+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;
static int udp_resolve_target(const char *url, struct sender_command_data *scd)
{
const char *result;
const struct sender udp_sender = {
.name = "udp",
.init = udp_send_init,
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 = {
.shutdown_clients = udp_shutdown_targets,
.resolve_target = udp_resolve_target,
.client_cmds = {
.context = vsst,
}, 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();
+ }
+}
unsigned int vss_paused(void);
unsigned int vss_stopped(void);
struct timeval *vss_chunk_time(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
/** Stop playing after current audio file. */
#define VSS_NOMORE 1