RTOS微内核设计之二: 系统接口定义

johnsonest 2009-05-15 11:00:27
增一分则肥,减一分则瘦

------《登徒子賦》

( 本文参照了ose操作系统的API设计,实际上,该操作系统是非常符合我前面提到的设计原则。准确的说,应该是这样:本人在没有了解OSE的时候,酝酿了前文提出的若干设计准则,在接触了ose后,进一步完善了哪些设计准则。另,本文是从应用程序的角度列举了操作系统API,还有一些比较少用的接口,比如调试接口在这里没有列出)

秉承上文提到的内核架构和设计思想,我们可以试着来定义一套相适应的操作系统应用接口集(API),这里提到的接口的概念,包括数据类型,常量,函数调用等.

为了便于描述,把API设计的原则列举如下:

1)最简原则:所谓"增一分则肥,减一分则瘦",这不仅指接口的数目,也指形参个数

2)封装原则:在接口里不能出现具体内核数据结构类型,均使用通用数据类型.

3)操作系统必须负责分配/销毁内核对象(这个工作不要由应用来做)

4)错误码的返回:若非错误会改变应用程序执行流,不要返回错误码。可以提供错误查询接口和设置错误处理方法

<一>基本数据类型定义

很自然的,我们得从基本数据类型开始.基本数据类型应该都是抽象数据类型,只涉及类型数据宽度和符号属性,不涉及内核实现.
typedef unsigned char UINT8;
typedef signed char SINT8;
typedef unsigned short UINT16;
typedef signed short SINT16;
typedef unsigned long UINT32;
typedef signed long SINT32;
typedef unsigned long long UINT64;
typedef signed long long SINT64;
//additional type
typedef UINT32 BOOL;
typedef UINT32 HANDLE;
typedef UINT32 VOID;
//standard message
typedef struct
{
UINT32 msgId;

}T_MSG;
typedef int (TASK_ENTRY)(VOID*pParam);
enum TASK_TYPE
{
TASK_TYPE_NORMAL;
TASK_TYPE_INTRRUPT;
TASK_TYPE_CYCLE;
};



这里值得说的是消息结构的定义,这也是一个抽象数据类型,不依赖于任何操作系统实现.对应用来说,消息包含两部分:消息ID和消息数据,消息数据的定义属于应用的范畴,这里不加定义.至于消息ID,是为了实现消息接收过滤功能。参见第三小节;

<二>任务操作接口定义

  (1)创建任务
HANDLE Create_Task( const SINT*name,
enum TASK_TYPE ttype,
TASK_ENTRY* entry,
VOID*param,
UINT32 stack_size,
UINT32 priority,
UINT32 time_slice)
函数说明:创建一个任务,初始任务处于停止状态,等待启动。
参数说明:
name: 任务名称
ttype: 任务类型,见TASK_TYPE 类型定义
entry: 任务入口
param: 任务入口参数
stack_size: 任务栈大小
priority: 任务优先级
time_slice: 时间片,应用于周期性任务
返回值:
0: 创建任务失败
任务句柄:创建成功的任务句柄



(2)销毁任务

    VOID Destroy_Task(HANDLE hTask)

(3)启动任务

VOID Start_Task(HANDLE hTask)

  (4)停止任务

    VOID Stop_Task(HANDLE hTask)

(5)获得当前任务

    HANDLE Current_Task(VOID)

(6)设置任务优先级

UINT32 Set_Priority(HANDLE hTask,UINT32 new_priority)

(7)获得任务优先级

UINT32 Get_Priority(HANDLE hTask)

(8)睡眠任务

VOID Sleep(UINT32 time)

(9) 唤醒任务

VOID Wakeup(HANDLE hTask)

<三>消息操作

   首先引入一个概念:消息过滤

   消息过滤就是在接收消息的时候,指定要接收的消息的约束条件,只有满足这些条件的消息才被返回.

   过滤器结构如下: UINT32 filter[]={n,msg1,msg2,...,msgn};

过滤器模式如下: 0:FILTER_MODE_AND

1:FILTER_MODE_OR

 其次,这些函数操作消息的时候,通常传入的都是消息指针的指针.这样当某个消息发送后(或者消息释放后),该消息指针将会被置空,防止程序继续访问已经发送的消息.这很重要,举个例子,你给某人寄信,一旦信件寄出,信件就不属于你了,你也没有机会修改信件,也不能取消.

通过这样的设计,可以把当前主流RTOS支持的各种任务间通信机制,合并成一种。

(1)创建消息

VOID* Create_Message(UINT32 size,UINT32 msgId)

(2) 释放消息

VOID Free_Message(T_MSG**ppMsg)

  (3) 向任务发送消息

SINT32 Send_Message(T_MSG**ppMsg,HANDLE hTask,SINT32 timeout)

当函数返回时。将会返回错误码,*ppMsg==NULL,从而阻止程序访问已经发送了的消息。

timeout=0,函数不阻塞,立即返回

timeout=-1,函数阻塞,直到消息发送完毕

其他情况,函数阻塞指定的时间。

(4)从当前任务接收消息

