📄 kernel.c
字号:
#include <limits.h>
#include "itron.h"
#include "config.h"
#include "kernel.h"
#include "target.h"
T_TCB TCB[TSKID_MAX + 1]; //任务的TCB//
T_TCB *RDQ[TSKPRI_MAX + 1]; //就绪队列的TCB指针//
T_SEM SEM[SEMID_MAX + 1]; //信号量//
T_MBX MBX[MBXID_MAX + 1]; //邮箱//
T_TIM TIM; //系统时间//
T_TCB *RUNTCB; //正在运行任务的TCB指针//
INT *USP; //指向任务堆栈指针的指针//
INT DELAY; //是否处在调度器延时状态//
INT INEST; //中断嵌套次数//
INT SYSSTAT; //系统状态(调度器加锁,CPU加锁...)//
INT UIPL; //中断允许级别//
void _dly_tsk(DLYTIME dlytim)
{
//在中断处理和分发器禁止状态使用该系统调用是无效的//
if (INEST>0 || SYSSTAT >= TSS_DDSP)
{
*USP = E_CTX; //返回系统调用无效//
return;
}
//延时时间小于最小延时时间则返回参数错误//
if (dlytim < TMO_POL)
{
*USP = E_PAR; //参数错误//
return;
}
//延时时间等于最小延时时间则正常返回//
if (dlytim == TMO_POL)
{
*USP = E_OK; //正常返回//
return;
}
RUNTCB->tmout = TIM.time + dlytim; //设定唤醒的时间//
RUNTCB->tskstat = TTS_WAI; //将当前任务状态改为等待状态//
RUNTCB->tskwait = TTW_DLY; //等待模式为Delay//
del_que(&RDQ[RUNTCB->tskpri], RUNTCB); //将任务TCB从Ready队列中删除//
add_que(&(TIM.head), RUNTCB); //将任务TCB添加到邮箱等待队列中//
dispatch(); //激活分发器//
}
//系统定时器处理//
void timer(void)
{
TIM.time ++; //系统定时器计数器//
//如果有等待的任务则判断是否到时//
if (TIM.head != NULL)
{
T_TCB *tcb = TIM.head;
T_TCB *nexttcb = TIM.head;
T_TCB *endtcb = tcb->prev;
do
{
tcb = nexttcb;
nexttcb = tcb->next;
//如果时间到则唤醒任务//
if (tcb->tmout == TIM.time)
{
tcb->tskstat = TTS_RDY; //任务状态设为就绪状态//
del_que(&(TIM.head), tcb); //将任务TCB从等待队列中删除//
add_que(&RDQ[tcb->tskpri], tcb); //将任务TCB添加到Ready队列中//
*(tcb->sp) = E_OK; //等待任务的返回值为正常返回//
DELAY = SET; //设置为分发器延时状态//
}
}while (tcb != endtcb);
}
}
//从邮箱中接收邮件//
void _rcv_msg(void **ppk_msg, ID mbxid)
{
T_MBX *mbx;
//在中断通知处理中或者CPU锁定状态不允许禁止分发器//
if (INEST > 0 || SYSSTAT >= TSS_DDSP)
{
*USP = E_CTX; //返回系统调用无效//
return;
}
//超过邮箱ID的最大值则返回邮箱ID不存在//
if (mbxid > MBXID_MAX)
{
*USP = E_NOEXS; //邮箱ID不存在//
return;
}
mbx = &MBX[mbxid]; //根据邮箱ID获取邮箱//
//邮件计数器值大于0则获取邮件
if (mbx->msgcnt > 0)
{
*ppk_msg = *(mbx->msghead); //获取邮件//
//将邮件从邮件对列中删除//
if (++(mbx->msghead) >= (msgq_tbl[mbxid]+msgsiz_tbl[mbxid]))
{
mbx->msghead = msgq_tbl[mbxid];
}
mbx->msgcnt--; //邮件计数器递减//
*USP = E_OK; //正常返回//
return;
}
else
{
RUNTCB->arg = ppk_msg;
RUNTCB->tskstat = TTS_WAI; //任务状态设置为等待状态//
RUNTCB->tskwait = TTW_MBX; //等待方式为等待邮件//
del_que(&RDQ[RUNTCB->tskpri], RUNTCB); //将任务TCB从Ready队列中删除//
add_que(&(mbx->head), RUNTCB); //将任务TCB添加到邮箱等待队列中//
dispatch(); //激活分发器//
return;
}
}
//发送邮件//
void _snd_msg(ID mbxid, void *pk_msg)
{
T_MBX *mbx;
//超过邮箱ID的最大值则返回邮箱ID不存在//
if (mbxid >MBXID_MAX)
{
*USP = E_NOEXS; //邮箱ID不存在//
return;
}
mbx = &MBX[mbxid]; //根据邮箱ID获取邮箱//
//如果没有任务在等待邮箱,则将邮件加入邮件队列//
if (mbx->head == NULL)
{
//如果邮件计数器大于邮箱邮件最大值则发生溢出//
if (mbx->msgcnt >= msgsiz_tbl[mbxid])
{
*USP = E_QOVR; //邮箱计数器溢出//
return;
}
else
{
*(mbx->msgtail) = pk_msg; //将邮件加入邮件队列//
if (++(mbx->msgtail) >= (msgq_tbl[mbxid]+msgsiz_tbl[mbxid]))
{
mbx->msgtail = msgq_tbl[mbxid];
}
mbx->msgcnt++; //邮件计数器递增//
*USP = E_OK; //正常返回//
return;
}
}
else
{
T_TCB *tcb = mbx->head; //取得第一个等待邮件的任务//
*(tcb->arg) = pk_msg; //邮件传递给任务//
tcb->tskstat = TTS_RDY; //将任务状态设置为Ready状态//
del_que(&(mbx->head), tcb); //将任务TCB从等待邮件队列删除//
add_que(&RDQ[tcb->tskpri], tcb); //任务TCB添加到Ready队列中//
*(tcb->sp) = E_OK; //等待任务继续运行时的返回值为正常返回//
*USP = E_OK; //中在运行的任务正常返回//
dispatch(); //激活分发器//
return;
}
}
//中断通知处理中发送邮件//
ER _isnd_msg(ID mbxid, void *pk_msg)
{
T_MBX *mbx;
//超过邮箱ID的最大值则返回邮箱ID不存在//
if (mbxid >MBXID_MAX)
{
return E_NOEXS; //邮箱ID不存在//
}
mbx = &MBX[mbxid]; //根据邮箱ID获取邮箱//
//如果没有任务在等待邮箱,则将邮件加入邮件队列//
if (mbx->head == NULL)
{
//如果邮件计数器大于邮箱邮件最大值则发生溢出//
if (mbx->msgcnt >= msgsiz_tbl[mbxid])
{
return E_QOVR; //邮箱计数器溢出//
}
else
{
*(mbx->msgtail) = pk_msg; //将邮件加入邮件队列//
if (++(mbx->msgtail) >= (msgq_tbl[mbxid]+msgsiz_tbl[mbxid]))
{
mbx->msgtail = msgq_tbl[mbxid];
}
mbx->msgcnt++; //邮件计数器递增//
return E_OK; //正常返回//
}
}
else //如果有任务等待邮件则将邮件传递给等待的任务//
{
T_TCB *tcb = mbx->head; //取得第一个等待邮件的任务//
*(tcb->arg) = pk_msg; //邮件传递给任务//
tcb->tskstat = TTS_RDY; //将任务状态设置为Ready状态//
del_que(&(mbx->head), tcb); //将任务TCB从等待邮件队列删除//
add_que(&RDQ[tcb->tskpri], tcb); //任务TCB添加到Ready队列中//
*(tcb->sp) = E_OK; //等待任务继续运行时的返回值为正常返回//
DELAY = SET; //设置分发器延时状态//
return E_OK; //正常返回//
}
}
//无等待获取邮件//
ER _prcv_msg(void **ppk_msg, ID mbxid)
{
T_MBX *mbx;
//超过邮箱ID的最大值则返回邮箱ID不存在//
if (mbxid > MBXID_MAX)
{
return E_NOEXS; //邮箱ID不存在//
}
mbx = &MBX[mbxid];
//邮件计数器值大于0则获取邮件
if (mbx->msgcnt > 0)
{
*ppk_msg = *(mbx->msghead); //获取邮件//
//将邮件从邮件对列中删除//
if (++(mbx->msghead) >= (msgq_tbl[mbxid]+msgsiz_tbl[mbxid]))
{
mbx->msghead = msgq_tbl[mbxid];
}
mbx->msgcnt--; //邮件计数器递减//
return E_OK; //正常返回//
}
else
{
return E_TMOUT; //轮询检测失败//
}
}
//获取信号量//
void _wai_sem(ID semid)
{
T_SEM *sem;
//在中断通知处理中或者CPU锁定状态不允许禁止分发器//
if (INEST > 0 || SYSSTAT >= TSS_DDSP)
{
*USP = E_CTX; //返回系统调用无效//
return;
}
//超过信号量的最大值//
if (semid > SEMID_MAX)
{
*USP = E_NOEXS; //信号量ID不存在//
return;
}
sem = &SEM[semid];
//如果信号量计数器大于0,则获得信号量//
if (sem->cnt > 0)
{
sem->cnt --; //信号量计数器递减//
*USP = E_OK; //正常返回//
return;
}
else //信号量计数器等于0,进入等待状态//
{
RUNTCB->tskstat = TTS_WAI; //任务状态设置为等待状态//
RUNTCB->tskwait = TTW_SEM; //等待方式为等待信号量//
del_que(&RDQ[RUNTCB->tskpri], RUNTCB); //将任务TCB从Ready队列中删除//
add_que(&(sem->head), RUNTCB); //将任务TCB添加到信号量等待队列中//
dispatch(); //激活分发器//
return;
}
}
//释放信号量//
void _sig_sem(ID semid)
{
T_SEM *sem;
//超过信号量的最大值//
if (semid > SEMID_MAX)
{
*USP = E_NOEXS; //信号量ID不存在//
return;
}
sem = &SEM[semid];
//如果没有任务在等待信号量,信号量计数器的值仅仅是简单地加1//
if (sem->head == NULL)
{
if (sem->cnt < INT_MAX) //判断信号量计数器是否溢出//
{
sem->cnt ++; //信号量计数器递增//
*USP = E_OK; //正常返回//
return;
}
else
{
*USP = E_QOVR; //信号量计数器溢出//
return;
}
}
else
{
T_TCB *tcb = sem->head; //获得等待信号量的第一个任务的TCB//
tcb->tskstat = TTS_RDY; //将状态设置为Ready状态//
del_que(&(sem->head), tcb); //从等待信号量队列中删除该TCB//
add_que(&RDQ[tcb->tskpri], tcb); //将该TCB添加到Ready对列中//
*(tcb->sp) = E_OK; //等待信号量的任务继续运行时的返回值为正常返回//
*USP = E_OK; //正在运行的任务为正常返回//
dispatch(); //激活分发器//
return;
}
}
//中断通知中释放信号量//
ER _isig_sem(ID semid)
{
T_SEM *sem;
//超过信号量的最大值//
if (semid > SEMID_MAX)
{
return E_NOEXS; //信号量ID不存在//
}
sem = &SEM[semid];
//如果没有任务在等待信号量,信号量计数器的值仅仅是简单地加1//
if (sem->head == NULL)
{
if (sem->cnt < INT_MAX) //判断信号量计数器是否溢出//
{
sem->cnt ++; //信号量计数器递增//
return E_OK; //正常返回//
}
else
{
return E_QOVR; //信号量计数器溢出//
}
}
else
{
T_TCB *tcb = sem->head; //获得等待信号量的第一个任务的TCB//
tcb->tskstat = TTS_RDY; //将状态设置为Ready状态//
del_que(&(sem->head), tcb); //从等待信号量队列中删除该TCB//
add_que(&RDQ[tcb->tskpri], tcb); //将该TCB添加到Ready对列中//
*(tcb->sp) = E_OK; //等待信号量的任务继续运行时的返回值为正常返回//
DELAY = SET; //设置分发器延时状态//
return E_OK; //正常返回//
}
}
//无等待获得信号量//
ER _preq_sem(ID semid)
{
T_SEM *sem;
//超过信号量的最大值//
if (semid > SEMID_MAX)
{
return E_NOEXS; //信号量ID不存在//
}
sem = &SEM[semid]; //通过ID获得对应的信号量//
//如果信号量计数器值大于零则获得该信号量,正常返回//
if (sem->cnt > 0)
{
sem->cnt --; //信号量计数器值递减//
return E_OK; //正常返回//
}
else
{
return E_TMOUT; //轮询检测失败//
}
}
ER _dis_dsp(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -