sched: Allow more than one running scheduler instance.
authorAndre Noll <maan@systemlinux.org>
Fri, 2 Sep 2011 16:27:29 +0000 (18:27 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 20 Nov 2011 14:08:41 +0000 (15:08 +0100)
The interactive completion code must be able to run a second,
independent scheduler instance for generating the possible completions.
This is currently not possible because the pre_select and post_select
list heads of the scheduler are defined globally in sched.c.

This patch moves these list heads from sched.c to struct sched. This
leaves only the global "now" variable in sched.c, but it is OK to
update this from all scheduler instances, so it can stay.

Moving the two list heads to struct sched requires that several
public functions, among them register_task(), grow an additional
parameter. The (mostly trivial) changes that update all callers to
provide the new argument make the patch rather invasive, unfortunately.

23 files changed:
afs.c
audiod.c
audiod_command.c
client.c
client.h
client_common.c
command.c
dccp_send.c
filter.c
grab_client.c
grab_client.h
http_send.c
recv.c
sched.c
sched.h
send_common.c
server.c
udp_send.c
vss.c
vss.h
write.c
write_common.c
write_common.h

diff --git a/afs.c b/afs.c
index 3f37805..b4c85dc 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -727,11 +727,11 @@ static void afs_signal_post_select(struct sched *s, struct task *t)
        }
        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;
 
@@ -745,7 +745,7 @@ static void register_signal_task(void)
        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;
@@ -906,7 +906,7 @@ static void command_post_select(struct sched *s, struct task *t)
        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. */
@@ -941,7 +941,7 @@ static void command_post_select(struct sched *s, struct task *t)
        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();
@@ -950,7 +950,7 @@ static void register_command_task(uint32_t cookie)
        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);
 }
 
 /**
@@ -964,7 +964,7 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd)
        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]);
@@ -978,7 +978,7 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd)
        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);
index 7085ef0..2957872 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -78,6 +78,8 @@ enum vss_status_flags {
        VSS_STATUS_FLAG_PLAYING = 2,
 };
 
+struct sched sched = {.max_fileno = 0};
+
 /**
  * The task for obtaining para_server's status (para_client stat).
  *
@@ -505,7 +507,7 @@ static void open_filters(struct slot_info *s)
                                .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));
@@ -528,7 +530,7 @@ static void open_writers(struct slot_info *s)
                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);
        }
 }
 
@@ -565,7 +567,7 @@ static int open_receiver(int format)
        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;
 }
 
@@ -1147,7 +1149,7 @@ static void start_stop_decoders(void)
        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);
 }
 
@@ -1180,7 +1182,7 @@ min_delay:
 }
 
 /* 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);
 
@@ -1242,13 +1244,13 @@ static void status_post_select(__a_unused struct sched *s, struct task *t)
                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]);
@@ -1332,7 +1334,6 @@ static void init_colors_or_die(void)
 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,
@@ -1384,12 +1385,12 @@ int main(int argc, char *argv[])
        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;
index dfb014a..adfa07e 100644 (file)
@@ -27,6 +27,7 @@
 #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. */
@@ -286,7 +287,7 @@ out:
 
 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);
@@ -344,7 +345,7 @@ int com_stat(int fd, int argc, char **argv)
 
 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)
index b6a2f24..038fc01 100644 (file)
--- a/client.c
+++ b/client.c
 
 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;
@@ -35,13 +36,13 @@ static void supervisor_post_select(__a_unused struct sched *s, struct task *t)
        }
        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;
        }
@@ -82,6 +83,7 @@ int main(int argc, char *argv[])
        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
@@ -89,13 +91,13 @@ int main(int argc, char *argv[])
         */
        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);
index 28b786a..3aa048a 100644 (file)
--- a/client.h
+++ b/client.h
@@ -48,4 +48,5 @@ struct client_task {
 
 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);
