+
+/* ------------------------------------------------------------------------- */
+
+/* Free allocated memory for a task's stack. */
+static inline int
+free_stack (void *stack, size_t size)
+{
+ return munmap (stack, size);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Get the next free task id.
+ *
+ * Stupid simple implementation, not thread safe! */
+static int
+get_next_id (void)
+{
+ static int id = 0;
+ return ++id; /* id=0 is reserved for task_kernel */
+}
+
+/* ------------------------------------------------------------------------- */
+/* Exported functions ----------------------------------------------------- */
+
+void
+task_init (void)
+{
+ /* TODO */
+}
+
+/* ------------------------------------------------------------------------- */
+
+struct task_t *
+task_create (char *name, void (*entry) (void *), void *arg)
+{
+ struct task_t *task;
+ unsigned char *stack;
+
+ if (!(task = malloc (sizeof *task)))
+ goto err_malloc_task;
+
+ if (!(stack = alloc_stack (STACK_SIZE)))
+ goto err_malloc_stack;
+
+ task->id = get_next_id ();
+ task->name = name;
+ task->status = STATUS_READY;
+
+ /* Probably not the best way to do this but with this interface and the
+ * current implementation it's the best we can do right now.
+ *
+ * We need it for task_switch ().
+ *
+ * In a multiprocessor system this doesn't hold up. */
+
+ task->parent = task_current;
+
+ if (ctx_create (&task->context, entry, arg, stack, STACK_SIZE))
+ goto err_ctx_create;
+
+ return task;
+
+err_ctx_create:
+ free_stack (stack, STACK_SIZE);
+err_malloc_stack:
+ free (task);
+err_malloc_task:
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+task_destroy (struct task_t *task)
+{
+ if (task->status != STATUS_TERMINATED)
+ return ERROR;
+
+ if (free_stack (task->context.stack, task->context.size))
+ return ERROR; /* Probably EINVAL. */
+
+ free (task);
+
+ return NOERROR;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+task_switch (struct task_t *task)
+{
+ if (!task)
+ return task_switch (task_current->parent);
+
+ /* Instructions not clear... */
+ switch (task->status)
+ {
+ case STATUS_TERMINATED: /* Switch to task_kernel or to parent? */
+ return task_switch (task_kernel);
+
+ case STATUS_RUNNING: /* Return ERROR or switch to another task? */
+ return ERROR;
+ }
+
+ task_current->status = STATUS_SUSPENDED;
+ task_current = task;
+ task_current->status = STATUS_RUNNING;
+
+ /* task_current and task are not the same, because if they task->status would
+ * be STATUS_RUNNING, which is handled earlier.
+ *
+ * Since that's the only error case for ctx_swap (), we're fine ... */
+
+ return ctx_swap (&task_current->context, &task->context);
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+task_id (struct task_t *task)
+{
+ if (!task)
+ return task_id (task->current);
+
+ return task->id;
+}
+
+/* ------------------------------------------------------------------------- */
+
+char *
+task_name (struct task_t *task)
+{
+ if (!task)
+ return task_id (task->current);
+
+ return task->name;
+}
+
+/* ------------------------------------------------------------------------- */