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);
}