X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=e8a82b5ed254d447b8edc106e0c6f98d2a64d2f7;hp=bd32ad387fd7ee2d6c9816a4a7603354a572fa1f;hb=00e95557839f3fef5fa06702f3864e8376d2a29b;hpb=823a4ff87a03ff9e1d2bfe8bc501f55ee4213649 diff --git a/audiod.c b/audiod.c index bd32ad38..e8a82b5e 100644 --- a/audiod.c +++ b/audiod.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2014 Andre Noll + * Copyright (C) 2005 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -93,14 +93,10 @@ enum vss_status_flags { */ struct sched sched = {.max_fileno = 0}; -/** - * The task for obtaining para_server's status (para_client stat). - * - * \sa struct task, struct sched. - */ +/* The task for obtaining para_server's status (para_client stat). */ struct status_task { /** The associated task structure of audiod. */ - struct task task; + struct task *task; /** Client data associated with the stat task. */ struct client_task *ct; /** Do not restart client command until this time. */ @@ -168,7 +164,7 @@ struct command_task { /** the local listening socket */ int fd; /** the associated task structure */ - struct task task; + struct task *task; }; /** iterate over all supported audio formats */ @@ -314,17 +310,6 @@ empty: return para_strdup(NULL); } -static int want_colors(void) -{ - if (conf.color_arg == color_arg_no) - return 0; - if (conf.color_arg == color_arg_yes) - return 1; - if (conf.logfile_given) - return 0; - return isatty(STDERR_FILENO); -} - static void parse_config_or_die(void) { int ret; @@ -391,8 +376,10 @@ static void close_receiver(int slot_num) audio_formats[s->format], slot_num); a->receiver->close(s->receiver_node); btr_remove_node(&s->receiver_node->btrn); + task_reap(&s->receiver_node->task); free(s->receiver_node); s->receiver_node = NULL; + stat_task->current_audio_format_num = -1; tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), &a->restart_barrier); } @@ -407,6 +394,7 @@ static void writer_cleanup(struct writer_node *wn) PARA_INFO_LOG("closing %s\n", writer_names[wn->writer_num]); w->close(wn); btr_remove_node(&wn->btrn); + task_reap(&wn->task); } static void close_writers(struct slot_info *s) @@ -444,6 +432,7 @@ static void close_filters(struct slot_info *s) if (f->close) f->close(fn); btr_remove_node(&fn->btrn); + task_reap(&fn->task); } free(s->fns); s->fns = NULL; @@ -459,7 +448,7 @@ static void notify_receivers(int error) continue; if (!s->receiver_node) continue; - task_notify(&s->receiver_node->task, error); + task_notify(s->receiver_node->task, error); } } @@ -497,22 +486,26 @@ static void open_filters(struct slot_info *s) s->fns = para_calloc(nf * sizeof(struct filter_node)); parent = s->receiver_node->btrn; for (i = 0; i < nf; i++) { + char buf[20]; struct filter *f = filters + a->filter_nums[i]; fn = s->fns + i; fn->filter_num = a->filter_nums[i]; fn->conf = a->filter_conf[i]; - fn->task.pre_select = f->pre_select; - fn->task.post_select = f->post_select; fn->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = f->name, .parent = parent, .handler = f->execute, .context = fn)); f->open(fn); - register_task(&sched, &fn->task); + sprintf(buf, "%s (slot %d)", f->name, (int)(s - slot)); + fn->task = task_register(&(struct task_info) { + .name = buf, + .pre_select = f->pre_select, + .post_select = f->post_select, + .context = fn, + }, &sched); parent = fn->btrn; PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n", audio_formats[s->format], i, nf, f->name, (int)(s - slot)); - sprintf(fn->task.status, "%s (slot %d)", f->name, (int)(s - slot)); } } @@ -566,10 +559,12 @@ static int open_receiver(int format) s->receiver_node = rn; PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n", audio_formats[format], r->name, slot_num); - rn->task.pre_select = r->pre_select; - rn->task.post_select = r->post_select; - sprintf(rn->task.status, "%s receiver node", r->name); - register_task(&sched, &rn->task); + rn->task = task_register(&(struct task_info) { + .name = r->name, + .pre_select = r->pre_select, + .post_select = r->post_select, + .context = rn, + }, &sched); return slot_num; } @@ -584,7 +579,7 @@ static bool receiver_running(void) if (!s->receiver_node) continue; - if (s->receiver_node->task.error >= 0) + if (task_status(s->receiver_node->task) >= 0) return true; if (ss1 == ss2) return true; @@ -611,7 +606,7 @@ struct btr_node *audiod_get_btr_root(void) struct timeval rstime; if (!s->receiver_node) continue; - if (s->receiver_node->task.error < 0) + if (task_status(s->receiver_node->task) < 0) continue; btr_get_node_start(s->receiver_node->btrn, &rstime); if (newest_slot >= 0 && tv_diff(&rstime, &newest_rstime, NULL) < 0) @@ -963,8 +958,7 @@ static int parse_stream_args(void) /* does not unlink socket on errors */ static int audiod_get_socket(void) { - struct sockaddr_un unix_addr; - int ret, fd; + int ret; if (conf.socket_given) socket_name = para_strdup(conf.socket_arg); @@ -977,70 +971,67 @@ static int audiod_get_socket(void) PARA_NOTICE_LOG("local socket: %s\n", socket_name); if (conf.force_given) unlink(socket_name); - ret = create_local_socket(socket_name, &unix_addr, + ret = create_local_socket(socket_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH); if (ret < 0) goto err; - fd = ret; - if (listen(fd , 5) < 0) { - ret = -ERRNO_TO_PARA_ERROR(errno); - goto err; - } - ret = mark_fd_nonblocking(fd); - if (ret < 0) - goto err; - return fd; + return ret; err: PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); } -static void signal_pre_select(struct sched *s, struct task *t) +static void signal_pre_select(struct sched *s, void *context) { - struct signal_task *st = container_of(t, struct signal_task, task); + struct signal_task *st = context; para_fd_set(st->fd, &s->rfds, &s->max_fileno); } -static int signal_post_select(struct sched *s, __a_unused struct task *t) +static int signal_post_select(struct sched *s, void *context) { - int signum; + struct signal_task *st = context; + int ret, signum; + ret = task_get_notification(st->task); + if (ret < 0) + return ret; signum = para_next_signal(&s->rfds); switch (signum) { case SIGINT: case SIGTERM: case SIGHUP: PARA_NOTICE_LOG("received signal %d\n", signum); - clean_exit(EXIT_FAILURE, "caught deadly signal"); + task_notify_all(s, E_AUDIOD_SIGNAL); + return -E_AUDIOD_SIGNAL; } return 0; } -static void signal_setup_default(struct signal_task *st) +static void command_pre_select(struct sched *s, void *context) { - st->task.pre_select = signal_pre_select; - st->task.post_select = signal_post_select; - sprintf(st->task.status, "signal task"); -} - -static void command_pre_select(struct sched *s, struct task *t) -{ - struct command_task *ct = container_of(t, struct command_task, task); + struct command_task *ct = context; para_fd_set(ct->fd, &s->rfds, &s->max_fileno); } -static int command_post_select(struct sched *s, struct task *t) +static int command_post_select(struct sched *s, void *context) { int ret; - struct command_task *ct = container_of(t, struct command_task, task); + struct command_task *ct = context; static struct timeval last_status_dump; struct timeval tmp, delay; bool force = true; - ret = handle_connect(ct->fd, &s->rfds); + ret = task_get_notification(ct->task); if (ret < 0) + return ret; + ret = handle_connect(ct->fd, &s->rfds); + if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - else if (ret > 0) + if (ret == -E_AUDIOD_TERM) { + task_notify_all(s, -ret); + return ret; + } + } else if (ret > 0) goto dump; /* if last status dump was less than 500ms ago, do nothing */ @@ -1067,17 +1058,21 @@ dump: static void init_command_task(struct command_task *ct) { - ct->task.pre_select = command_pre_select; - ct->task.post_select = command_post_select; - ct->task.error = 0; ct->fd = audiod_get_socket(); /* doesn't return on errors */ - sprintf(ct->task.status, "command task"); + + ct->task = task_register(&(struct task_info) { + .name = "command", + .pre_select = command_pre_select, + .post_select = command_post_select, + .context = ct, + }, &sched); } static void close_stat_pipe(void) { if (!stat_task->ct) return; + task_reap(&stat_task->ct->task); client_close(stat_task->ct); stat_task->ct = NULL; clear_and_dump_items(); @@ -1103,17 +1098,17 @@ static bool must_close_slot(int slot_num) if (s->format < 0) return false; - if (s->receiver_node && s->receiver_node->task.error >= 0) + if (s->receiver_node && task_status(s->receiver_node->task) >= 0) return false; for (i = 0; i < a->num_filters; i++) - if (s->fns && s->fns[i].task.error >= 0) + if (s->fns && task_status(s->fns[i].task) >= 0) return false; if (a->num_writers > 0) { for (i = 0; i < a->num_writers; i++) - if (s->wns && s->wns[i].task.error >= 0) + if (s->wns && task_status(s->wns[i].task) >= 0) return false; } else { - if (s->wns && s->wns[0].task.error >= 0) + if (s->wns && task_status(s->wns[0].task) >= 0) return false; } return true; @@ -1139,19 +1134,13 @@ static void close_unused_slots(void) close_slot(i); } -/** - * Close the connection to para_server and exit. - * - * \param status The exit status which is passed to exit(3). - * \param msg The log message - * - * Log \a msg with loglevel \p EMERG, close the connection to para_server and - * all slots, and call \p exit(status). \a status should be either EXIT_SUCCESS - * or EXIT_FAILURE. +/* + * Cleanup all resources. * - * \sa exit(3). + * This performs various cleanups, removes the audiod socket and closes the + * connection to para_server. */ -void __noreturn clean_exit(int status, const char *msg) +static void audiod_cleanup(void) { if (socket_name) unlink(socket_name); @@ -1159,8 +1148,6 @@ void __noreturn clean_exit(int status, const char *msg) close_unused_slots(); audiod_cmdline_parser_free(&conf); close_stat_clients(); - PARA_EMERG_LOG("%s\n", msg); - exit(status); } /* @@ -1171,7 +1158,6 @@ static void start_stop_decoders(void) { int ret; struct slot_info *sl; - struct audio_format_info *a; close_unused_slots(); if (audiod_status != AUDIOD_ON || @@ -1185,17 +1171,15 @@ static void start_stop_decoders(void) return; } sl = slot + ret; - a = afi + sl->format; - if (a->num_filters) - open_filters(sl); + open_filters(sl); open_writers(sl); activate_grab_clients(&sched); btr_log_tree(sl->receiver_node->btrn, LL_NOTICE); } -static void status_pre_select(struct sched *s, struct task *t) +static void status_pre_select(struct sched *s, void *context) { - struct status_task *st = container_of(t, struct status_task, task); + struct status_task *st = context; int i, ret, cafn = stat_task->current_audio_format_num; if (must_start_decoder()) @@ -1225,15 +1209,19 @@ min_delay: } /* restart the client task if necessary */ -static int status_post_select(struct sched *s, struct task *t) +static int status_post_select(struct sched *s, void *context) { - struct status_task *st = container_of(t, struct status_task, task); + struct status_task *st = context; + int ret; + ret = task_get_notification(st->task); + if (ret < 0) + return ret; if (audiod_status == AUDIOD_OFF) { if (!st->ct) goto out; - if (st->ct->task.error >= 0) { - task_notify(&st->ct->task, E_AUDIOD_OFF); + if (task_status(st->ct->task) >= 0) { + task_notify(st->ct->task, E_AUDIOD_OFF); goto out; } close_stat_pipe(); @@ -1243,7 +1231,6 @@ static int status_post_select(struct sched *s, struct task *t) if (st->ct) { char *buf; size_t sz; - int ret; ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF); if (ret < 0) { @@ -1256,14 +1243,14 @@ static int status_post_select(struct sched *s, struct task *t) struct timeval diff; tv_diff(now, &st->last_status_read, &diff); if (diff.tv_sec > 61) - task_notify(&st->ct->task, E_STATUS_TIMEOUT); + task_notify(st->ct->task, E_STATUS_TIMEOUT); goto out; } btr_merge(st->btrn, st->min_iqs); sz = btr_next_buffer(st->btrn, &buf); ret = for_each_stat_item(buf, sz, update_item); if (ret < 0) { - task_notify(&st->ct->task, -ret); + task_notify(st->ct->task, -ret); goto out; } if (sz != ret) { @@ -1305,14 +1292,18 @@ out: static void init_status_task(struct status_task *st) { memset(st, 0, sizeof(struct status_task)); - st->task.pre_select = status_pre_select; - st->task.post_select = status_post_select; st->sa_time_diff_sign = 1; st->clock_diff_count = conf.clock_diff_count_arg; st->current_audio_format_num = -1; - sprintf(st->task.status, "stat"); st->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stat")); + + stat_task->task = task_register(&(struct task_info) { + .name = "stat", + .pre_select = status_pre_select, + .post_select = status_post_select, + .context = stat_task, + }, &sched); } static void set_initial_status(void) @@ -1348,18 +1339,6 @@ __noreturn static void print_help_and_die(void) exit(0); } -static void init_colors_or_die(void) -{ - int i; - - if (!want_colors()) - return; - daemon_set_default_log_colors(); - daemon_set_flag(DF_COLOR_LOG); - for (i = 0; i < conf.log_color_given; i++) - daemon_set_log_color_or_die(conf.log_color_arg[i]); -} - /** * the main function of para_audiod * @@ -1394,7 +1373,8 @@ int main(int argc, char *argv[]) print_help_and_die(); daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg); parse_config_or_die(); - init_colors_or_die(); + daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no, + conf.logfile_given, conf.log_color_arg, conf.log_color_given); init_random_seed_or_die(); daemon_set_flag(DF_LOG_TIME); daemon_set_flag(DF_LOG_HOSTNAME); @@ -1416,7 +1396,6 @@ int main(int argc, char *argv[]) FOR_EACH_SLOT(i) clear_slot(i); setup_signal_handling(); - signal_setup_default(sig_task); init_status_task(stat_task); init_command_task(cmd_task); @@ -1424,13 +1403,20 @@ int main(int argc, char *argv[]) if (conf.daemon_given) daemonize(false /* parent exits immediately */); - register_task(&sched, &sig_task->task); - register_task(&sched, &cmd_task->task); - register_task(&sched, &stat_task->task); + sig_task->task = task_register(&(struct task_info) { + .name = "signal", + .pre_select = signal_pre_select, + .post_select = signal_post_select, + .context = sig_task, + }, &sched); + sched.default_timeout.tv_sec = 2; sched.default_timeout.tv_usec = 999 * 1000; ret = schedule(&sched); + audiod_cleanup(); + sched_shutdown(&sched); - PARA_EMERG_LOG("%s\n", para_strerror(-ret)); - return EXIT_FAILURE; + if (ret < 0) + PARA_EMERG_LOG("%s\n", para_strerror(-ret)); + return ret < 0? EXIT_FAILURE : EXIT_SUCCESS; }