144 lines
4.9 KiB
C
144 lines
4.9 KiB
C
// demo.c -- Demonstration of the cooperative task switching library
|
|
//
|
|
// Shows priority scheduling, round-robin, pausing/resuming, dynamic
|
|
// priority changes, and slot reuse after task termination.
|
|
//
|
|
// This is a standalone test harness that runs on the host (Linux x86_64)
|
|
// or DJGPP target to verify the task switcher without the GUI stack.
|
|
// Each phase exercises a different scheduler feature and prints output
|
|
// so you can verify the scheduling order visually.
|
|
|
|
#include <stdio.h>
|
|
#include "taskswitch.h"
|
|
|
|
// Forward declarations
|
|
static void pauseTarget(void *arg);
|
|
static void shortLived(void *arg);
|
|
static void worker(void *arg);
|
|
|
|
|
|
static void pauseTarget(void *arg) {
|
|
(void)arg;
|
|
for (int32_t i = 0; i < 10; i++) {
|
|
printf(" [pauser] iteration %d\n", (int)i);
|
|
tsYield();
|
|
}
|
|
printf(" [pauser] finished\n");
|
|
}
|
|
|
|
|
|
static void shortLived(void *arg) {
|
|
int32_t id = (int32_t)(intptr_t)arg;
|
|
printf(" [short-%d] running (id=%d)\n", (int)id, (int)tsCurrentId());
|
|
tsYield();
|
|
printf(" [short-%d] done\n", (int)id);
|
|
}
|
|
|
|
|
|
static void worker(void *arg) {
|
|
const char *name = (const char *)arg;
|
|
int32_t pri = tsGetPriority(tsCurrentId());
|
|
|
|
for (int32_t i = 0; i < 5; i++) {
|
|
printf(" [%s] step %d (priority %d)\n", name, (int)i, (int)pri);
|
|
tsYield();
|
|
}
|
|
printf(" [%s] finished\n", name);
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
printf("=== Cooperative Task Switching Demo ===\n\n");
|
|
|
|
if (tsInit() != TS_OK) {
|
|
printf("ERROR: failed to initialize task system\n");
|
|
return 1;
|
|
}
|
|
|
|
int32_t tHigh = tsCreate("high", worker, "high", 0, TS_PRIORITY_HIGH);
|
|
int32_t tNorm = tsCreate("normal", worker, "normal", 0, TS_PRIORITY_NORMAL);
|
|
int32_t tLow = tsCreate("low", worker, "low", 0, TS_PRIORITY_LOW);
|
|
int32_t tPauser = tsCreate("pauser", pauseTarget, NULL, 0, TS_PRIORITY_NORMAL);
|
|
|
|
if (tHigh < 0 || tNorm < 0 || tLow < 0 || tPauser < 0) {
|
|
printf("ERROR: failed to create tasks\n");
|
|
tsShutdown();
|
|
return 1;
|
|
}
|
|
|
|
printf("Created: high=%d normal=%d low=%d pauser=%d\n\n", (int)tHigh, (int)tNorm, (int)tLow, (int)tPauser);
|
|
|
|
// Phase 1: all tasks run, but high-priority tasks get more turns per round.
|
|
// Low (priority 0) gets 1 turn, normal (5) gets 6, high (10) gets 11.
|
|
// In the output you'll see "high" appearing much more frequently than
|
|
// "low", demonstrating the weighted fair-share scheduling.
|
|
printf("--- Phase 1: Priority scheduling ---\n");
|
|
for (int32_t i = 0; i < 6; i++) {
|
|
printf("[main] yield %d\n", (int)i);
|
|
tsYield();
|
|
}
|
|
|
|
// Phase 2: pause the pauser task so it stops being scheduled
|
|
printf("\n--- Phase 2: Pause 'pauser' ---\n");
|
|
tsPause((uint32_t)tPauser);
|
|
printf("[main] pauser state: %d (expect %d=paused)\n", tsGetState((uint32_t)tPauser), TaskStatePaused);
|
|
for (int32_t i = 0; i < 4; i++) {
|
|
printf("[main] yield %d (pauser is paused)\n", (int)i);
|
|
tsYield();
|
|
}
|
|
|
|
// Phase 3: resume pauser
|
|
printf("\n--- Phase 3: Resume 'pauser' ---\n");
|
|
tsResume((uint32_t)tPauser);
|
|
for (int32_t i = 0; i < 4; i++) {
|
|
printf("[main] yield %d\n", (int)i);
|
|
tsYield();
|
|
}
|
|
|
|
// Phase 4: boost low to the highest priority so it gets more turns
|
|
printf("\n--- Phase 4: Boost 'low' to highest ---\n");
|
|
tsSetPriority((uint32_t)tLow, TS_PRIORITY_HIGH + 5);
|
|
for (int32_t i = 0; i < 6; i++) {
|
|
printf("[main] yield %d\n", (int)i);
|
|
tsYield();
|
|
}
|
|
|
|
// Let remaining tasks finish
|
|
printf("\n--- Draining remaining tasks ---\n");
|
|
while (tsActiveCount() > 1) {
|
|
tsYield();
|
|
}
|
|
|
|
// Phase 5: dynamic creation with slot reuse.
|
|
// After all tasks from phases 1-4 have terminated, their slots are free.
|
|
// Creating new tasks should recycle those slots (IDs 1-4) rather than
|
|
// growing the array. Each "wave" creates 3 tasks, lets them finish,
|
|
// then creates 3 more -- the IDs should repeat across waves.
|
|
printf("\n--- Phase 5: Slot reuse ---\n");
|
|
printf("[main] active before: %u\n", (unsigned)tsActiveCount());
|
|
|
|
// Create short-lived tasks that will terminate and free their slots
|
|
for (int32_t wave = 0; wave < 3; wave++) {
|
|
printf("[main] wave %d: creating 3 tasks\n", (int)wave);
|
|
int32_t ids[3];
|
|
for (int32_t j = 0; j < 3; j++) {
|
|
int32_t tag = wave * 3 + j;
|
|
char name[TS_NAME_MAX];
|
|
snprintf(name, sizeof(name), "short-%d", (int)tag);
|
|
ids[j] = tsCreate(name, shortLived, (void *)(intptr_t)tag, 0, TS_PRIORITY_NORMAL);
|
|
printf("[main] created id=%d\n", (int)ids[j]);
|
|
}
|
|
|
|
// Let them all finish
|
|
while (tsActiveCount() > 1) {
|
|
tsYield();
|
|
}
|
|
printf("[main] wave %d complete, active=%u\n", (int)wave, (unsigned)tsActiveCount());
|
|
}
|
|
|
|
printf("\nActive tasks: %u\n", (unsigned)tsActiveCount());
|
|
printf("=== Demo complete ===\n");
|
|
|
|
tsShutdown();
|
|
return 0;
|
|
}
|