From 00cedf20a69178ac3ec3e43035a2d54868f1bc6d Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Mon, 30 Dec 2013 17:37:41 +0000 Subject: [PATCH 1/1] Simplify sched: Use only a single task list. Currently the scheduler maintains two linked task lists, the pre_select and the post_select list. This is completely unnecessary and bloats the code for no good reason. This patch makes it use a single list only and updates the documentation accordingly. --- sched.c | 80 ++++++++++++++------------------------------------------- sched.h | 28 +++++++++----------- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/sched.c b/sched.c index 8b68667b..86069029 100644 --- a/sched.c +++ b/sched.c @@ -21,25 +21,6 @@ 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; @@ -50,7 +31,9 @@ static void sched_preselect(struct sched *s) { 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) @@ -82,19 +65,16 @@ static void sched_post_select(struct sched *s) { 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. * @@ -103,10 +83,10 @@ static void sched_post_select(struct sched *s) * 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) { @@ -137,7 +117,7 @@ again: } 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; } @@ -148,27 +128,16 @@ 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); } /** @@ -186,21 +155,12 @@ char *get_task_list(struct sched *s) 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; } @@ -261,9 +221,7 @@ void task_notify_all(struct sched *s, int err) { 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); } diff --git a/sched.h b/sched.h index f15e4efb..c706b509 100644 --- a/sched.h +++ b/sched.h @@ -10,11 +10,11 @@ /** * 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. */ @@ -29,10 +29,8 @@ 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; + /** Tasks which have been registered to the scheduler. */ + struct list_head task_list; }; /** @@ -45,26 +43,24 @@ struct sched { */ 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. */ -- 2.39.2