122 lines
3.2 KiB
C
122 lines
3.2 KiB
C
// intellectual property is bullshit bgdc
|
|
|
|
#ifndef UTASK_H
|
|
#define UTASK_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define IN_UTASK_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <inttypes.h>
|
|
|
|
#ifdef __riscv
|
|
# include "utask_riscv.h"
|
|
#else
|
|
# error "utask.h does not support this architecture"
|
|
#endif
|
|
|
|
#define UTASK_STACK_CANARY 0x5AD54ACC
|
|
|
|
// Extremely lightweight cooperative multitasking library. Each task runs on
|
|
// its own stack, and yields to other tasks when ready. Tasks are run
|
|
// round-robin.
|
|
//
|
|
// TODO: Allow tasks to exit
|
|
// TODO: Stack high water mark
|
|
|
|
struct utask_s;
|
|
|
|
typedef struct utask_s {
|
|
void (*func)(uintptr_t arg);
|
|
uint8_t * stack; // May be adjusted on task start
|
|
size_t stack_size; // May be adjusted on task start
|
|
char const * name; // Optional
|
|
|
|
// -- Private - user need not initialize --
|
|
uintptr_t _arg;
|
|
struct utask_s * _next;
|
|
bool _started;
|
|
struct utask_arch_specific _arch;
|
|
} utask_t;
|
|
|
|
// Default initializers for the private members of utask_t. This is not
|
|
// necessary, but you can include this in definitions to keep the compiler
|
|
// from warning about uninitialized members.
|
|
#define UTASK_INIT \
|
|
._arg = 0, \
|
|
._next = NULL, \
|
|
._started = false, \
|
|
._arch = UTASK_ARCH_SPECIFIC_INIT,
|
|
|
|
// Get the next task after this one. Useful for traversing the task list.
|
|
#define UTASK_NEXT(t) ((t)->_next)
|
|
|
|
// Pointer to the currently executing task struct
|
|
extern utask_t * current_task;
|
|
|
|
// Pointer to the task list
|
|
extern utask_t * volatile task_list;
|
|
|
|
// Add a task to the queue. The queue may be modified at any time.
|
|
//
|
|
// tasks: task list. The task list should start as NULL.
|
|
// task: task to add. Function and stack pointers should be initialized.
|
|
// arg: argument passed to task.
|
|
//
|
|
// Returns the new task list pointer.
|
|
void utask_add(utask_t * task, uintptr_t arg);
|
|
|
|
// Run. Never returns.
|
|
void utask_run(void);
|
|
|
|
// Query task high water mark. Returns how many free bytes of stack are
|
|
// untouched.
|
|
size_t utask_stack_free_bytes(utask_t * task);
|
|
|
|
// Inhibit sleep. When this is called, a task_sleep_allow() must follow or the
|
|
// system will never go to sleep. May nest indefinitely. Preemption-safe, may
|
|
// be called from interrupts.
|
|
void utask_sleep_inhibit(void);
|
|
|
|
// Undo task_sleep_inhibit(). Preemption-safe, may be called from interrupts.
|
|
void utask_sleep_allow(void);
|
|
|
|
// Weak-linked stack overflow handler. Override to handle.
|
|
void utask_stack_overflow_cb(utask_t * task);
|
|
|
|
// Weak-linked sleeper. To permit the main loop to go to sleep in between
|
|
// interrupts, override this and insert whatever sleep code you want to use.
|
|
void utask_sleep_cb(void);
|
|
|
|
// These are defined in the architecture-specific header.
|
|
#if !UTASK_ARCH_INCLUDED
|
|
|
|
// Yield from this task. It will be run the next time around.
|
|
#define utask_yield()
|
|
|
|
// Define a stack for a task. The architecture-specific macro will ensure it
|
|
// is defined in the correct section, with the correct alignment, etc.
|
|
//
|
|
// Defined such that you may prepend `static` if desired.
|
|
//
|
|
// name: Name of the stack variable
|
|
// size: Size in bytes
|
|
#define utask_decl_stack(name, size)
|
|
|
|
#endif
|
|
|
|
// Yield until a condition is true.
|
|
#define utask_yield_until(cond) do { while (!(cond)) utask_yield(); } while (0)
|
|
|
|
#undef IN_UTASK_H
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // !defined(UTASK_H)
|