T_MSG* Reiceive_Message(UINT32 filter[],UINT32 mode,UINT32 timeout)

返回当前任务收到的满足过滤器条件的消息。

当mode=FILTER_MODE_AND时,只有当过滤器指定的消息全都收到,函数才返回消息链表。

当mode=FILTER_MODE_OR时,收到任何一个过滤器中的消息,函数就返回

当过滤器为空时,收到任何消息灰返回。

timeout的含义与Send_Message中的类似

(5)获得消息所用的内存尺寸大小

UINT32 Get_MessageSize(T_MSG*ppMsg)



(6)获得指定消息的发送方任务

HANDLE Get_MessageSender(T_MSG*pMsg)

(7)获得消息链表中的下一个消息,当收到消息链时有用

T_MSG* Get_MessageNext(T_MSG*ppMsg)

<四> 互斥信号量

这个名字叫得有点怪,我们将要讨论的确实是一个信号量,但是用于临界区保护.传统信号量的通信功能,已经被<第三节消息操作>所替代.

(1)创建信号量

HANDLE Create_Semaphore(const SINT8 *name, UINT32 iniCnt)

如果创建的是临界区,iniCnt通常设置为1

(2)销毁信号量

VOID Destroy_Semaphore(HANDLE hSemaphore)

(3)等待信号量

SINT32 Wait_Semaphore(HANDLE hSemaphore)

将会返回错误码

(4)释放信号量

SINT32 Give_Semaphore(HANDLE hSemaphore)

将会返回错误码

<五> 定时器

这里的定时器,指的是以系统始终为驱动源,定时精度为tick级别(具体tick单位为多少,取决于系统配置),能满足大多数定时精度要求不高的应用需求的“软定时器”。高精度定时通常直接采用SOC上的硬定时器,不在本文讨论范围。以下说的定时器,专指软定时器。

定时器大多是在应用任务中设置,传统的设计采用回调函数的方式来处理定时器超时事件。每个定时器都有不同的回调函数,回调函数不在应用任务上下文中执行,大多数在内核中执行,牵涉到应用共享数据的任务(线程)安全问题。所以很多应用得自己实现一套应用级定时器。

操作系统应该实现这些功能,提供这种定时服务,让工程师专职于应用设计。以下列出了 必要的API借口。

(1)启动定时器

BOOL Set_Timer(UINT32 ms,UINT32 timeType,UINT32 timeId)

参数说明:

ms: 定时器间隔,毫秒为单位

timeType:定时器类型。0表示一次性定时器,1表示周期性定时器

timeId:定时器标识,应用自定义。该值将作为超时消息参事发送给应用。

(2)停止定时器

BOOL Stop_Timer(UINT32 timeId)

(3)获得系统时钟tick数

UINT32 Get_SystemTick(VOID)

(4)设置系统时钟tick数

BOOL Set_SystemTick(UINT32 ticks)

(5)tick与毫秒的转换

UINT32 Micros2Ticks(UINT32 ms)

UINT32 Ticks2Micros(UINT32 ticks)

<六> 中断

中断处理函数类型定义:

typedef VOID (*T_ISR)(UINT32 vec)

(1)关联中断

T_ISR Connect_ISR(UINT32 vec,T_ISR routine)

该函数将中断处理函数和中断向量关联起来,并返回原来的中断函数

(2) 关闭中断

UINT32 Disable_Interrupt(UINT32 level)

level=0xffffffff,表示关闭所有中断

(3)使能中断

VOID Enable_Interrupt(UINT32 level)

level=0xffffffff,表示使能所有中断

<七> 调度器

VOID Scheduler_Lock():禁止调度,但是不禁止中断

VOID Scheduler_UnLock():解禁调度。

<八>内存管理

(1)创建内存池

HANDLE Create_MemPool(UINT8 *memStart,UINT32 poolSize,UINT32 poolType,UINT32 fixSize)

参数说明:

memStart:内存池开始地址(但是不是用户使用能分配的内存起始地址)

poolSize:内存池大小,一字节为单位

poolType:0,动态尺寸内存池,1表示固定尺寸内存池

fixSize:如果poolType=1,则表示固定块的大小。其他情况,忽略。

(2)销毁内存池

VOID Destroy_MemPool(HANDLE hPool)

(3)分配内存

VOID* MemMalloc(HANDLE hPool,UINT32 size)

如果内存池是固定大小类型,size被忽略

(4)释放内存

VOID MemFree(VOID*pMem)

鉴于内存使用的多样性,工程师可以使用上述接口,封装成满足要求的库接口。

<九>错误处理

(1)设置捕捉错误

VOID Set_Trap(T_ERR_HANDLER errHandler)

(2) 捕捉错误

VOID Trap(UINT32 errNo)



<十>其他接口

系统配置

VOID SysConfig(const VOID* staticConfig)

VOID*GetSysConfig(VOID)

系统环境创建

VOID SetupSystem(const UINT8* mem,UINT32 size)

系统启动

VOID SysStart()

(to be continue.....)








...全文
392 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
学习一下

567

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