sylixos提供两种类型的RMS调度器接口,一个是sylixos内核自带接口,一个是POSIX标准接口,这两类实现方式不同,效果也略有差异。
POSIX标准接口
POSIX标准接口实现比较简洁,而且周期精度较高。
现简单来讲,就是利用CLOCK_MONOTONIC时间和nanosleep延时,所以时间精度最高能到纳秒。CLOCK_MONOTONIC时间是系统启动后的累计时间,是单调递增的,好比一个时间轴,唤醒点在时间轴上是等间隔的。
/*********************************************************************************************************
RMS 结构
*********************************************************************************************************/
typedef struct {
int PRMS_iStatus;
struct timespec PRMS_tsSave;
void *PRMS_pvPad[16];
} sched_rms_t;
/*********************************************************************************************************
** 函数名称: sched_rms_init
** 功能描述: 初始化 RMS 调度器
** 输 入 : prms RMS 调度器
** thread 需要调用 RMS 的线程.
** 输 出 : 是否初始化成功
*********************************************************************************************************/
int sched_rms_init (sched_rms_t *prms, pthread_t thread)
{
if (!prms) {
errno = EINVAL;
return (PX_ERROR);
}
if (API_ThreadSetSchedParam(thread, LW_OPTION_SCHED_FIFO,
LW_OPTION_RESPOND_IMMIEDIA)) {
errno = ESRCH;
return (PX_ERROR);
}
lib_bzero(prms, sizeof(sched_rms_t));
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: sched_rms_destroy
** 功能描述: 删除 RMS 调度器
** 输 入 : prms RMS 调度器
** 输 出 : 是否删除成功
*********************************************************************************************************/
int sched_rms_destroy (sched_rms_t *prms)
{
if (!prms) {
errno = EINVAL;
return (PX_ERROR);
}
prms->PRMS_iStatus = PRMS_STATUS_INACTIVE;
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: sched_rms_period
** 功能描述: 删除 RMS 调度器
** 输 入 : prms RMS 调度器
** period RMS 周期
** 输 出 : 0 表示正确
** error == EINTR 表示被信号激活.
*********************************************************************************************************/
int sched_rms_period (sched_rms_t *prms, const struct timespec *period)
{
struct timespec temp;
struct timespec etime;
if (!prms || !period) {
errno = EINVAL;
return (PX_ERROR);
}
switch (prms->PRMS_iStatus) {
case PRMS_STATUS_INACTIVE:
lib_clock_gettime(CLOCK_MONOTONIC, &prms->PRMS_tsSave); /* 获得当前时间 */
prms->PRMS_iStatus = PRMS_STATUS_ACTIVE;
return (ERROR_NONE);
case PRMS_STATUS_ACTIVE:
lib_clock_gettime(CLOCK_MONOTONIC, &temp);
__timespecSub2(&etime, &temp, &prms->PRMS_tsSave);
if (__timespecLeftTime(period, &etime)) { /* 执行时间超过周期 */
lib_clock_gettime(CLOCK_MONOTONIC, &prms->PRMS_tsSave); /* 获得当前时间 */
errno = EOVERFLOW;
return (PX_ERROR);
}
__timespecSub2(&temp, period, &etime);
/*
* 注意: 这里直接加上周期是为了让每次测算都是以一个固定周期律进行
* 提高周期精度. (不使用 lib_clock_gettime())
*/
__timespecAdd(&prms->PRMS_tsSave, period); /* 以确定周期运行 */
return (nanosleep(&temp, LW_NULL));
default:
errno = ENOTSUP;
return (PX_ERROR);
}
}
SylixOS内核自带接口
SylixOS内核自带接口是在内核实现的,利用的是系统心跳计数和休眠唤醒链表,时间精度是心跳周期。
RMS 对象也是系统资源,同其他系统资源一样通过单链表来进行分配和回收管理。
/*********************************************************************************************************
RATE MONO SCHEDLER
*********************************************************************************************************/
typedef struct {
LW_LIST_MONO RMS_monoResrcList; /* 空闲资源表 */
UINT8 RMS_ucType;
UINT8 RMS_ucStatus; /* 状态 */
ULONG RMS_ulTickNext; /* 激活时间 */
ULONG RMS_ulTickSave; /* 系统时间保存 */
PLW_CLASS_TCB RMS_ptcbOwner; /* 所有者 */
UINT16 RMS_usIndex; /* 下标 */
CHAR RMS_cRmsName[LW_CFG_OBJECT_NAME_SIZE]; /* 名字 */
} LW_CLASS_RMS;
typedef LW_CLASS_RMS *PLW_CLASS_RMS;
__KERNEL_EXT LW_CLASS_RMS _K_rmsBuffer[LW_CFG_MAX_RMSS]; /* RMS 缓冲区 */
__KERNEL_EXT LW_CLASS_OBJECT_RESRC _K_resrcRms; /* RMS 对象资源管理 */
/*********************************************************************************************************
** 函数名称: _Allocate_Rms_Object
** 功能描述: 从空闲 RMS 控件池中取出一个空闲 RMS
** 输 入 :
** 输 出 : 获得的 RMS 地址,失败返回 NULL
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_CLASS_RMS _Allocate_Rms_Object (VOID)
{
REGISTER PLW_LIST_MONO pmonoFree;
REGISTER PLW_CLASS_RMS prmsFree;
if (_LIST_MONO_IS_EMPTY(_K_resrcRms.RESRC_pmonoFreeHeader)) {
return (LW_NULL);
}
pmonoFree = _list_mono_allocate_seq(&_K_resrcRms.RESRC_pmonoFreeHeader,
&_K_resrcRms.RESRC_pmonoFreeTail);
/* 获得资源 */
prmsFree = _LIST_ENTRY(pmonoFree, LW_CLASS_RMS,
RMS_monoResrcList); /* 获得资源表容器地址 */
_K_resrcRms.RESRC_uiUsed++;
if (_K_resrcRms.RESRC_uiUsed > _K_resrcRms.RESRC_uiMaxUsed) {
_K_resrcRms.RESRC_uiMaxUsed = _K_resrcRms.RESRC_uiUsed;
}
return (prmsFree);
}
/*********************************************************************************************************
** 函数名称: _Free_Rms_Object
** 功能描述: 将 Rms 控制块交还缓冲池
** 输 入 :
** 输 出 :
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID _Free_Rms_Object (PLW_CLASS_RMS prmsFree)
{
REGISTER PLW_LIST_MONO pmonoFree;
pmonoFree = &prmsFree->RMS_monoResrcList;
_list_mono_free_seq(&_K_resrcRms.RESRC_pmonoFreeHeader,
&_K_resrcRms.RESRC_pmonoFreeTail,
pmonoFree);
_K_resrcRms.RESRC_uiUsed--;
}
/*********************************************************************************************************
** 函数名称: _RmsActive
** 功能描述: 第一次激活 RMS 并开始对线程执行时间进行测量 (进入内核并关中断后被调用)
** 输 入 :
** 输 出 :
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID _RmsActive (PLW_CLASS_RMS prms)
{
prms->RMS_ucStatus = LW_RMS_ACTIVE;
__KERNEL_TIME_GET_IGNIRQ(prms->RMS_ulTickSave, ULONG);
}
/*********************************************************************************************************
** 函数名称: _RmsGetExecTime
** 功能描述: 计算任务执行的时间 (进入内核并关中断后被调用)
** 输 入 :
** 输 出 :
** 全局变量:
** 调用模块:
*********************************************************************************************************/
ULONG _RmsGetExecTime (PLW_CLASS_RMS prms)
{
REGISTER ULONG ulThreadExecTime;
ULONG ulKernelTime;
__KERNEL_TIME_GET_IGNIRQ(ulKernelTime, ULONG);
ulThreadExecTime = (ulKernelTime >= prms->RMS_ulTickSave) ?
(ulKernelTime - prms->RMS_ulTickSave) :
(ulKernelTime + (__ARCH_ULONG_MAX - prms->RMS_ulTickSave) + 1);
return (ulThreadExecTime);
}
/*********************************************************************************************************
** 函数名称: _RmsInitExpire
** 功能描述: 开始进行时间等待 (进入内核并关中断后被调用)
** 输 入 :
** 输 出 :
** 全局变量:
** 调用模块:
*********************************************************************************************************/
ULONG _RmsInitExpire (PLW_CLASS_RMS prms, ULONG ulPeriod, ULONG *pulWaitTick)
{
PLW_CLASS_TCB ptcbCur;
REGISTER ULONG ulThreadExecTime; /* 计算线程执行时间 */
ULONG ulKernelTime;
LW_TCB_GET_CUR(ptcbCur);
__KERNEL_TIME_GET_IGNIRQ(ulKernelTime, ULONG);
ulThreadExecTime = (ulKernelTime >= prms->RMS_ulTickSave) ?
(ulKernelTime - prms->RMS_ulTickSave) :
(ulKernelTime + (__ARCH_ULONG_MAX - prms->RMS_ulTickSave) + 1);
if (ulThreadExecTime > ulPeriod) {
__KERNEL_TIME_GET_IGNIRQ(prms->RMS_ulTickSave, ULONG); /* 重新记录系统时钟 */
return (ERROR_RMS_TICK);
}
if (ulThreadExecTime == ulPeriod) {
*pulWaitTick = 0;
__KERNEL_TIME_GET_IGNIRQ(prms->RMS_ulTickSave, ULONG); /* 重新记录系统时钟 */
return (ERROR_NONE);
}
*pulWaitTick = ulPeriod - ulThreadExecTime; /* 计算睡眠时间 */
prms->RMS_ucStatus = LW_RMS_EXPIRED; /* 改变状态 */
prms->RMS_ptcbOwner = ptcbCur; /* 记录当前TCB */
__KERNEL_TIME_GET_IGNIRQ(prms->RMS_ulTickNext, ULONG);
prms->RMS_ulTickNext += *pulWaitTick; /* 计算下次到时时间 */
/* 自然溢出 */
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: _RmsEndExpire
** 功能描述: 一个周期完毕,等待下一个周期 (进入内核后被调用)
** 输 入 :
** 输 出 :
** 全局变量:
** 调用模块:
*********************************************************************************************************/
ULONG _RmsEndExpire (PLW_CLASS_RMS prms)
{
if (prms->RMS_ucStatus != LW_RMS_EXPIRED) { /* 被 cancel 或 删除了 */
return (ERROR_RMS_WAS_CHANGED); /* 被改变了 */
}
prms->RMS_ucStatus = LW_RMS_ACTIVE; /* 改变状态 */
__KERNEL_TIME_GET(prms->RMS_ulTickSave, ULONG); /* 重新记录系统时钟 */
if (prms->RMS_ulTickNext != prms->RMS_ulTickSave) { /* 是否 TIME OUT */
return (ERROR_THREAD_WAIT_TIMEOUT);
} else {
return (ERROR_NONE);
}
}
/*********************************************************************************************************
** 函数名称: API_RmsCreate
** 功能描述: 建立一个精度单调调度器
** 输 入 :
** pcName 名字
** ulOption 选项
** pulId Id 号
** 输 出 :
*********************************************************************************************************/
LW_OBJECT_HANDLE API_RmsCreate (CPCHAR pcName,
ULONG ulOption,
LW_OBJECT_ID *pulId)
{
REGISTER PLW_CLASS_RMS prms;
REGISTER ULONG ulIdTemp;
__KERNEL_MODE_PROC(
prms = _Allocate_Rms_Object();
); /* 退出内核 */
prms->RMS_ucType = LW_RMS_USED;
prms->RMS_ucStatus = LW_RMS_INACTIVE;
prms->RMS_ulTickNext = 0ul;
prms->RMS_ulTickSave = 0ul;
if (pcName) { /* 拷贝名字 */
lib_strcpy(prms->RMS_cRmsName, pcName);
} else {
prms->RMS_cRmsName[0] = PX_EOS; /* 清空名字 */
}
ulIdTemp = _MakeObjectId(_OBJECT_RMS,
LW_CFG_PROCESSOR_NUMBER,
prms->RMS_usIndex); /* 构建对象 id */
if (pulId) {
*pulId = ulIdTemp;
}
return (ulIdTemp);
}
/*********************************************************************************************************
** 函数名称: API_RmsPeriod
** 功能描述: 指定精度单调调度器开始按固定周期工作
** 输 入 :
** ulId RMS 句柄
** ulPeriod 程序段执行周期
** 输 出 :
*********************************************************************************************************/
ULONG API_RmsPeriod (LW_OBJECT_HANDLE ulId, ULONG ulPeriod)
{
INTREG iregInterLevel;
PLW_CLASS_TCB ptcbCur;
REGISTER PLW_CLASS_PCB ppcb;
REGISTER PLW_CLASS_RMS prms;
REGISTER UINT16 usIndex;
REGISTER ULONG ulErrorCode;
ULONG ulWaitTime;
usIndex = _ObjectGetIndex(ulId);
LW_TCB_GET_CUR_SAFE(ptcbCur); /* 当前任务控制块 */
prms = &_K_rmsBuffer[usIndex];
switch (prms->RMS_ucStatus) { /* 状态机 */
case LW_RMS_INACTIVE:
_RmsActive(prms); /* 启动 RMS */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
case LW_RMS_ACTIVE: /* 已将初始化完成 */
ulErrorCode = _RmsInitExpire(prms, ulPeriod, &ulWaitTime); /* 初始化“到期”数据 */
if (ulErrorCode) { /* 发生错误 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
_ErrorHandle(ulErrorCode);
return (ulErrorCode);
}
if (!ulWaitTime) { /* 时间刚刚好? */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
}
/*
* 当前线程开始睡眠
*/
ppcb = _GetPcb(ptcbCur);
__DEL_FROM_READY_RING(ptcbCur, ppcb); /* 从就绪表中删除 */
ptcbCur->TCB_ulDelay = ulWaitTime;
__ADD_TO_WAKEUP_LINE(ptcbCur); /* 加入等待扫描链 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核, 产生调度 */
/*
* 当前线程睡眠结束
*/
__KERNEL_MODE_PROC(
ulErrorCode = _RmsEndExpire(prms); /* 处理到期的 RMS */
);
_ErrorHandle(ulErrorCode);
return (ulErrorCode);
default: /* 转态机错误 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
_ErrorHandle(ERROR_RMS_NULL);
return (ERROR_RMS_NULL);
}
}
/*********************************************************************************************************
** 函数名称: API_RmsExecTimeGet
** 功能描述: 获得当前任务从调用 API_RmsPeriod() 函数到目前执行的时间,单位为: Tick.
** 输 入 :
** ulId RMS 句柄
** pulExecTime 运行时间
** 输 出 :
*********************************************************************************************************/
ULONG API_RmsExecTimeGet (LW_OBJECT_HANDLE ulId, ULONG *pulExecTime)
{
INTREG iregInterLevel;
REGISTER PLW_CLASS_RMS prms;
REGISTER UINT16 usIndex;
usIndex = _ObjectGetIndex(ulId);
prms = &_K_rmsBuffer[usIndex];
if (prms->RMS_ucStatus != LW_RMS_ACTIVE) { /* 状态错误 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
_ErrorHandle(ERROR_RMS_STATUS);
return (ERROR_RMS_STATUS);
}
*pulExecTime = _RmsGetExecTime(prms); /* 获得运行时间 */
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: API_RmsCancel
** 功能描述: 指定精度单调调度器停止工作
** 输 入 :
** ulId RMS 句柄
** 输 出 :
*********************************************************************************************************/
ULONG API_RmsCancel (LW_OBJECT_HANDLE ulId)
{
INTREG iregInterLevel;
REGISTER PLW_CLASS_RMS prms;
REGISTER UINT16 usIndex;
usIndex = _ObjectGetIndex(ulId);
prms = &_K_rmsBuffer[usIndex];
if (prms->RMS_ucStatus != LW_RMS_ACTIVE) { /* 状态错误 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
_ErrorHandle(ERROR_RMS_STATUS);
return (ERROR_RMS_STATUS);
}
prms->RMS_ucStatus = LW_RMS_INACTIVE; /* 失效 */
return (ERROR_NONE);
}