purrforce/taskmgr.c

93 lines
3.3 KiB
C
Raw Permalink Normal View History

2024-03-26 06:31:37 +00:00
#include "api.h"
#ifndef TASKMGR_MAX_TASKS
#define TASKMGR_MAX_TASKS 12
#endif
unsigned taskmgr_ms_till_next(void){
return 10;
}
static unsigned right_here=0;
struct run_tag {
int oneshot;/**<if true, free slot after first use (so setTimeout() rather than setInterval() basically)*/
int stack_up;/**<if true, run multiple times (max once per taskmgr_run() though) to catch up if we fall behind, else it is like dropframes*/
unsigned frequency_ms;
unsigned awaiting;/**<countdown*/
void(*cb)(void*ud);/**< this not being null means in use, if null, slot is free*/
void*ud;
char brief_descr[15+1];
unsigned deficit;/**<deposit left over change during stack_up logic*/
};
static unsigned time_passed(unsigned before,unsigned now){
unsigned timepassed=0;
if(now<before) {
timepassed = 0xfffffffful - before;
before=0;
}
timepassed += now-before;
return timepassed;
}
static struct run_tag run_tab[TASKMGR_MAX_TASKS];
/**@return true if there are stacked/immidiates left*/
static int one_loop(unsigned for_max_ms){
unsigned right_now = gettime_ms();
unsigned passed=0;
int i;
unsigned effective_passed;
int backed_up=0;
if(for_max_ms==0)for_max_ms=0xfffffffful;//0 means run at least once no matter what
/*--calc time passed--*/
if(right_now < right_here) {
/*--wrap around--*/
passed = right_now + (0xfffffffful - right_here);
} else passed = right_now - right_here;
/*--process all slots (active/inactive), some might be awaiting==0 so even if passed==0, still run--*/
for(i=0;i<TASKMGR_MAX_TASKS;++i){
if(run_tab[i].cb == NULL)continue;
effective_passed= passed + run_tab[i].deficit;
if(run_tab[i].awaiting < effective_passed) {
void(*task2run)(void*)=run_tab[i].cb;
void *taskParam = run_tab[i].ud;
effective_passed -= run_tab[i].awaiting;
if(effective_passed > 0 && effective_passed < run_tab[i].frequency_ms) {
run_tab[i].awaiting = run_tab[i].frequency_ms - effective_passed;
} else if(effective_passed > 0) {
backed_up=1;
if(run_tab[i].stack_up) {
/*--stack up logic--*/
run_tab[i].awaiting=0;
run_tab[i].deficit = effective_passed - run_tab[i].frequency_ms;
} else {
run_tab[i].awaiting=0;
}
}
if(run_tab[i].oneshot) {
run_tab[i].cb = NULL;
run_tab[i].ud = NULL;
}
task2run(run_tab[i].ud);
} else {
run_tab[i].awaiting -= effective_passed;
}
/*--deal with SLOW,LONG running callbacks vs for_max_ms "run for" issue--*/
if(time_passed(right_now,gettime_ms())>for_max_ms)break;
}
return backed_up;
}
void taskmgr_run(unsigned for_max_ms){
unsigned total_passed=0;
unsigned initial_moment = gettime_ms();
int backed_up = one_loop(for_max_ms);
if(for_max_ms > 0) {
while(backed_up) {
total_passed=time_passed(initial_moment,gettime_ms());
if(total_passed>=for_max_ms) break;
backed_up=one_loop(total_passed < for_max_ms ? for_max_ms - total_passed : 1);
}
}
}