#include "time.h"
#include "error.h"
+struct task {
+ /** The task name supplied when the task was registered(). */
+ char name[255];
+ /** Copied from the task_info struct during task_register(). */
+ void (*pre_select)(struct sched *s, struct task *t);
+ /** Copied from the task_info struct during task_register(). */
+ int (*post_select)(struct sched *s, struct task *t);
+ /** Whether this task is active (>=0) or in error state (<0). */
+ int status;
+ /** Position of the task in the task list of the scheduler. */
+ struct list_head node;
+ /** If less than zero, the task was notified by another task. */
+ int notification;
+ /** True if task is in error state and exit status has been queried. */
+ bool dead;
+ /** Usually a pointer to the struct containing this task. */
+ void *context;
+};
+
static struct timeval now_struct;
struct timeval *now = &now_struct;
struct task *t, *tmp;
list_for_each_entry_safe(t, tmp, &s->task_list, node) {
- if (t->error < 0)
+ if (t->status < 0)
continue;
if (t->notification != 0)
sched_min_delay(s);
static void unlink_and_free_task(struct task *t)
{
- PARA_INFO_LOG("freeing task %s\n", t->status);
+ PARA_INFO_LOG("freeing task %s\n", t->name);
list_del(&t->node);
- if (t->owned_by_sched)
- free(t);
+ free(t);
}
//#define SCHED_DEBUG 1
static inline void call_post_select(struct sched *s, struct task *t)
{
#ifndef SCHED_DEBUG
- t->error = t->post_select(s, t);
+ t->status = t->post_select(s, t);
#else
struct timeval t1, t2, diff;
unsigned long pst;
clock_get_realtime(&t1);
- t->error = t->post_select(s, t);
+ t->status = t->post_select(s, t);
clock_get_realtime(&t2);
tv_diff(&t1, &t2, &diff);
pst = tv2ms(&diff);
if (pst > 50)
PARA_WARNING_LOG("%s: post_select time: %lums\n",
- t->status, pst);
+ t->name, pst);
#endif
}
unsigned num_running_tasks = 0;
list_for_each_entry_safe(t, tmp, &s->task_list, node) {
- if (t->error < 0) {
+ if (t->status < 0) {
if (t->dead) /* task has been reaped */
unlink_and_free_task(t);
continue;
}
call_post_select(s, t);
t->notification = 0;
- if (t->error < 0) {
- if (!t->owned_by_sched)
- list_del(&t->node);
- } else
+ if (t->status >= 0)
num_running_tasks++;
}
return num_running_tasks;
t = *tptr;
if (!t)
return 0;
- if (!t->owned_by_sched)
- return 0;
- if (t->error >= 0)
+ if (t->status >= 0)
return 0;
if (t->dead) /* will be freed in sched_post_select() */
return 0;
*/
t->dead = true;
*tptr = NULL;
- return t->error;
+ return t->status;
}
/**
struct task *t, *tmp;
list_for_each_entry_safe(t, tmp, &s->task_list, node) {
- if (t->error >= 0)
+ if (t->status >= 0)
/* The task list should contain only terminated tasks. */
PARA_WARNING_LOG("shutting down running task %s\n",
- t->status);
+ t->name);
unlink_and_free_task(t);
}
}
-/**
- * Add a task to the scheduler. Deprecated.
- *
- * \param t The task to add.
- * \param s The scheduler instance to add the task to.
- *
- * \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;
- t->owned_by_sched = false;
- if (!s->task_list.next)
- INIT_LIST_HEAD(&s->task_list);
- list_add_tail(&t->node, &s->task_list);
-}
-
/**
* Add a task to the scheduler task list.
*
if (!s->task_list.next)
INIT_LIST_HEAD(&s->task_list);
- snprintf(t->status, sizeof(t->status) - 1, "%s", info->name);
- t->status[sizeof(t->status) - 1] = '\0';
+ snprintf(t->name, sizeof(t->name) - 1, "%s", info->name);
+ t->name[sizeof(t->name) - 1] = '\0';
t->notification = 0;
- t->error = 0;
+ t->status = 0;
t->dead = false;
t->pre_select = info->pre_select;
t->post_select = info->post_select;
t->context = info->context;
- t->owned_by_sched = true;
list_add_tail(&t->node, &s->task_list);
return t;
}
*/
void *task_context(struct task *t)
{
- assert(t->owned_by_sched);
return t->context;
}
list_for_each_entry_safe(t, tmp, &s->task_list, node) {
char *tmp_msg;
tmp_msg = make_message("%s%p\t%s\t%s\n", msg? msg : "", t,
- t->error < 0? (t->dead? "dead" : "zombie") : "running",
- t->status);
+ t->status < 0? (t->dead? "dead" : "zombie") : "running",
+ t->name);
free(msg);
msg = tmp_msg;
}
assert(err > 0);
if (t->notification == -err) /* ignore subsequent notifications */
return;
- PARA_INFO_LOG("notifying task %s: %s\n", t->status, para_strerror(err));
+ PARA_INFO_LOG("notifying task %s: %s\n", t->name, para_strerror(err));
t->notification = -err;
}
return t->notification;
}
+/**
+ * Return the status value of a task.
+ *
+ * \param t The task to get the status value from.
+ *
+ * \return Zero if task does not exist, one if task is running, negative error
+ * code if task has terminated.
+ */
+int task_status(const struct task *t)
+{
+ if (!t)
+ return 0;
+ if (t->dead)
+ return 0;
+ if (t->status >= 0)
+ return 1;
+ return t->status;
+}
+
/**
* Set the notification value of all tasks of a scheduler instance.
*