前言
在软件世界外面,超时是一个十分重要的概念。比方
● 以后线程临时休眠 1 秒钟,休眠完结后继续执行
● 每 5 秒钟采集一下 CPU 利用率
● 数据发送失败,2 秒钟当前再试一试
● 期待某种数据,但最多期待 50 毫秒
利用
// 将当前任务休眠若干 tick 数,tick 为工夫单位,常见值为 10 毫秒
LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick)
// 获取信号量 semHandle, 如果以后信号量不可用且 timeout 不为 0,则最多期待 timeout 所指定的工夫,在这段时间内如果信号量可用,则获取胜利,否则获取失败。
LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
// 从空的音讯队列读取音讯,或者向满的音讯队列写音讯时,如果 timeout 不为 0,则最多期待 timeout 指定的工夫,在这段时间内音讯队列可读或可写,则进行对应的读写并返回胜利,否则返回失败。
LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeOut)
LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeOut)
// 获取互斥锁,如果以后互斥锁被其它线程占用,则最多期待 timeout 指定的工夫,此工夫内其它线程开释了互斥锁并被本线程抢到则返回胜利,否则返回失败。
LITE_OS_SEC_TEXT UINT32 LOS_MuxPend(UINT32 muxHandle, UINT32 timeout)
// 期待其它线程向本线程发送事件,最多期待 timout 指定的工夫
LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeOut)
上述这些函数都是超时概念在 OpenHarmony 中 liteos_m 内核里的具体利用。
具体而言,liteos_m 内核如何实现这个超时逻辑的呢,咱们接着看下一个章节
原理
如上图所示。在时间轴上,黄色圆点代表须要进行某种操作的工夫点,而绿色圆点为查看零碎是否有超时事件须要解决的查看工夫点。零碎周期性的进行查看 (周期单位为 tick)。在 2 个检查点之间可能有超时事件,也可能无超时事件。
例如,依据上图展现的状况。以后在第一个检查点,发现了 2 个超时事件,那么这次解决这 2 个超时事件;随着工夫流逝,箭头来到第 2 个检查点,又发现 2 个超时事件,持续解决;在第 3 个检查点时,本段时间内无超时事件,所以是空操作。后续的查看以此类推。
代码实现
为了准确性以及时效性,本文选取了最新的版本的代码来形容。上述检查点和工夫点由链表构造进行定义。具体在 kernel/liteos_m/include/los_sortlink.h 文件中。
因为原理图中的超时事件产生是非平均的,且存在有序顺次产生的逻辑,所以,这些信息被保护在双向链表中 (对删除操作更敌对)。
SortLinkList 代表了链表中的每一个须要处理事件的工夫点,responseTime 代表具体的工夫值(从启机开始的 cpu cycle 数目)。SortLinkAttribute 代表链表的头部(哑头)。从名称也能看出,这个是一个排序的双向链表,排序的根据即 responseTime 这个数值。
须要留神的一个细节是:零碎反对 2 个链表,其中一个是 TASK 链表,另一个是 SWTMR 链表。这 2 个链表实现形式统一,次要区别是,SWTMR 链表超时解决是唤醒 swtmr 线程来解决超时事件,而 task 链表唤醒的是每个具体的 task(sleep,ipc 超时等场景)。应用 swtmr 线程来解决若干超时的机制,能够无效缩小零碎须要的线程数目,从而节俭系统资源的占用。
总结
本文形容了超时逻辑在 OpenHarmony 中的实现,从原理,应用以及具体实现细节上进行了详尽探讨,并演绎整顿了以后这种实现形式所带来的好处。