一、基于事件的任务调度器
1.事件任务调度器数据结构
typedef unsigned char bit_t;
typedef unsigned char u1_t;
typedef signed char s1_t;
typedef unsigned short u2_t;
typedef short s2_t;
typedef unsigned int u4_t;
typedef int s4_t;
typedef unsigned long long u8_t;
typedef long long s8_t;
typedef unsigned int uint;
typedef const char* str_t;
typedef s4_t ostime_t;
struct osjob_t;
typedef void (*osjobcb_t) (struct osjob_t*);
struct osjob_t {
struct osjob_t* next;//链表
ostime_t deadline;//任务执行事件
osjobcb_t func; //任务函数
};
TYPEDEF_xref2osjob_t;
// RUNTIME STATE 用于记录当前即时任务及计划任务;即时任务添加进即时任务链表后即时运行;计划任务则为计时时间到则运行。
static struct {
osjob_t* scheduledjobs; /* 计划任务 */
osjob_t* runnablejobs; /* 即时任务 */
} OS;
任务的添加和删除工作,都以回调的形式完成。
2.OS初始化及时基
/* 系统初始化,如定时器、中断等 */
void os_init () {
/* hal_init(); */
}
/* 获取系统时间,需要消耗MCU一个定时器来实现OS系统时基 */
ostime_t os_getTime () {
return hal_ticks();
}
3.任务及任务链表
任务链表分两个,一个为即时任务链表,一个为定时任务链表;删除时需要从两个表中寻找并删除。
从任务链表中删除指定任务
static u1_t unlinkjob (osjob_t** pnext, osjob_t* job) {
for( ; *pnext; pnext = &((*pnext)->next)) {
if(*pnext == job) { // unlink
*pnext = job->next;
return 1;
}
}
return 0;
}
// clear scheduled job
void os_clearCallback (osjob_t* job) {
hal_disableIRQs();
unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job);
hal_enableIRQs();
}
添加任务至即时任务链表
// schedule immediately runnable job
void os_setCallback (osjob_t* job, osjobcb_t cb) {
osjob_t** pnext;
hal_disableIRQs();
// remove if job was already queued
os_clearCallback(job);
// fill-in job
job->func = cb;
job->next = NULL;
// add to end of run queue
for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
*pnext = job;
hal_enableIRQs();
}
添加任务至计划任务链表
// schedule timed job
void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
osjob_t** pnext;
hal_disableIRQs();
// remove if job was already queued
os_clearCallback(job);
// fill-in job
job->deadline = time;
job->func = cb;
job->next = NULL;
// insert into schedule
for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
// enqueue before next element and stop
job->next = *pnext;
break;
}
}
*pnext = job;
hal_enableIRQs();
}
4.任务后台
优先从即时任务中提取任务运行,即时任务运行完成后,才会再运行计划任务。所以,计划任务一般给对实时性无要求的任务,有时候为了保证即时任务,需要将一些任务设定为计划任务,如:点灯任务。
// execute jobs from timer and from run queue
void os_runloop () {
while(1) {
osjob_t* j = NULL;
hal_disableIRQs();
// check for runnable jobs
if(OS.runnablejobs) {
j = OS.runnablejobs;
OS.runnablejobs = j->next;
} else if(OS.scheduledjobs
&& hal_checkTimer(OS.scheduledjobs->deadline)) {
// check for expired timed jobs
j = OS.scheduledjobs;
OS.scheduledjobs = j->next;
} else { // nothing pending
hal_sleep(); // wake by irq (timer already restarted)
}
hal_enableIRQs();
if(j) { // run job callback
j->func(j);
}
}
}
5.任务调度实例
static void immediatelyfunc (osjob_t* j)
{
/*TODO*/
}
static void scheduledfunc (osjob_t* j)
{
/*TODO*/
}
// application entry point
int main () {
osjob_t immediatelyjob;
osjob_t scheduledjob;
// initialize runtime env
os_init();
// setup initial job 添加即时任务
os_setCallback(&immediatelyjob, immediatelyfunc);
// execute scheduled jobs and events
os_setTimedCallback (&scheduledjob, 1000, scheduledfunc)
os_runloop();// (not reached)
return 0;
}