static struct timeval now_struct;
struct timeval *now = &now_struct;
-/*
- * Remove a task from the scheduler.
- *
- * \param t The task to remove.
- *
- * If the pre_select pointer of \a t is not \p NULL, it is removed from
- * the pre_select list of the scheduler. Same goes for \a post_select.
- */
-static void unregister_task(struct task *t)
-{
- assert(t->error < 0);
- PARA_INFO_LOG("unregistering %s (%s)\n", t->status,
- para_strerror(-t->error));
- if (t->pre_select)
- list_del(&t->pre_select_node);
- if (t->post_select)
- list_del(&t->post_select_node);
-}
-
static inline bool timeout_is_zero(struct sched *s)
{
struct timeval *tv = &s->select_timeout;
{
struct task *t, *tmp;
- list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->task_list, node) {
+ if (t->error < 0)
+ continue;
if (t->notification != 0)
sched_min_delay(s);
if (t->pre_select)
{
struct task *t, *tmp;
- 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);
+ list_for_each_entry_safe(t, tmp, &s->task_list, node) {
+ call_post_select(s, t);
t->notification = 0;
- if (t->error >= 0)
- continue;
- unregister_task(t);
+ if (t->error < 0)
+ list_del(&t->node);
}
}
/**
- * The core function for all paraslash programs.
+ * The core function of all paraslash programs.
*
* \param s Pointer to the scheduler struct.
*
* the fd sets of \a s. Next, it calls para_select() and makes the result available
* to the registered tasks by calling their post_select hook.
*
- * \return Zero if no more tasks are left in either of the two lists, negative
- * if para_select returned an error.
+ * \return Zero if no more tasks are left in the task list, negative if the
+ * select function returned an error.
*
- * \sa task, now.
+ * \sa \ref task, \ref now.
*/
int schedule(struct sched *s)
{
}
clock_get_realtime(now);
sched_post_select(s);
- if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list))
+ if (list_empty(&s->task_list))
return 0;
goto again;
}
* \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 sched *s, struct task *t)
{
PARA_INFO_LOG("registering %s (%p)\n", t->status, t);
+ assert(t->post_select);
t->notification = 0;
- 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, &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, &s->post_select_list);
- }
+ if (!s->task_list.next)
+ INIT_LIST_HEAD(&s->task_list);
+ list_add_tail(&t->node, &s->task_list);
}
/**
struct task *t, *tmp;
char *msg = NULL;
- 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, &s->post_select_list, post_select_node) {
+ list_for_each_entry_safe(t, tmp, &s->task_list, node) {
char *tmp_msg;
-// if (t->pre_select)
-// continue;
- tmp_msg = make_message("%s%p\tpost\t%s\n", msg? msg : "", t, t->status);
+ tmp_msg = make_message("%s%p\t%s\n", msg? msg : "", t, t->status);
free(msg);
msg = tmp_msg;
}
- //PARA_DEBUG_LOG("task list:\n%s", msg);
return msg;
}
{
struct task *t;
- list_for_each_entry(t, &s->pre_select_list, pre_select_node)
- task_notify(t, err);
- list_for_each_entry(t, &s->post_select_list, post_select_node)
+ list_for_each_entry(t, &s->task_list, node)
task_notify(t, err);
}
/**
* Paraslash's scheduler.
*
- * Designed with KISS in mind. It manages two lists of tasks. The pre_select
- * list contains pointers to functions that are called before calling select()
- * from the main loop. Similarly, \a post_select_list is a list of function
- * pointers each of which is called after the select call. Tasks add hooks to
- * these lists by registering themselves to the 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_select
+ * function which is called from the scheduler main loop before it calls
+ * select(). Similarly, each task must define a post_select function which is
+ * called after the select call.
*/
struct sched {
/** Initial value before any pre_select call. */
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;
+ /** Tasks which have been registered to the scheduler. */
+ struct list_head task_list;
};
/**
*/
struct task {
/**
- * The pre select hook of \a t.
+ * The optional pre select hook of \a t.
*
* Its purpose is to add file descriptors to the fd sets of the
* scheduler and to decrease the select timeout if necessary.
*/
void (*pre_select)(struct sched *s, struct task *t);
/**
- * The post select hook of \a t.
+ * The mandatory post select hook of \a t.
*
* Its purpose is to evaluate and act upon the results of the previous
* select call. If this function returns a negative value, the
* scheduler unregisters the task.
*/
int (*post_select)(struct sched *s, struct task *t);
- /** Whether this task is in error state. */
+ /** Whether this task is active (>=0) or in error state (<0). */
int error;
- /** Position of the task in the pre_select list of the scheduler. */
- struct list_head pre_select_node;
- /** Position of the task in the post_select list of the scheduler. */
- struct list_head post_select_node;
+ /** Position of the task in the task list of the scheduler. */
+ struct list_head node;
/** Descriptive text and current status of the task. */
char status[255];
/** If less than zero, the task was notified by another task. */