鸿蒙内核源码分析之时钟节拍的实现方式

时钟概念
时间是非常重要的概念,我们整个学生阶段有个东西很重要,就是校园铃声. 它控制着上课,下课,吃饭,睡觉的节奏.没有它学校的管理就乱套了,老师拖课想拖多久就多久,那可不行,下课铃声一响就是在告诉老师时间到了,该停止了让学生happy去了.
操作系统也一样,需要通过时间来规范其任务的执行,操作系统中最小的时间单位是时钟节拍 (os tick)。任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳,中断之间的时间间隔取决于不同的应用,一般是 1ms–100ms,时钟节拍率越快,系统的实时响应越快,但是系统的额外开销就越大,从系统启动开始计数的时钟节拍数称为系统时间。
在鸿蒙内核中,时钟节拍的长度可以根据 loscfg_base_core_tick_per_second 的定义来调整,等于 1/loscfg_base_core_tick_per_second 秒。
时钟节拍的实现方式
时钟节拍由配置为中断触发模式的硬件定时器产生,当中断到来时,将调用一次:void ostickhandler(void),通知操作系统已经过去一个系统时钟;不同硬件定时器中断实现都不同,
/** * @ingroup los_config * number of ticks in one second */#ifndef loscfg_base_core_tick_per_second#define loscfg_base_core_tick_per_second 100 //默认每秒100次触发,当然这是可以改的#endif 每秒100个tick,时间单位为10毫秒, 即每秒调用时钟中断处理程序100次.
/* * description : tick interruption handler *///节拍中断处理函数 ,鸿蒙默认10ms触发一次lite_os_sec_text void ostickhandler(void){ //... ostimeslicecheck();//进程和任务的时间片检查 ostaskscan(); /* task timeout scan *///任务扫描#if (loscfg_base_core_swtmr == yes) osswtmrscan();//定时器扫描,看是否有超时的定时器#endif} 它主要干了三件事情
第一:检查当前任务的时间片,任务执行一次分配多少时间呢?答案是2个时间片,即 20ms.
#ifndef loscfg_base_core_timeslice_timeout#define loscfg_base_core_timeslice_timeout 2 //2个时间片,20ms#endif//检查进程和任务的时间片,如果没有时间片了直接调度lite_os_sec_text void ostimeslicecheck(void){ lostaskcb *runtask = null; losprocesscb *runprocess = oscurrprocessget();//获取当前进程 if (runprocess->policy != los_sched_rr) {//进程调度算法是否是抢占式 goto sched_task;//进程不是抢占式调度直接去检查任务的时间片 } if (runprocess->timeslice != 0) {//进程还有时间片吗? runprocess->timeslice--;//进程时间片减少一次 if (runprocess->timeslice == 0) {//没有时间片了 los_schedule();//进程时间片用完,发起调度 } }sched_task: runtask = oscurrtaskget();//获取当前任务 if (runtask->policy != los_sched_rr) {//任务调度算法是否是抢占式 return;//任务不是抢占式调度直接结束检查 } if (runtask->timeslice != 0) {//任务还有时间片吗? runtask->timeslice--;//任务时间片也减少一次 if (runtask->timeslice == 0) {//没有时间片了 los_schedule();//任务时间片用完,发起调度 } }} 第二:扫描任务,主要是检查被阻塞的任务是否可以被重新调度
lite_os_sec_text void ostaskscan(void){ sortlinklist *sortlist = null; lostaskcb *taskcb = null; bool needschedule = false; uint16 tempstatus; los_dl_list *listobject = null; sortlinkattribute *tasksortlink = null; tasksortlink = &ospercpuget()->tasksortlink;//获取任务的排序链表 tasksortlink->cursor = (tasksortlink->cursor + 1) & os_tsk_sortlink_mask; listobject = tasksortlink->sortlink + tasksortlink->cursor;//只处理这个游标上的链表,因为系统对超时任务都已经规链表了. //当任务因超时而挂起时,任务块处于超时排序链接上,(每个cpu)和ipc(互斥锁、扫描电镜等)的块同时被唤醒 /*不管是超时还是相应的ipc,它都在等待。现在使用synchronize sortlink precedure,因此整个任务扫描需要保护,防止另一个核心同时删除sortlink。 * when task is pended with timeout, the task block is on the timeout sortlink * (per cpu) and ipc(mutex,sem and etc.)'s block at the same time, it can be waken * up by either timeout or corresponding ipc it's waiting. * * now synchronize sortlink preocedure is used, therefore the whole task scan needs * to be protected, preventing another core from doing sortlink deletion at same time. */ los_spinlock(&g_taskspin); if (los_listempty(listobject)) { los_spinunlock(&g_taskspin); return; } sortlist = los_dl_list_entry(listobject->pstnext, sortlinklist, sortlinknode);//拿本次tick对应链表的sortlinklist的第一个节点sortlinknode rollnum_dec(sortlist->idxrollnum);//滚动数-- while (rollnum(sortlist->idxrollnum) == 0) {//找到时间到了节点,注意这些节点都是由定时器产生的, los_listdelete(&sortlist->sortlinknode); taskcb = los_dl_list_entry(sortlist, lostaskcb, sortlist);//拿任务,这里的任务都是超时任务 taskcb->taskstatus &= ~os_task_status_pend_time; tempstatus = taskcb->taskstatus; if (tempstatus & os_task_status_pend) { taskcb->taskstatus &= ~os_task_status_pend;#if (loscfg_kernel_liteipc == yes) taskcb->ipcstatus &= ~ipc_thread_status_pend;#endif taskcb->taskstatus |= os_task_status_timeout; los_listdelete(&taskcb->pendlist); taskcb->tasksem = null; taskcb->taskmux = null; } else { taskcb->taskstatus &= ~os_task_status_delay; } if (!(tempstatus & os_task_status_suspend)) { os_task_sched_queue_enqueue(taskcb, os_process_status_pend); needschedule = true; } if (los_listempty(listobject)) { break; } sortlist = los_dl_list_entry(listobject->pstnext, sortlinklist, sortlinknode); } los_spinunlock(&g_taskspin); if (needschedule != false) {//需要调度 los_mpschedule(os_mp_cpu_all);//核间通讯,给所有cpu发送调度信号 los_schedule();//开始调度 }} 第三:定时器扫描,看是否有超时的定时器
/* * description: tick interrupt interface module of software timer * return : los_ok on success or error code on failure *///osswtmrscan 由系统时钟中断处理函数调用lite_os_sec_text void osswtmrscan(void)//扫描定时器,如果碰到超时的,就放入超时队列{ sortlinklist *sortlist = null; swtmr_ctrl_s *swtmr = null; swtmrhandleritemptr swtmrhandler = null; los_dl_list *listobject = null; sortlinkattribute* swtmrsortlink = &ospercpuget()->swtmrsortlink;//拿到当前cpu的定时器链表 swtmrsortlink->cursor = (swtmrsortlink->cursor + 1) & os_tsk_sortlink_mask; listobject = swtmrsortlink->sortlink + swtmrsortlink->cursor; //由于swtmr是在特定的sortlink中,所以需要很小心的处理它,但其他cpu core仍然有机会处理它,比如停止计时器 /* * it needs to be carefully coped with, since the swtmr is in specific sortlink * while other cores still has the chance to process it, like stop the timer. */ los_spinlock(&g_swtmrspin); if (los_listempty(listobject)) { los_spinunlock(&g_swtmrspin); return; } sortlist = los_dl_list_entry(listobject->pstnext, sortlinklist, sortlinknode); rollnum_dec(sortlist->idxrollnum); while (rollnum(sortlist->idxrollnum) == 0) { sortlist = los_dl_list_entry(listobject->pstnext, sortlinklist, sortlinknode); los_listdelete(&sortlist->sortlinknode); swtmr = los_dl_list_entry(sortlist, swtmr_ctrl_s, stsortlist); swtmrhandler = (swtmrhandleritemptr)los_memboxalloc(g_swtmrhandlerpool);//取出一个可用的软时钟处理项 if (swtmrhandler != null) { swtmrhandler->handler = swtmr->pfnhandler; swtmrhandler->arg = swtmr->uwarg; if (los_queuewrite(ospercpuget()->swtmrhandlerqueue, swtmrhandler, sizeof(char *), los_no_wait)) { (void)los_memboxfree(g_swtmrhandlerpool, swtmrhandler); } } if (swtmr->ucmode == los_swtmr_mode_once) { osswtmrdelete(swtmr); if (swtmr->ustimerid ustimerid += loscfg_base_core_swtmr_limit; } else { swtmr->ustimerid %= loscfg_base_core_swtmr_limit; } } else if (swtmr->ucmode == los_swtmr_mode_no_selfdelete) { swtmr->ucstate = os_swtmr_status_created; } else { swtmr->ucoverrun++; osswtmrstart(swtmr); } if (los_listempty(listobject)) { break; } sortlist = los_dl_list_entry(listobject->pstnext, sortlinklist, sortlinknode); } los_spinunlock(&g_swtmrspin);} 最后看调度算法的实现


关于商用组串式逆变器安装的方法介绍
比特斯拉充电还贵的共享充电宝 你还会去用吗
基于LTC3789芯片的高效同步升降压电源设计
大屏拼接领域:两种不同的市场旋律,加速LED替代LCD
PSoC的核心设计技术
鸿蒙内核源码分析之时钟节拍的实现方式
通过案例分析轴瓦温度在汽轮机中的应用
赛微电子公司成功开发出650 V系列GaN功率器件产品
60W电源适配器方案神助攻,为你的设备提供全面动力支持!
晶圆临时键合及解键合工艺技术介绍
区块链实体运用的领域有哪一些
苹果AirPods 2代参加拼多多百亿补贴
华硕新款电竞显示器刷新率创纪录,达到了280Hz
基于线性传感器IC的霍尔效应集成电路系统分析
大模型入局机器人领域 机器人行业将迎新机遇
研究量子力学三种主要方法
485总线单点对多点常见问题分析
解析中国激光电视崛起之路:中国激光电视已经成为了行业领跑者
如何开发一个属于自己的Chainlink智能合约
Tailor Brands利用机器学习实现自动化的设计,获1550万美元B轮融资