X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=server.c;h=f19fc996ecc7355ddf24379e242fcec4da287dd6;hp=4f1d5708f76e997ff8fc5ee477dd97d65a6b3785;hb=e2167286448ce2ed9a01a548e7e9832563035088;hpb=17c140cc24838c2b7049e2b4c17621f4284d53dc diff --git a/server.c b/server.c index 4f1d5708..f19fc996 100644 --- a/server.c +++ b/server.c @@ -45,6 +45,7 @@ #include "afh.h" #include "string.h" #include "afs.h" +#include "net.h" #include "server.h" #include "list.h" #include "send.h" @@ -52,7 +53,6 @@ #include "vss.h" #include "config.h" #include "close_on_fork.h" -#include "net.h" #include "daemon.h" #include "ipc.h" #include "fd.h" @@ -100,12 +100,33 @@ uint32_t afs_socket_cookie; /** The mutex protecting the shared memory area containing the mmd struct. */ int mmd_mutex; +/* Serializes log output. */ +static int log_mutex; + static struct sched sched; 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. */ @@ -133,9 +154,17 @@ char *server_get_tasks(void) return get_task_list(&sched); } -/* - * setup shared memory area and get mutex for locking - */ +static void pre_log_hook(void) +{ + mutex_lock(log_mutex); +} + +static void post_log_hook(void) +{ + mutex_unlock(log_mutex); +} + +/* Setup shared memory area and init mutexes */ static void init_ipc_or_die(void) { void *shm; @@ -154,6 +183,10 @@ static void init_ipc_or_die(void) if (ret < 0) goto err_out; mmd_mutex = ret; + ret = mutex_new(); + if (ret < 0) + goto destroy_mmd_mutex; + log_mutex = ret; mmd->num_played = 0; mmd->num_commands = 0; @@ -163,6 +196,8 @@ static void init_ipc_or_die(void) mmd->vss_status_flags = VSS_NEXT; mmd->new_vss_status_flags = VSS_NEXT; return; +destroy_mmd_mutex: + mutex_destroy(mmd_mutex); err_out: PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); @@ -248,7 +283,7 @@ success: daemon_set_flag(DF_LOG_TIMING); daemon_set_priority(OPT_UINT32_VAL(PRIORITY)); if (user_list_file) - init_user_list(user_list_file); + user_list_init(user_list_file); ret = 1; free_cf: free(cf); @@ -307,27 +342,22 @@ static int signal_post_select(struct sched *s, __a_unused void *context) PARA_EMERG_LOG("terminating on signal %d\n", signum); kill(0, SIGTERM); /* - * We must wait for afs because afs catches SIGINT/SIGTERM. - * Before reacting to the signal, afs might want to use the + * We must wait for all of our children to die. For the afs + * process or a command handler might want to use the * shared memory area and the mmd mutex. If we destroy this * mutex too early and afs tries to lock the shared memory * area, the call to mutex_lock() will fail and terminate the * afs process. This leads to dirty osl tables. - * - * There's no such problem with the other children of the - * server process (the command handlers) as these reset their - * SIGINT/SIGTERM handlers to the default action, i.e. these - * processes get killed immediately by the above kill(). */ - PARA_INFO_LOG("waiting for afs (pid %d) to die\n", - (int)afs_pid); - waitpid(afs_pid, NULL, 0); + PARA_INFO_LOG("waiting for child processes to die\n"); + mutex_unlock(mmd_mutex); + while (wait(NULL) != -1 || errno != ECHILD) + ; /* still at least one child alive */ + mutex_lock(mmd_mutex); cleanup: free(mmd->afd.afhi.chunk_table); - close_listed_fds(); - mutex_destroy(mmd_mutex); - shm_detach(mmd); - exit(EXIT_FAILURE); + task_notify_all(s, E_DEADLY_SIGNAL); + return -E_DEADLY_SIGNAL; } return 0; } @@ -475,6 +505,8 @@ static int init_afs(int argc, char **argv) int i; afs_pid = getpid(); + crypt_shutdown(); + user_list_deplete(); for (i = argc - 1; i >= 0; i--) memset(argv[i], 0, strlen(argv[i])); i = argc - lls_num_inputs(cmdline_lpr) - 1; @@ -532,10 +564,12 @@ 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 */); - init_random_seed_or_die(); + server_pid = getpid(); + crypt_init(); daemon_log_welcome("server"); - init_ipc_or_die(); /* init mmd struct and mmd->lock */ + init_ipc_or_die(); /* init mmd struct, mmd and log mutex */ daemon_set_start_time(); + daemon_set_hooks(pre_log_hook, post_log_hook); PARA_NOTICE_LOG("initializing audio format handlers\n"); afh_init(); @@ -610,6 +644,21 @@ static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds, return ret; } +/** + * Deallocate all lopsub parse results. + * + * The server allocates a parse result for command line options and optionally + * a second parse result for the effective configuration, defined by merging + * the command line options with the options stored in the configuration file. + * This function frees both structures. + */ +void free_lpr(void) +{ + lls_free_parse_result(server_lpr, CMD_PTR); + if (server_lpr != cmdline_lpr) + lls_free_parse_result(cmdline_lpr, CMD_PTR); +} + /** * The main function of para_server. * @@ -630,23 +679,29 @@ int main(int argc, char *argv[]) server_init(argc, argv, sct); mutex_lock(mmd_mutex); ret = schedule(&sched); + /* + * We hold the mmd lock: it was re-acquired in server_select() + * after the select call. + */ + mutex_unlock(mmd_mutex); sched_shutdown(&sched); + crypt_shutdown(); signal_shutdown(signal_task); - if (sct->child_fd < 0) { /* parent (server) */ + if (!process_is_command_handler()) { /* parent (server) */ + mutex_destroy(mmd_mutex); + daemon_set_hooks(NULL, NULL); /* only one process remaining */ + mutex_destroy(log_mutex); + deplete_close_on_fork_list(); 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() - * after the select call. - */ - mutex_unlock(mmd_mutex); + } else { alarm(ALARM_TIMEOUT); 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); + vss_shutdown(); + shm_detach(mmd); + user_list_deplete(); + free_lpr(); exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS); }