261 lines
7.6 KiB
Text
261 lines
7.6 KiB
Text
.section Libraries
|
|
.topic libtasks
|
|
.title libtasks -- Cooperative Task Switching
|
|
.toc 0 libtasks -- Cooperative Task Switching
|
|
.index libtasks
|
|
.index Task Switching
|
|
.index Cooperative Multitasking
|
|
.index taskswitch.h
|
|
|
|
.h1 libtasks -- Cooperative Task Switching
|
|
|
|
Credit-based cooperative (non-preemptive) multitasking library for DOS protected mode (DJGPP/DPMI). Each task receives (priority + 1) credits per scheduling round. Tasks run round-robin, consuming one credit per turn. When all credits are exhausted, every ready task is refilled. Higher-priority tasks run proportionally more often but never starve lower ones.
|
|
|
|
Header: tasks/taskswitch.h
|
|
|
|
.h2 Why Cooperative
|
|
|
|
DOS is single-threaded with no kernel scheduler. DPMI provides no preemption primitives. The DVX GUI event model is inherently single-threaded: one compositor, one input queue, one window stack. Cooperative switching lets each task yield at safe points, avoiding synchronization primitives entirely.
|
|
|
|
.h2 Error Codes
|
|
|
|
.table
|
|
Constant Value Description
|
|
-------- ----- -----------
|
|
TS_OK 0 Success
|
|
TS_ERR_INIT -1 Task system not initialized
|
|
TS_ERR_PARAM -2 Invalid parameter (bad task ID, etc.)
|
|
TS_ERR_FULL -3 Task array full (should not occur; array grows)
|
|
TS_ERR_NOMEM -4 Memory allocation failed
|
|
TS_ERR_STATE -5 Invalid state transition
|
|
.endtable
|
|
|
|
.h2 Constants
|
|
|
|
.table
|
|
Constant Value Description
|
|
-------- ----- -----------
|
|
TS_DEFAULT_STACK_SIZE 32768 Default stack size per task (32 KB)
|
|
TS_NAME_MAX 32 Maximum task name length including NUL
|
|
TS_PRIORITY_LOW 0 Low priority (1 credit per round)
|
|
TS_PRIORITY_NORMAL 5 Normal priority (6 credits per round)
|
|
TS_PRIORITY_HIGH 10 High priority (11 credits per round)
|
|
.endtable
|
|
|
|
.h2 Types
|
|
|
|
.h3 TaskStateE
|
|
|
|
Task scheduling state. Only Ready tasks participate in scheduling.
|
|
|
|
.table
|
|
Value Description
|
|
----- -----------
|
|
TaskStateReady Eligible for scheduling
|
|
TaskStateRunning Currently executing (cosmetic; marks active task)
|
|
TaskStatePaused Skipped by scheduler until explicitly resumed
|
|
TaskStateTerminated Slot available for reuse
|
|
.endtable
|
|
|
|
.h3 TaskEntryT
|
|
|
|
.code
|
|
typedef void (*TaskEntryT)(void *arg);
|
|
.endcode
|
|
|
|
Task entry point function signature. The void* argument lets the caller pass arbitrary context (e.g. a shell app descriptor).
|
|
|
|
.h2 tsInit
|
|
|
|
.code
|
|
int32_t tsInit(void);
|
|
.endcode
|
|
|
|
Initialize the task system. The calling context becomes task 0 (the main task). Task 0 is special: it cannot be killed or paused, and tsRecoverToMain() always returns control here. No separate stack is allocated for task 0; it uses the process stack directly.
|
|
|
|
Returns: TS_OK on success, TS_ERR_INIT if already initialized.
|
|
|
|
.h2 tsShutdown
|
|
|
|
.code
|
|
void tsShutdown(void);
|
|
.endcode
|
|
|
|
Shut down the task system and free all task stacks and internal storage. Safe to call even if tsInit() was never called.
|
|
|
|
.h2 tsCreate
|
|
|
|
.code
|
|
int32_t tsCreate(const char *name, TaskEntryT entry, void *arg, uint32_t stackSize, int32_t priority);
|
|
.endcode
|
|
|
|
Create a new task. Terminated task slots are recycled to avoid unbounded array growth.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
name Task name (truncated to TS_NAME_MAX - 1 characters)
|
|
entry Task entry point function
|
|
arg Opaque argument passed to entry
|
|
stackSize Stack size in bytes (pass 0 for TS_DEFAULT_STACK_SIZE)
|
|
priority Scheduling priority (0..10; use TS_PRIORITY_* constants)
|
|
.endtable
|
|
|
|
Returns: Task ID (>= 0) on success, or a negative error code (TS_ERR_INIT, TS_ERR_PARAM, TS_ERR_NOMEM).
|
|
|
|
.h2 tsYield
|
|
|
|
.code
|
|
void tsYield(void);
|
|
.endcode
|
|
|
|
Yield CPU to the next eligible ready task using credit-based round-robin. This is the sole mechanism for task switching. Every task must call this (or a GUI function that calls it) periodically, or it will monopolize the CPU.
|
|
|
|
.h2 tsPause
|
|
|
|
.code
|
|
int32_t tsPause(uint32_t taskId);
|
|
.endcode
|
|
|
|
Pause a task, removing it from scheduling. Cannot pause the main task (ID 0). If a task pauses itself, an implicit yield occurs.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to pause
|
|
.endtable
|
|
|
|
Returns: TS_OK on success, TS_ERR_PARAM on invalid ID, TS_ERR_STATE if the task is not in a pausable state.
|
|
|
|
.h2 tsResume
|
|
|
|
.code
|
|
int32_t tsResume(uint32_t taskId);
|
|
.endcode
|
|
|
|
Resume a paused task. Credits are refilled so the task gets a fair share of CPU time immediately rather than waiting for the next scheduling round.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to resume
|
|
.endtable
|
|
|
|
Returns: TS_OK on success, TS_ERR_PARAM on invalid ID, TS_ERR_STATE if the task is not paused.
|
|
|
|
.h2 tsSetPriority
|
|
|
|
.code
|
|
int32_t tsSetPriority(uint32_t taskId, int32_t priority);
|
|
.endcode
|
|
|
|
Set a task's scheduling priority. Also refills credits so the change takes effect immediately.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to modify
|
|
priority New priority level (0..10)
|
|
.endtable
|
|
|
|
Returns: TS_OK on success, TS_ERR_PARAM on invalid ID or out-of-range priority.
|
|
|
|
.h2 tsGetPriority
|
|
|
|
.code
|
|
int32_t tsGetPriority(uint32_t taskId);
|
|
.endcode
|
|
|
|
Get a task's current scheduling priority.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to query
|
|
.endtable
|
|
|
|
Returns: Priority value (0..10) on success, TS_ERR_PARAM on invalid ID.
|
|
|
|
.h2 tsGetState
|
|
|
|
.code
|
|
TaskStateE tsGetState(uint32_t taskId);
|
|
.endcode
|
|
|
|
Get a task's current scheduling state.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to query
|
|
.endtable
|
|
|
|
Returns: TaskStateE value. Returns TaskStateTerminated for invalid IDs.
|
|
|
|
.h2 tsCurrentId
|
|
|
|
.code
|
|
uint32_t tsCurrentId(void);
|
|
.endcode
|
|
|
|
Get the ID of the currently executing task. Always valid while the task system is initialized.
|
|
|
|
Returns: Current task ID.
|
|
|
|
.h2 tsGetName
|
|
|
|
.code
|
|
const char *tsGetName(uint32_t taskId);
|
|
.endcode
|
|
|
|
Get a task's name string.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to query
|
|
.endtable
|
|
|
|
Returns: Pointer to the task's name, or NULL on invalid ID. The pointer remains valid until the task slot is reused.
|
|
|
|
.h2 tsExit
|
|
|
|
.code
|
|
void tsExit(void);
|
|
.endcode
|
|
|
|
Terminate the calling task. Must not be called from the main task (ID 0). The stack is freed immediately and the slot is marked for reuse. This function never returns; it performs an internal context switch to the next ready task.
|
|
|
|
.h2 tsKill
|
|
|
|
.code
|
|
int32_t tsKill(uint32_t taskId);
|
|
.endcode
|
|
|
|
Forcibly terminate another task. Cannot kill the main task (ID 0) or the currently running task (use tsExit() for self-termination). Safe because cooperative scheduling guarantees the target is suspended at a yield point.
|
|
|
|
.table
|
|
Parameter Description
|
|
--------- -----------
|
|
taskId ID of the task to terminate
|
|
.endtable
|
|
|
|
Returns: TS_OK on success, TS_ERR_PARAM on invalid ID or illegal target (main task, self).
|
|
|
|
.h2 tsRecoverToMain
|
|
|
|
.code
|
|
void tsRecoverToMain(void);
|
|
.endcode
|
|
|
|
Crash recovery: force the scheduler back to the main task (ID 0). Call after longjmp from a signal handler that fired in a non-main task. The crashed task is NOT cleaned up by this call; call tsKill() afterward to free its resources. This exists because longjmp unwinds the crashed task's stack but the scheduler state still points to it.
|
|
|
|
.h2 tsActiveCount
|
|
|
|
.code
|
|
uint32_t tsActiveCount(void);
|
|
.endcode
|
|
|
|
Get the number of non-terminated tasks currently in the system.
|
|
|
|
Returns: Count of tasks in Ready, Running, or Paused state.
|