X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=sched.c;h=7ee77027bc9c4cf6e26faed3533d37865c7cedbe;hp=041cf417723bd848ea56d2c7eb4935943abeeaef;hb=23b121a85984baa9252f4b4c0b8c4f186e394bb7;hpb=ef1f130a1f9ac61a51da10ee56c5bd9ef1b52366 diff --git a/sched.c b/sched.c index 041cf417..7ee77027 100644 --- a/sched.c +++ b/sched.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Andre Noll + * Copyright (C) 2006-2013 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -9,7 +9,6 @@ #include #include #include -#include #include "para.h" #include "ipc.h" @@ -56,6 +55,10 @@ static void sched_preselect(struct sched *s) unregister_task(t); continue; } + if (t->notification != 0) { + sched_min_delay(s); + break; + } if (!t->pre_select) continue; t->pre_select(s, t); @@ -92,16 +95,9 @@ static void sched_post_select(struct sched *s) if (t->error >= 0) call_post_select(s, t); // PARA_INFO_LOG("%s: %d\n", t->status, t->ret); + t->notification = 0; if (t->error >= 0) continue; - /* - * We have to check whether the list is empty because the call - * to ->post_select() might have called sched_shutdown(). In - * this case t has been unregistered already, so we must not - * unregister it again. - */ - if (list_empty(&s->post_select_list)) - return; unregister_task(t); } } @@ -176,6 +172,7 @@ again: void register_task(struct sched *s, struct task *t) { PARA_INFO_LOG("registering %s (%p)\n", t->status, t); + t->notification = 0; if (!s->pre_select_list.next) INIT_LIST_HEAD(&s->pre_select_list); if (!s->post_select_list.next) @@ -190,30 +187,11 @@ void register_task(struct sched *s, struct task *t) } } -/** - * Unregister all tasks. - * - * This will cause \a schedule() to return immediately because both the - * \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(struct sched *s) -{ - struct task *t, *tmp; - - 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, &s->post_select_list, post_select_node) { - t->error = -E_SCHED_SHUTDOWN; - unregister_task(t); - } -} - /** * Get the list of all registered tasks. * + * \param s The scheduler instance to get the task list from. + * * \return The task list. * * Each entry of the list contains an identifier which is simply a hex number. @@ -242,6 +220,69 @@ char *get_task_list(struct sched *s) return msg; } +/** + * Set the notification value of a task. + * + * \param t The task to notify. + * \param err A positive error code. + * + * Tasks which honor notifications are supposed to call \ref + * task_get_notification() in their post_select function and act on the + * returned notification value. + * + * If the scheduler detects during its pre_select loop that at least one task + * has been notified, the loop terminates, and the post_select methods of all + * taks are immediately called again. + * + * The notification for a task is reset after the call to its post_select + * method. + * + * \sa \ref task_get_notification(). + */ +void task_notify(struct task *t, int err) +{ + assert(err > 0); + if (t->notification == -err) /* ignore subsequent notifications */ + return; + PARA_INFO_LOG("notifying task %s: %s\n", t->status, para_strerror(err)); + t->notification = -err; +} + +/** + * Return the notification value of a task. + * + * \param t The task to get the notification value from. + * + * \return The notification value. If this is negative, the task has been + * notified by another task. Tasks are supposed to check for notifications by + * calling this function from their post_select method. + * + * \sa \ref task_notify(). + */ +int task_get_notification(struct task *t) +{ + return t->notification; +} + +/** + * Set the notification value of all tasks of a scheduler instance. + * + * \param s The scheduler instance whose tasks should be notified. + * \param err A positive error code. + * + * This simply iterates over all existing tasks of \a s and sets each + * task's notification value to \p -err. + */ +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) + task_notify(t, err); +} + /** * Set the select timeout to the minimal possible value. *