}
PARA_EMERG_LOG("terminating on signal %d\n", signum);
shutdown:
- sched_shutdown();
+ sched_shutdown(s);
t->error = -E_AFS_SIGNAL;
}
-static void register_signal_task(void)
+static void register_signal_task(struct sched *s)
{
struct signal_task *st = &signal_task_struct;
st->task.pre_select = signal_pre_select;
st->task.post_select = afs_signal_post_select;
sprintf(st->task.status, "signal task");
- register_task(&st->task);
+ register_task(s, &st->task);
}
static struct list_head afs_client_list;
ret = execute_server_command(&s->rfds);
if (ret < 0) {
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
- sched_shutdown();
+ sched_shutdown(s);
return;
}
/* Check the list of connected clients. */
para_list_add(&client->node, &afs_client_list);
}
-static void register_command_task(uint32_t cookie)
+static void register_command_task(uint32_t cookie, struct sched *s)
{
struct command_task *ct = &command_task_struct;
ct->fd = setup_command_socket_or_die();
ct->task.pre_select = command_pre_select;
ct->task.post_select = command_post_select;
sprintf(ct->task.status, "afs command task");
- register_task(&ct->task);
+ register_task(s, &ct->task);
}
/**
static struct sched s;
int i, ret;
- register_signal_task();
+ register_signal_task(&s);
INIT_LIST_HEAD(&afs_client_list);
for (i = 0; i < NUM_AFS_TABLES; i++)
afs_tables[i].init(&afs_tables[i]);
PARA_INFO_LOG("server_socket: %d, afs_socket_cookie: %u\n",
server_socket, (unsigned) cookie);
init_admissible_files(conf.afs_initial_mode_arg);
- register_command_task(cookie);
+ register_command_task(cookie, &s);
s.default_timeout.tv_sec = 0;
s.default_timeout.tv_usec = 999 * 1000;
ret = schedule(&s);
VSS_STATUS_FLAG_PLAYING = 2,
};
+struct sched sched = {.max_fileno = 0};
+
/**
* The task for obtaining para_server's status (para_client stat).
*
.handler = f->execute, .context = fn));
f->open(fn);
- register_task(&fn->task);
+ register_task(&sched, &fn->task);
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));
wn = s->wns + i;
wn->conf = a->writer_conf[i];
wn->writer_num = a->writer_nums[i];
- register_writer_node(wn, parent);
+ register_writer_node(wn, parent, &sched);
}
}
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(&rn->task);
+ register_task(&sched, &rn->task);
return slot_num;
}
if (a->num_filters)
open_filters(sl);
open_writers(sl);
- activate_grab_clients();
+ activate_grab_clients(&sched);
btr_log_tree(sl->receiver_node->btrn, LL_NOTICE);
}
}
/* restart the client task if necessary */
-static void status_post_select(__a_unused struct sched *s, struct task *t)
+static void status_post_select(struct sched *s, struct task *t)
{
struct status_task *st = container_of(t, struct status_task, task);
int argc = 5;
PARA_INFO_LOG("clock diff count: %d\n", st->clock_diff_count);
st->clock_diff_count--;
- client_open(argc, argv, &st->ct, NULL, NULL, st->btrn);
+ client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
set_stat_task_restart_barrier(2);
} else {
char *argv[] = {"audiod", "--", "stat", "-p", NULL};
int argc = 4;
- client_open(argc, argv, &st->ct, NULL, NULL, st->btrn);
+ client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s);
set_stat_task_restart_barrier(5);
}
free(stat_item_values[SI_BASENAME]);
int main(int argc, char *argv[])
{
int ret, i;
- static struct sched s;
struct command_task command_task_struct, *cmd_task = &command_task_struct;
struct audiod_cmdline_parser_params params = {
.override = 0,
if (conf.daemon_given)
daemonize(false /* parent exits immediately */);
- register_task(&sig_task->task);
- register_task(&cmd_task->task);
- register_task(&stat_task->task);
- s.default_timeout.tv_sec = 2;
- s.default_timeout.tv_usec = 999 * 1000;
- ret = schedule(&s);
+ register_task(&sched, &sig_task->task);
+ register_task(&sched, &cmd_task->task);
+ register_task(&sched, &stat_task->task);
+ sched.default_timeout.tv_sec = 2;
+ sched.default_timeout.tv_usec = 999 * 1000;
+ ret = schedule(&sched);
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
return EXIT_FAILURE;
#include "fd.h"
#include "audiod_command_list.h"
+extern struct sched sched;
extern char *stat_item_values[NUM_STAT_ITEMS];
/** Iterate over the array of all audiod commands. */
int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
{
- char *tl = get_task_list();
+ char *tl = get_task_list(&sched);
int ret = 1;
if (tl)
ret = client_write(fd, tl);
int com_grab(int fd, int argc, char **argv)
{
- return grab_client_new(fd, argc, argv);
+ return grab_client_new(fd, argc, argv, &sched);
}
__noreturn int com_term(int fd, __a_unused int argc, __a_unused char **argv)
INIT_CLIENT_ERRLISTS;
+static struct sched sched;
static struct client_task *ct;
static struct stdin_task sit;
static struct stdout_task sot;
-static void supervisor_post_select(__a_unused struct sched *s, struct task *t)
+static void supervisor_post_select(struct sched *s, struct task *t)
{
if (ct->task.error < 0) {
t->error = ct->task.error;
}
if (ct->status == CL_SENDING) {
stdin_set_defaults(&sit);
- register_task(&sit.task);
+ register_task(s, &sit.task);
t->error = -E_TASK_STARTED;
return;
}
if (ct->status == CL_RECEIVING) {
stdout_set_defaults(&sot);
- register_task(&sot.task);
+ register_task(s, &sot.task);
t->error = -E_TASK_STARTED;
return;
}
init_random_seed_or_die();
s.default_timeout.tv_sec = 1;
s.default_timeout.tv_usec = 0;
+
/*
* We add buffer tree nodes for stdin and stdout even though
* only one of them will be needed. This simplifies the code
*/
sit.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdin"));
- ret = client_open(argc, argv, &ct, &client_loglevel, sit.btrn, NULL);
+ ret = client_open(argc, argv, &ct, &client_loglevel, sit.btrn, NULL, &sched);
if (ret < 0)
goto out;
sot.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdout", .parent = ct->btrn));
- register_task(&svt);
- ret = schedule(&s);
+ register_task(&sched, &svt);
+ ret = schedule(&sched);
out:
client_close(ct);
btr_free_node(sit.btrn);
void client_close(struct client_task *ct);
int client_open(int argc, char *argv[], struct client_task **ct_ptr,
- int *loglevel, struct btr_node *parent, struct btr_node *child);
+ int *loglevel, struct btr_node *parent, struct btr_node *child,
+ struct sched *sched);
}
/* connect to para_server and register the client task */
-static int client_connect(struct client_task *ct)
+static int client_connect(struct sched *s, struct client_task *ct)
{
int ret;
ct->task.pre_select = client_pre_select;
ct->task.post_select = client_post_select;
sprintf(ct->task.status, "client");
- register_task(&ct->task);
+ register_task(s, &ct->task);
return 1;
err_out:
close(ct->scc.fd);
* \param loglevel If not \p NULL, the number of the loglevel is stored here.
* \param parent Add the new buffer tree node as a child of this node.
* \param child Add the new buffer tree node as a parent of this node.
+ * \param sched The scheduler instance to register the task to.
*
* Check the command line options given by \a argc and argv, set default values
* for user name and rsa key file, read further option from the config file.
* \return Standard.
*/
int client_open(int argc, char *argv[], struct client_task **ct_ptr,
- int *loglevel, struct btr_node *parent, struct btr_node *child)
+ int *loglevel, struct btr_node *parent, struct btr_node *child,
+ struct sched *sched)
{
char *home = para_homedir();
int ret;
PARA_INFO_LOG("key_file: %s\n", ct->key_file);
PARA_NOTICE_LOG("connecting %s:%d\n", ct->conf.hostname_arg,
ct->conf.server_port_arg);
- ret = client_connect(ct);
+ ret = client_connect(sched, ct);
out:
free(home);
if (ret < 0) {
#include "server.h"
#include "list.h"
#include "send.h"
+#include "sched.h"
#include "vss.h"
#include "net.h"
#include "daemon.h"
#include "user_list.h"
#include "server_command_list.h"
#include "afs_command_list.h"
-#include "sched.h"
#include "signal.h"
#include "version.h"
#include "net.h"
#include "list.h"
#include "send.h"
+#include "sched.h"
#include "vss.h"
#include "fd.h"
#include "close_on_fork.h"
sit->btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdin"));
stdin_set_defaults(sit);
- register_task(&sit->task);
+ register_task(&s, &sit->task);
fns = para_malloc(conf.filter_given * sizeof(*fns));
for (i = 0, parent = sit->btrn; i < conf.filter_given; i++) {
fn->task.pre_select = f->pre_select;
fn->task.post_select = f->post_select;
f->open(fn);
- register_task(&fn->task);
+ register_task(&s, &fn->task);
parent = fn->btrn;
}
sot->btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdout", .parent = parent));
stdout_set_defaults(sot);
- register_task(&sot->task);
+ register_task(&s, &sot->task);
s.default_timeout.tv_sec = 1;
s.default_timeout.tv_usec = 0;
*
* \param gc The grab client to activate.
*/
-static void gc_activate(struct grab_client *gc)
+static void gc_activate(struct grab_client *gc, struct sched *s)
{
struct btr_node *root = audiod_get_btr_root(), *parent;
char *name = gc->name? gc->name : "grab";
snprintf(gc->task.status, sizeof(gc->task.status) - 1, "%s", name);
gc->task.status[sizeof(gc->task.status) - 1] = '\0';
gc->task.error = 0;
- register_task(&gc->task);
+ register_task(s, &gc->task);
}
/**
* This function also garbage collects all grab clients whose tasks have been
* unscheduled.
*/
-void activate_grab_clients(void)
+void activate_grab_clients(struct sched *s)
{
struct grab_client *gc, *tmp;
free(gc);
continue;
}
- gc_activate(gc);
+ gc_activate(gc, s);
}
}
* \param fd The file descriptor of the client.
* \param argc Argument count.
* \param argv Argument vector.
+ * \param s The scheduler to register the grab client task to.
*
* If the command line options given by \a argc and \a argv are valid.
* allocate a struct grab_client and initialize it with this valid
*
* \return Standard.
*/
-int grab_client_new(int fd, int argc, char **argv)
+int grab_client_new(int fd, int argc, char **argv, struct sched *s)
{
int ret;
struct grab_client *gc = para_calloc(sizeof(struct grab_client));
goto err_out;
gc->fd = fd;
para_list_add(&gc->node, &inactive_grab_client_list);
- gc_activate(gc);
+ gc_activate(gc, s);
return 1;
err_out:
free(gc);
/** \file grab_client.h exported symbols from grab_client.c */
-int grab_client_new(int fd, int argc, char **argv);
-void activate_grab_clients(void);
+int grab_client_new(int fd, int argc, char **argv, struct sched *s);
+void activate_grab_clients(struct sched *s);
#include "http.h"
#include "list.h"
#include "send.h"
+#include "sched.h"
#include "vss.h"
#include "close_on_fork.h"
#include "net.h"
sot.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.parent = rn.btrn, .name = "stdout"));
stdout_set_defaults(&sot);
- register_task(&sot.task);
+ register_task(&s, &sot.task);
rn.task.pre_select = r->pre_select;
rn.task.post_select = r->post_select;
sprintf(rn.task.status, "%s", r->name);
- register_task(&rn.task);
+ register_task(&s, &rn.task);
ret = schedule(&s);
out:
#include "time.h"
#include "error.h"
-static struct list_head pre_select_list, post_select_list;
-static int initialized;
-
static struct timeval now_struct;
struct timeval *now = &now_struct;
*/
static void unregister_task(struct task *t)
{
- if (!initialized)
- return;
assert(t->error < 0);
PARA_INFO_LOG("unregistering %s (%s)\n", t->status,
para_strerror(-t->error));
static void sched_preselect(struct sched *s)
{
struct task *t, *tmp;
- list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) {
if (t->error < 0) {
unregister_task(t);
continue;
{
struct task *t, *tmp;
- list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->post_select_list, post_select_node) {
if (t->error >= 0)
call_post_select(s, t);
// PARA_INFO_LOG("%s: %d\n", t->status, t->ret);
* this case t has been unregistered already, so we must not
* unregister it again.
*/
- if (list_empty(&post_select_list))
+ if (list_empty(&s->post_select_list))
return;
unregister_task(t);
}
{
int ret;
- if (!initialized)
- return -E_NOT_INITIALIZED;
if (!s->select_function)
s->select_function = para_select;
again:
s->max_fileno = -1;
gettimeofday(now, NULL);
sched_preselect(s);
- if (list_empty(&pre_select_list) && list_empty(&post_select_list))
+ if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list))
return 0;
if (!timeout_is_zero(s)) {
ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds,
FD_ZERO(&s->wfds);
}
sched_post_select(s);
- if (list_empty(&pre_select_list) && list_empty(&post_select_list))
+ if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list))
return 0;
goto again;
}
-/*
- * Initialize the paraslash scheduler.
- */
-static void init_sched(void)
-{
- PARA_INFO_LOG("initializing scheduler\n");
- INIT_LIST_HEAD(&pre_select_list);
- INIT_LIST_HEAD(&post_select_list);
- initialized = 1;
-}
-
/**
* Add a task to the scheduler.
*
- * \param t the task to add
+ * \param t The task to add.
+ * \param s The scheduler instance to add the task to.
*
* If the pre_select pointer of \a t is not \p NULL, it is added to
* the pre_select list of the scheduler. Same goes for post_select.
*
* \sa task::pre_select, task::post_select
*/
-void register_task(struct task *t)
+void register_task(struct sched *s, struct task *t)
{
- if (!initialized)
- init_sched();
PARA_INFO_LOG("registering %s (%p)\n", t->status, t);
+ if (!s->pre_select_list.next)
+ INIT_LIST_HEAD(&s->pre_select_list);
+ if (!s->post_select_list.next)
+ INIT_LIST_HEAD(&s->post_select_list);
if (t->pre_select) {
PARA_DEBUG_LOG("pre_select: %p\n", &t->pre_select);
- list_add_tail(&t->pre_select_node, &pre_select_list);
+ list_add_tail(&t->pre_select_node, &s->pre_select_list);
}
if (t->post_select) {
PARA_DEBUG_LOG("post_select: %p\n", &t->post_select);
- list_add_tail(&t->post_select_node, &post_select_list);
+ list_add_tail(&t->post_select_node, &s->post_select_list);
}
}
* \a pre_select_list and the \a post_select_list are empty. This function
* must be called from the post_select (rather than the pre_select) method.
*/
-void sched_shutdown(void)
+void sched_shutdown(struct sched *s)
{
struct task *t, *tmp;
- if (!initialized)
- return;
- list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) {
t->error = -E_SCHED_SHUTDOWN;
unregister_task(t);
}
- list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->post_select_list, post_select_node) {
t->error = -E_SCHED_SHUTDOWN;
unregister_task(t);
}
- initialized = 0;
}
/**
* Each entry of the list contains an identifier which is simply a hex number.
* The result is dynamically allocated and must be freed by the caller.
*/
-char *get_task_list(void)
+char *get_task_list(struct sched *s)
{
struct task *t, *tmp;
char *msg = NULL;
- if (!initialized)
- return NULL;
- list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) {
char *tmp_msg;
tmp_msg = make_message("%s%p\tpre\t%s\n", msg? msg : "", t, t->status);
free(msg);
msg = tmp_msg;
}
- list_for_each_entry_safe(t, tmp, &post_select_list, post_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->post_select_list, post_select_node) {
char *tmp_msg;
// if (t->pre_select)
// continue;
int max_fileno;
/** If non-NULL, use this function instead of para_select. */
int (*select_function)(int, fd_set *, fd_set *, struct timeval *);
+ /** Currently active pre_select functions. */
+ struct list_head pre_select_list;
+ /** Currently active post_select functions. */
+ struct list_head post_select_list;
};
/**
*/
extern struct timeval *now;
-void register_task(struct task *t);
+void register_task(struct sched *s, struct task *t);
int schedule(struct sched *s);
-char *get_task_list(void);
-void sched_shutdown(void);
+char *get_task_list(struct sched *s);
+void sched_shutdown(struct sched *s);
void sched_min_delay(struct sched *s);
void sched_request_timeout(struct timeval *to, struct sched *s);
void sched_request_timeout_ms(long unsigned ms, struct sched *s);
#include "send.h"
#include "close_on_fork.h"
#include "chunk_queue.h"
+#include "sched.h"
#include "vss.h"
/** Clients will be kicked if there are more than that many bytes pending. */
#include "server.h"
#include "list.h"
#include "send.h"
+#include "sched.h"
#include "vss.h"
#include "config.h"
#include "close_on_fork.h"
#include "daemon.h"
#include "ipc.h"
#include "fd.h"
-#include "sched.h"
#include "signal.h"
#include "user_list.h"
#include "color.h"
/** The file containing user information (public key, permissions). */
static char *user_list_file = NULL;
+static struct sched sched;
/** The task responsible for server command handling. */
struct server_command_task {
para_install_sighandler(SIGCHLD);
para_sigaction(SIGPIPE, SIG_IGN);
add_close_on_fork_list(st->fd);
- register_task(&st->task);
+ register_task(&sched, &st->task);
}
static void command_pre_select(struct sched *s, struct task *t)
goto err;
add_close_on_fork_list(sct->listen_fd); /* child doesn't need the listener */
sprintf(sct->task.status, "server command task");
- register_task(&sct->task);
+ register_task(&sched, &sct->task);
return;
err:
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
init_signal_task();
para_unblock_signal(SIGCHLD);
PARA_NOTICE_LOG("initializing virtual streaming system\n");
- init_vss_task(afs_socket);
+ init_vss_task(afs_socket, &sched);
init_server_command_task(argc, argv);
if (conf.daemon_given)
kill(getppid(), SIGTERM);
int main(int argc, char *argv[])
{
int ret;
- static struct sched s = {
- .default_timeout = {
- .tv_sec = 1,
- .tv_usec = 0
- },
- .select_function = server_select
- };
+
+ sched.default_timeout.tv_sec = 1;
+ sched.select_function = server_select;
+
server_init(argc, argv);
mutex_lock(mmd_mutex);
- ret = schedule(&s);
+ ret = schedule(&sched);
if (ret < 0) {
PARA_EMERG_LOG("%s\n", para_strerror(-ret));
exit(EXIT_FAILURE);
#include "server.h"
#include "list.h"
#include "send.h"
+#include "sched.h"
#include "vss.h"
#include "portable_io.h"
#include "net.h"
#include "fd.h"
-#include "sched.h"
#include "close_on_fork.h"
/**
#include "server.cmdline.h"
#include "list.h"
#include "send.h"
+#include "sched.h"
#include "vss.h"
#include "ipc.h"
#include "fd.h"
-#include "sched.h"
extern struct misc_meta_data *mmd;
* Initialize the virtual streaming system task.
*
* \param afs_socket The fd for communication with afs.
+ * \param s The scheduler to register the vss task to.
*
* This also initializes all supported senders and starts streaming
* if the --autoplay command line flag was given.
*/
-void init_vss_task(int afs_socket)
+void init_vss_task(int afs_socket, struct sched *s)
{
static struct vss_task vss_task_struct, *vsst = &vss_task_struct;
int i;
&vsst->data_send_barrier);
}
sprintf(vsst->task.status, "vss task");
- register_task(&vsst->task);
+ register_task(s, &vsst->task);
}
/** \file vss.h Exported functions from vss.c (para_server). */
-void init_vss_task(int afs_socket);
+void init_vss_task(int afs_socket, struct sched *s);
unsigned int vss_playing(void);
unsigned int vss_next(void);
unsigned int vss_repos(void);
* \return Standard.
*/
static void setup_writer_node(const char *arg, struct btr_node *parent,
- struct writer_node *wn)
+ struct writer_node *wn, struct sched *s)
{
if (arg)
wn->conf = check_writer_arg_or_die(arg, &wn->writer_num);
wn->writer_num = DEFAULT_WRITER;
wn->conf = writers[DEFAULT_WRITER].parse_config_or_die("");
}
- register_writer_node(wn, parent);
+ register_writer_node(wn, parent, s);
}
static int setup_and_schedule(void)
sit.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdin"));
stdin_set_defaults(&sit);
- register_task(&sit.task);
+ register_task(&s, &sit.task);
cwt->state = CWS_NEED_HEADER;
cwt->min_iqs = WAV_HEADER_LEN;
cwt->task.pre_select = check_wav_pre_select;
cwt->task.post_select = check_wav_post_select;
cwt->task.error = 0;
- register_task(&cwt->task);
+ register_task(&s, &cwt->task);
if (!conf.writer_given) {
wns = para_calloc(sizeof(*wns));
- setup_writer_node(NULL, cwt->btrn, wns);
+ setup_writer_node(NULL, cwt->btrn, wns, &s);
i = 1;
} else {
wns = para_calloc(conf.writer_given * sizeof(*wns));
for (i = 0; i < conf.writer_given; i++)
setup_writer_node(conf.writer_arg[i], cwt->btrn,
- wns + i);
+ wns + i, &s);
}
s.default_timeout.tv_sec = 10;
*
* \param wn The writer node to open.
* \param parent The parent btr node (the source for the writer node).
+ * \param s The scheduler instance to register the task to.
*
* The configuration of the writer node stored in \p wn->conf must be
* initialized before this function may be called.
*/
-void register_writer_node(struct writer_node *wn, struct btr_node *parent)
+void register_writer_node(struct writer_node *wn, struct btr_node *parent,
+ struct sched *s)
{
struct writer *w = writers + wn->writer_num;
char *name = make_message("%s writer", writer_names[wn->writer_num]);
free(name);
wn->task.post_select = w->post_select;
wn->task.pre_select = w->pre_select;
- register_task(&wn->task);
+ register_task(s, &wn->task);
}
/**
void writer_init(void);
void *check_writer_arg_or_die(const char *wa, int *writer_num);
void print_writer_helps(int detailed);
-void register_writer_node(struct writer_node *wn, struct btr_node *parent);
+void register_writer_node(struct writer_node *wn, struct btr_node *parent,
+ struct sched *s);
void get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
void get_btr_channels(struct btr_node *btrn, int32_t *result);
void get_btr_sample_format(struct btr_node *btrn, int32_t *result);