*/
__noreturn void afs_init(int socket_fd)
{
- static struct sched s;
+ struct sched *s = sched_new(afs_poll);
int ret;
- register_signal_task(&s);
+ register_signal_task(s);
init_list_head(&afs_client_list);
ret = open_afs_tables();
if (ret < 0)
goto out_close;
PARA_INFO_LOG("server_socket: %d\n", server_socket);
init_admissible_files(OPT_STRING_VAL(AFS_INITIAL_MODE));
- register_command_task(&s);
- s.default_timeout = 1000;
- s.poll_function = afs_poll;
+ register_command_task(s);
ret = write(socket_fd, "\0", 1);
if (ret != 1) {
if (ret == 0)
ret = -ERRNO_TO_PARA_ERROR(errno);
goto out_close;
}
- ret = schedule(&s);
- sched_shutdown(&s);
+ ret = schedule(s);
+ sched_shutdown(s);
mood_unload(NULL);
playlist_unload(NULL);
out_close:
#include "buffer_tree.h"
#include "interactive.h"
-static struct sched sched;
+static struct sched *sched;
struct audioc_task {
int fd;
.pre_monitor = audioc_pre_monitor,
.post_monitor = audioc_post_monitor,
.context = at,
- }, &sched);
+ }, sched);
i9e_attach_to_stdout(at->btrn);
return 1;
close:
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
- sched.poll_function = i9e_poll;
-
- sched.default_timeout = 1000;
- ret = i9e_open(&ici, &sched);
+ sched = sched_new(i9e_poll);
+ ret = i9e_open(&ici, sched);
if (ret < 0)
goto out;
para_log = i9e_log;
- ret = schedule(&sched);
- sched_shutdown(&sched);
+ ret = schedule(sched);
+ sched_shutdown(sched);
i9e_close();
para_log = stderr_log;
out:
* This is needed also in audiod_command.c (for the tasks command), so it can
* not be made static.
*/
-struct sched sched = {.timeout = 0};
+struct sched *sched;
/* The task for obtaining para_server's status (para_client stat). */
struct status_task {
.pre_monitor = f->pre_monitor,
.post_monitor = f->post_monitor,
.context = fn,
- }, &sched);
+ }, sched);
parent = fn->btrn;
PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n",
audio_formats[s->format], i, nf, name, (int)(s - slot));
wn = s->wns + i;
wn->wid = a->wids[i];
wn->lpr = a->writer_lpr[i];
- register_writer_node(wn, parent, &sched);
+ register_writer_node(wn, parent, sched);
PARA_NOTICE_LOG("%s writer started in slot %d\n",
writer_name(a->wids[i]), (int)(s - slot));
}
.pre_monitor = r->pre_monitor,
.post_monitor = r->post_monitor,
.context = rn,
- }, &sched);
+ }, sched);
return slot_num;
}
.pre_monitor = command_pre_monitor,
.post_monitor = command_post_monitor,
.context = ct,
- }, &sched);
+ }, sched);
}
static void close_stat_pipe(void)
sl = slot + ret;
open_filters(sl);
open_writers(sl);
- activate_grab_clients(&sched);
+ activate_grab_clients(sched);
btr_log_tree(sl->receiver_node->btrn, LL_NOTICE);
audiod_status_dump(true);
}
.pre_monitor = status_pre_monitor,
.post_monitor = status_post_monitor,
.context = stat_task,
- }, &sched);
+ }, sched);
}
static void set_initial_status(void)
set_initial_status();
FOR_EACH_SLOT(i)
clear_slot(i);
+ sched = sched_new(NULL);
setup_signal_handling();
init_status_task(stat_task);
.pre_monitor = signal_pre_monitor,
.post_monitor = signal_post_monitor,
.context = signal_task,
- }, &sched);
+ }, sched);
- sched.default_timeout = 2999;
- ret = schedule(&sched);
+ ret = schedule(sched);
audiod_cleanup();
- sched_shutdown(&sched);
+ sched_shutdown(sched);
signal_shutdown(signal_task);
crypt_shutdown();
out:
/** Array of error strings. */
DEFINE_PARA_ERRLIST;
-static struct sched sched;
+static struct sched *sched;
static struct client_task *ct;
static struct stdin_task sit;
static struct stdout_task sot;
static int execute_client_command(const char *cmd, char **result)
{
int ret;
- struct sched command_sched = {.default_timeout = 1000};
+ struct sched *command_sched = sched_new(NULL);
struct exec_task exec_task = {
.result_buf = para_strdup(""),
.result_size = 1,
.pre_monitor = exec_pre_monitor,
.post_monitor = exec_post_monitor,
.context = &exec_task,
- }, &command_sched);
- ret = client_connect(ct, &command_sched, NULL, exec_task.btrn);
+ }, command_sched);
+ ret = client_connect(ct, command_sched, NULL, exec_task.btrn);
if (ret < 0)
goto out;
- schedule(&command_sched);
- sched_shutdown(&command_sched);
+ schedule(command_sched);
+ sched_shutdown(command_sched);
lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR);
ct->lpr = old_lpr;
*result = exec_task.result_buf;
ret = create_merged_lpr(line);
if (ret <= 0)
return ret;
- ret = client_connect(ct, &sched, NULL, NULL);
+ ret = client_connect(ct, sched, NULL, NULL);
if (ret < 0)
return ret;
i9e_attach_to_stdout(ct->btrn[0]);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
- sched.poll_function = i9e_poll;
+ sched = sched_new(i9e_poll);
- ret = i9e_open(&ici, &sched);
+ ret = i9e_open(&ici, sched);
if (ret < 0)
goto out;
para_log = i9e_log;
- ret = schedule(&sched);
- sched_shutdown(&sched);
+ ret = schedule(sched);
+ sched_shutdown(sched);
i9e_close();
para_log = stderr_log;
out:
int ret;
crypt_init();
- sched.default_timeout = 1000;
-
ret = client_parse_config(argc, argv, &ct, &client_loglevel);
if (ret < 0)
goto out;
if (ret == 0)
interactive_session(); /* does not return */
+ sched = sched_new(NULL);
/*
* 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_connect(ct, &sched, sit.btrn, NULL);
+ ret = client_connect(ct, sched, sit.btrn, NULL);
if (ret < 0)
goto out;
sot.btrn = btr_new_node(&(struct btr_node_description)
.name = "supervisor",
.post_monitor = supervisor_post_monitor,
.context = &supervisor_task,
- }, &sched);
+ }, sched);
- ret = schedule(&sched);
+ ret = schedule(sched);
if (ret >= 0) {
ret = task_status(ct->task);
if (ret < 0) {
}
}
}
- sched_shutdown(&sched);
+ sched_shutdown(sched);
crypt_shutdown();
out:
if (ret < 0)
*/
int main(int argc, char *argv[])
{
- static struct sched s;
+ struct sched *s = sched_new(NULL);
int i, ret;
const struct filter *f;
struct btr_node *parent;
goto free_lpr;
sit->btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdin"));
- stdin_task_register(sit, &s);
+ stdin_task_register(sit, s);
fns = arr_alloc(OPT_GIVEN(FILTER), sizeof(*fns));
for (i = 0, parent = sit->btrn; i < OPT_GIVEN(FILTER); i++) {
ti.context = fn;
if (f->open)
f->open(fn);
- fn->task = task_register(&ti, &s);
+ fn->task = task_register(&ti, s);
parent = fn->btrn;
}
sot->btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdout", .parent = parent));
- stdout_task_register(sot, &s);
-
- s.default_timeout = 1000;
+ stdout_task_register(sot, s);
btr_log_tree(sit->btrn, LL_INFO);
- ret = schedule(&s);
- sched_shutdown(&s);
+ ret = schedule(s);
+ sched_shutdown(s);
teardown:
for (i--; i >= 0; i--) {
struct filter_node *fn = fns[i];
struct status_task status_task = {.fd = -1};
struct input_task input_task = {.task = NULL};
struct signal_task *signal_task;
- struct sched sched = {.default_timeout = 1000};
+ struct sched *sched = sched_new(NULL);
exec_task.task = task_register(&(struct task_info) {
.name = "exec",
.pre_monitor = exec_pre_monitor,
.post_monitor = exec_post_monitor,
.context = &exec_task,
- }, &sched);
+ }, sched);
status_task.task = task_register(&(struct task_info) {
.name = "status",
.pre_monitor = status_pre_monitor,
.post_monitor = status_post_monitor,
.context = &status_task,
- }, &sched);
+ }, sched);
input_task.task = task_register(&(struct task_info) {
.name = "input",
.pre_monitor = input_pre_monitor,
.post_monitor = input_post_monitor,
.context = &input_task,
- }, &sched);
+ }, sched);
signal_task = signal_init_or_die();
para_install_sighandler(SIGINT);
.pre_monitor = signal_pre_monitor,
.post_monitor = signal_post_monitor,
.context = signal_task,
- }, &sched);
- ret = schedule(&sched);
- sched_shutdown(&sched);
+ }, sched);
+ ret = schedule(sched);
+ sched_shutdown(sched);
signal_shutdown(signal_task);
return ret;
}
char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
-static struct sched sched;
+static struct sched *sched;
static struct play_task play_task, *pt = &play_task;
#define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite))
.pre_monitor = AFH_RECV->pre_monitor,
.post_monitor = AFH_RECV->post_monitor,
.context = &pt->rn
- }, &sched);
+ }, sched);
sprintf(buf, "%s decoder", af);
pt->fn.task = task_register(
&(struct task_info) {
.pre_monitor = decoder->pre_monitor,
.post_monitor = decoder->post_monitor,
.context = &pt->fn
- }, &sched);
- register_writer_node(&pt->wn, pt->fn.btrn, &sched);
+ }, sched);
+ register_writer_node(&pt->wn, pt->fn.btrn, sched);
return 1;
fail:
wipe_receiver_node();
char *buf;
size_t sz;
- buf = get_task_list(&sched);
+ buf = get_task_list(sched);
btr_add_output(buf, strlen(buf), pt->btrn);
state = get_playback_state();
sz = xasprintf(&buf, "state: %c\n", state);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGWINCH, &act, NULL);
- sched.poll_function = i9e_poll;
+ sched = sched_new(i9e_poll);
ici.bound_keyseqs = get_mapped_keyseqs();
pt->btrn = ici.producer = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = __func__));
- ret = i9e_open(&ici, &sched);
+ ret = i9e_open(&ici, sched);
if (ret < 0)
goto out;
para_log = i9e_log;
int ret;
unsigned num_inputs;
- sched.default_timeout = 5000;
parse_config_or_die(argc, argv);
session_open();
num_inputs = lls_num_inputs(play_lpr);
.pre_monitor = play_pre_monitor,
.post_monitor = play_post_monitor,
.context = pt,
- }, &sched);
- ret = schedule(&sched);
- sched_shutdown(&sched);
+ }, sched);
+ ret = schedule(sched);
+ sched_shutdown(sched);
i9e_close();
wipe_receiver_node();
para_log = stderr_log;
const struct receiver *r = NULL;
struct receiver_node rn;
struct stdout_task sot = {.btrn = NULL};
- static struct sched s;
+ static struct sched *s;
struct task_info ti;
const struct lls_command *cmd;
struct lls_parse_result *lpr; /* command line */
goto remove_btrn;
sot.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.parent = rn.btrn, .name = "stdout"));
- stdout_task_register(&sot, &s);
-
+ s = sched_new(NULL);
+ stdout_task_register(&sot, s);
ti.name = lls_command_name(cmd);
ti.pre_monitor = r->pre_monitor;
ti.post_monitor = r->post_monitor;
ti.context = &rn;
- rn.task = task_register(&ti, &s);
-
- s.default_timeout = 1000;
- ret = schedule(&s);
- sched_shutdown(&s);
+ rn.task = task_register(&ti, s);
+ ret = schedule(s);
+ sched_shutdown(s);
r->close(&rn);
btr_remove_node(&sot.btrn);
remove_btrn:
static struct timeval now_struct;
const struct timeval *now = &now_struct;
+/* Internal representation of a paraslash scheduler instance. */
+struct sched {
+ /* Initial value (in milliseconds) before any pre_monitor call. */
+ int default_timeout;
+ /* The timeout (also in milliseconds) for the next iteration. */
+ int timeout;
+ /* Passed to poll(2). */
+ struct pollfd *pfd;
+ /* Number of elements in the above array, passed to poll(2). */
+ unsigned pfd_array_len;
+ /* Number of fds registered for monitoring so far. */
+ unsigned num_pfds;
+ /* Maps fds to indices of the pfd array. */
+ unsigned *pidx;
+ /* Number of elements in the above pidx array. */
+ unsigned pidx_array_len;
+ /* Either the application-supplied function or xpoll() of fd.c. */
+ int (*poll_function)(struct pollfd *fds, nfds_t nfds, int timeout);
+ /* Tasks which have been registered to the scheduler. */
+ struct list_head task_list;
+};
+
+/**
+ * Allocate and initialize a scheduler instance.
+ *
+ * \param poll_function Optional.
+ *
+ * If NULL is passed as the poll function pointer, the \ref xpoll() wrapper
+ * is used to wait for events on the file descriptors passed.
+ *
+ * \return A pointer to the new instance that can be used to register tasks
+ * or to start scheduling. The only possible error is allocation failure,
+ * in which case the function aborts. Thus, it never returns NULL.
+ */
+struct sched *sched_new(int (*poll_function)(struct pollfd *, nfds_t, int))
+{
+ struct sched *s = zalloc(sizeof(*s));
+ s->default_timeout = 1000;
+ init_list_head(&s->task_list);
+ s->poll_function = poll_function? poll_function : xpoll;
+ return s;
+}
+
static void sched_pre_monitor(struct sched *s)
{
struct task *t, *tmp;
int ret;
unsigned num_running_tasks;
- if (!s->poll_function)
- s->poll_function = xpoll;
again:
s->num_pfds = 0;
if (s->pidx)
}
free(s->pfd);
free(s->pidx);
+ free(s);
}
/**
struct task *t = alloc(sizeof(*t));
assert(info->post_monitor);
-
- if (!s->task_list.next)
- init_list_head(&s->task_list);
-
t->info = *info;
t->name = para_strdup(info->name);
t->notification = 0;
/** \file sched.h Sched and task structures and exported symbols from sched.c. */
-
-/**
- * Paraslash's scheduler.
- *
- * Designed with KISS in mind. It maintains a list of task structures which is
- * extended when a new task is registered. Each task may define a pre_monitor
- * function which is called from the scheduler main loop before it calls
- * poll(2). Similarly, each task must define a post_monitor function which is
- * called after poll(2) returns.
- *
- * \sa select(2), poll(2).
- */
-struct sched {
- /** Initial value (in milliseconds) before any pre_monitor call. */
- int default_timeout;
- /** The timeout (also in milliseconds) for the next iteration. */
- int timeout;
- /** Passed to poll(2). */
- struct pollfd *pfd;
- /** Number of elements in the above array, passed to poll(2). */
- unsigned pfd_array_len;
- /** Number of fds registered for montitoring so far. */
- unsigned num_pfds;
- /** Maps fds to indices of the pfd array. */
- unsigned *pidx;
- /** Mumber of elements in the above pidx array. */
- unsigned pidx_array_len;
- /** If non-NULL, use this function instead of \ref xpoll(). */
- int (*poll_function)(struct pollfd *fds, nfds_t nfds, int timeout);
- /** Tasks which have been registered to the scheduler. */
- struct list_head task_list;
-};
-
-struct task;
+struct sched;
/** Information that must be supplied by callers of \ref task_register(). */
struct task_info {
*/
extern const struct timeval *now;
+struct sched *sched_new(int (*poll_function)(struct pollfd *, nfds_t, int));
struct task *task_register(struct task_info *info, struct sched *s);
int schedule(struct sched *s);
void sched_shutdown(struct sched *s);
/* Serializes log output. */
static int log_mutex;
-static struct sched sched;
+static struct sched *sched;
static struct signal_task *signal_task;
/** The process id of the audio file selector process. */
.post_monitor = signal_post_monitor,
.context = signal_task,
- }, &sched);
+ }, sched);
}
static void command_pre_monitor(struct sched *s, void *context)
.pre_monitor = command_pre_monitor,
.post_monitor = command_post_monitor,
.context = sct,
- }, &sched);
+ }, sched);
/*
* Detect whether the abstract Unix domain socket space is supported,
* but do not create the socket. We check this once in server context
init_signal_task();
para_unblock_signal(SIGCHLD);
PARA_NOTICE_LOG("initializing virtual streaming system\n");
- vss_init(afs_socket, &sched);
+ vss_init(afs_socket, sched);
init_server_command_task(sct, argc, argv);
if (daemon_pipe >= 0) {
if (write(daemon_pipe, "\0", 1) < 0) {
struct server_command_task server_command_task_struct,
*sct = &server_command_task_struct;
- sched.default_timeout = 1000;
- sched.poll_function = server_poll;
-
+ sched = sched_new(server_poll);
server_init(argc, argv, sct);
mutex_lock(mmd_mutex);
- ret = schedule(&sched);
+ ret = schedule(sched);
/*
* We hold the mmd lock: it was re-acquired in server_poll()
* after the poll(2) call.
*/
mutex_unlock(mmd_mutex);
- sched_shutdown(&sched);
+ sched_shutdown(sched);
crypt_shutdown();
signal_shutdown(signal_task);
if (!process_is_command_handler()) { /* parent (server) */
int i, n, ret, writer_given = OPT_GIVEN(WRITER, lpr);
struct btr_node *cw_btrn;
struct writer_node *wns;
- static struct sched s;
+ struct sched *s = sched_new(NULL);
struct wav_params wp;
struct write_task wt;
sit.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "stdin"));
- stdin_task_register(&sit, &s);
+ stdin_task_register(&sit, s);
LLS_COPY_WAV_PARMS(&wp, LSG_WRITE_PARA_WRITE, lpr);
wt.cwc = check_wav_init(sit.btrn, NULL, &wp, &cw_btrn);
.pre_monitor = write_pre_monitor,
.post_monitor = write_post_monitor,
.context = &wt,
- }, &s);
+ }, s);
n = writer_given? writer_given : 1;
wns = arr_zalloc(n, sizeof(*wns));
const char *arg = i < writer_given?
lls_string_val(i, OPT_RESULT(WRITER, lpr)) : NULL;
wns[i].wid = check_writer_arg_or_die(arg, &wns[i].lpr);
- register_writer_node(wns + i, cw_btrn, &s);
+ register_writer_node(wns + i, cw_btrn, s);
}
- s.default_timeout = 10500;
- ret = schedule(&s);
+ ret = schedule(s);
if (ret >= 0) {
int j, ts;
for (j = 0; j < n; j++) {
}
free(wns);
check_wav_shutdown(wt.cwc);
- sched_shutdown(&s);
+ sched_shutdown(s);
return ret;
}