index eb9f9e1..85978c8 100644 (file)
@@ -310,7 +310,7 @@ out:
 }
 
 /* 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;
 
@@ -327,7 +327,7 @@ static int client_connect(struct client_task *ct)
        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);
@@ -345,6 +345,7 @@ err_out:
  * \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.
@@ -353,7 +354,8 @@ err_out:
  * \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;
@@ -413,7 +415,7 @@ int client_open(int argc, char *argv[], struct client_task **ct_ptr,
        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) {
index b6861b8..932c9f3 100644 (file)
--- a/command.c
+++ b/command.c
@@ -24,6 +24,7 @@
 #include "server.h"
 #include "list.h"
 #include "send.h"
+#include "sched.h"
 #include "vss.h"
 #include "net.h"
 #include "daemon.h"
@@ -32,7 +33,6 @@
 #include "user_list.h"
 #include "server_command_list.h"
 #include "afs_command_list.h"
-#include "sched.h"
 #include "signal.h"
 #include "version.h"
 
index 0484778..53fa54e 100644 (file)
@@ -24,6 +24,7 @@
 #include "net.h"
 #include "list.h"
 #include "send.h"
+#include "sched.h"
 #include "vss.h"
 #include "fd.h"
 #include "close_on_fork.h"
index 0dfc94b..bc9952a 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -120,7 +120,7 @@ int main(int argc, char *argv[])
        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++) {
@@ -143,13 +143,13 @@ int main(int argc, char *argv[])
                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;
index 9109c2f..e5f4241 100644 (file)
@@ -116,7 +116,7 @@ static void gc_post_select(struct sched *s, struct task *t);
  *
  * \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";
@@ -135,7 +135,7 @@ static void gc_activate(struct grab_client *gc)
        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);
 }
 
 /**
@@ -149,7 +149,7 @@ static void gc_activate(struct grab_client *gc)
  * 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;
 
@@ -159,7 +159,7 @@ void activate_grab_clients(void)
                        free(gc);
                        continue;
                }
-               gc_activate(gc);
+               gc_activate(gc, s);
        }
 }
 
@@ -266,6 +266,7 @@ static int gc_check_args(int argc, char **argv, struct grab_client *gc)
  * \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
@@ -276,7 +277,7 @@ static int gc_check_args(int argc, char **argv, struct grab_client *gc)
  *
  * \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));
@@ -286,7 +287,7 @@ int grab_client_new(int fd, int argc, char **argv)
                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);
index 88b9548..2465d88 100644 (file)
@@ -6,5 +6,5 @@
 
 /** \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);
index 8ae2341..5021170 100644 (file)
@@ -21,6 +21,7 @@
 #include "http.h"
 #include "list.h"
 #include "send.h"
+#include "sched.h"
 #include "vss.h"
 #include "close_on_fork.h"
 #include "net.h"
diff --git a/recv.c b/recv.c
index 52f457f..9b63f51 100644 (file)
--- a/recv.c
+++ b/recv.c
@@ -102,12 +102,12 @@ int main(int argc, char *argv[])
        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:
diff --git a/sched.c b/sched.c
index 66a1741..041cf41 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -20,9 +20,6 @@
 #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;
 
@@ -36,8 +33,6 @@ 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));
@@ -56,7 +51,7 @@ static inline bool timeout_is_zero(struct sched *s)
 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;
@@ -93,7 +88,7 @@ static void sched_post_select(struct sched *s)
 {
        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);
@@ -105,7 +100,7 @@ static void sched_post_select(struct sched *s)
                 * 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);
        }
@@ -130,8 +125,6 @@ int schedule(struct sched *s)
 {
        int ret;
 
-       if (!initialized)
-               return -E_NOT_INITIALIZED;
        if (!s->select_function)
                s->select_function = para_select;
 again:
@@ -141,7 +134,7 @@ 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,
@@ -164,44 +157,36 @@ again:
                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);
        }
 }
 
@@ -212,21 +197,18 @@ void register_task(struct task *t)
  * \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;
 }
 
 /**
@@ -237,20 +219,18 @@ void sched_shutdown(void)
  * 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;
diff --git a/sched.h b/sched.h
index ea9578f..b3df0b6 100644 (file)
--- a/sched.h
+++ b/sched.h
@@ -29,6 +29,10 @@ struct sched {
        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;
 };
 
 /**
@@ -74,10 +78,10 @@ struct task {
  */
 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);
index e786f99..5bd7d57 100644 (file)
@@ -22,6 +22,7 @@
 #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. */
index 4650f99..ef79a2e 100644 (file)
--- a/server.c
+++ b/server.c
@@ -79,6 +79,7 @@
 #include "server.h"
 #include "list.h"
 #include "send.h"
+#include "sched.h"
 #include "vss.h"
 #include "config.h"
 #include "close_on_fork.h"
@@ -86,7 +87,6 @@
 #include "daemon.h"
 #include "ipc.h"
 #include "fd.h"
-#include "sched.h"
 #include "signal.h"
 #include "user_list.h"
 #include "color.h"
@@ -123,6 +123,7 @@ int mmd_mutex;
 /** 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 {
@@ -346,7 +347,7 @@ static void init_signal_task(void)
        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)
@@ -429,7 +430,7 @@ static void init_server_command_task(int argc, char **argv)
                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));
@@ -519,7 +520,7 @@ static void server_init(int argc, char **argv)
        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);
@@ -571,16 +572,13 @@ static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds,
 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);
index 7a1a89f..880d795 100644 (file)
 #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"
 
 /**
diff --git a/vss.c b/vss.c
index 4a8aafa..17d4691 100644 (file)
--- a/vss.c
+++ b/vss.c
 #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;
 
@@ -1157,11 +1157,12 @@ static void vss_post_select(struct sched *s, struct task *t)
  * 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;
@@ -1194,5 +1195,5 @@ void init_vss_task(int afs_socket)
                        &vsst->data_send_barrier);
        }
        sprintf(vsst->task.status, "vss task");
-       register_task(&vsst->task);
+       register_task(s, &vsst->task);
 }
diff --git a/vss.h b/vss.h
index bd798b0..ae53f6e 100644 (file)
--- a/vss.h
+++ b/vss.h
@@ -6,7 +6,7 @@
 
 /** \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);
diff --git a/write.c b/write.c
index 3b5f2d1..afaad95 100644 (file)
--- a/write.c
+++ b/write.c
@@ -186,7 +186,7 @@ __noreturn static void print_help_and_die(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);
@@ -194,7 +194,7 @@ static void setup_writer_node(const char *arg, struct btr_node *parent,
                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)
@@ -208,7 +208,7 @@ 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;
@@ -219,17 +219,17 @@ static int setup_and_schedule(void)
        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;
index b856993..71b6664 100644 (file)
@@ -77,11 +77,13 @@ void *check_writer_arg_or_die(const char *wa, int *writer_num)
  *
  * \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]);
@@ -93,7 +95,7 @@ void register_writer_node(struct writer_node *wn, struct btr_node *parent)
        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);
 }
 
 /**
index 00ded8f..68eb406 100644 (file)
@@ -9,7 +9,8 @@
 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);