鸿蒙内核源码分析(时钟任务篇)

时钟概念

  • 时间是非常重要的概念,我们整个学生阶段有个东西很重要,就是校园铃声. 它控制着上课,下课,吃饭,睡觉的节奏.没有它学校的管理就乱套了,老师拖课想拖多久就多久,那可不行,下课铃声一响就是在告诉老师时间到了,该停止了让学生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的第一个节点sortLinkNodeROLLNUM_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;
#endiftaskCB->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 < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) {swtmr->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);
}

最后看调度算法的实现

//调度算法的实现
VOID OsSchedResched(VOID)
{LosTaskCB *runTask = NULL;LosTaskCB *newTask = NULL;LosProcessCB *runProcess = NULL;LosProcessCB *newProcess = NULL;LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//必须持有任务自旋锁,自旋锁是不是进程层面去抢锁,而是CPU各自核之间去争夺锁if (!OsPreemptableInSched()) {//是否置了重新调度标识位return;}runTask = OsCurrTaskGet();//获取当前任务newTask = OsGetTopTask();//获取优先级最最最高的任务/* always be able to get one task */LOS_ASSERT(newTask != NULL);//不能没有需调度的任务if (runTask == newTask) {//当前任务就是最高任务,那还调度个啥的,直接退出.return;}runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;//当前任务状态位置成不在运行状态newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//最高任务状态位置成在运行状态runProcess = OS_PCB_FROM_PID(runTask->processID);//通过进程ID索引拿到进程实体newProcess = OS_PCB_FROM_PID(newTask->processID);//同上OsSchedSwitchProcess(runProcess, newProcess);//切换进程,里面主要涉及进程空间的切换,也就是MMU的上下文切换.
#if (LOSCFG_KERNEL_SMP == YES)//CPU多核的情况/* mask new running task's owner processor */runTask->currCpu = OS_TASK_INVALID_CPUID;//当前任务不占用CPUnewTask->currCpu = ArchCurrCpuid();//让新任务占用CPU
#endif(VOID)OsTaskSwitchCheck(runTask, newTask);//切换task的检查
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)OsSchedStatistics(runTask, newTask);
#endifif ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {//没有时间片且是抢占式调度的方式,注意 非抢占式都不需要时间片的.newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;//给新任务时间片 默认 20ms}OsCurrTaskSet((VOID*)newTask);//设置新的task为CPU核的当前任务if (OsProcessIsUserMode(newProcess)) {//用户模式下会怎么样?OsCurrUserTaskSet(newTask->userArea);//设置task栈空间}/* do the task context switch */OsTaskSchedule(newTask, runTask);//切换任务上下文,注意OsTaskSchedule是一个汇编函数 见于 los_dispatch.s
}

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/4376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LLM大语言模型(十三):ChatGLM3-6B兼容Langchain的Function Call的一步一步的详细转换过程记录

# LangChain&#xff1a;原始prompt System: Respond to the human as helpfully and accurately as possible. You have access to the following tools: Calculator: Useful for when you need to calculate math problems, args: {\calculation\: {\description\: \calcul…

自动化爬虫工具:you-get安装与使用

Windows下的安装命令&#xff1a; pip install you-get linux下的安装命令&#xff1a; pip3 install you-get 下载完成后&#xff0c;我们可以看到如下的警告&#xff0c;意思就是这个工具并未被添加到环境变量中&#xff0c;如果我们想在命令行中直接调用&#xff0c;需要…

vim的IDE进阶之路

一 ctags 1 安装 安装ctags比较简单&#xff0c;我用的是vim-plug&#xff0c;网络上随便一搜应该就有很多教程&#xff0c;而且没有什么坑 2 使用 vim之函数跳转功能_nvim函数跳转-CSDN博客https://blog.csdn.net/ballack_linux/article/details/71036072不过针对cuda程序…

2024年电子商务与大数据经济国际会议 (EBDE 2024)

2024年电子商务与大数据经济国际会议 (EBDE 2024) 2024 International Conference on E-commerce and Big Data Economy 【会议简介】 2024年电子商务与大数据经济国际会议即将在厦门召开。本次会议旨在汇聚全球电子商务与大数据经济领域的专家学者&#xff0c;共同探讨电子商务…

nacos-redis-springboot

新项目 准备工作 nacos 版本 2.0.3 redis 最终版本说明 springcloud-alibaba&#xff1a;2.2.7RELEASE springcloud&#xff1a;Hoxton.SR12 springboot&#xff1a;2.3.12.RELEASE Nacos&#xff1a;2.0.3 步骤 启动nacos和redis 准备nacos配置文件 server: port…

使用frp实现内网穿透教程

文章目录 简介frp 是什么&#xff1f;为什么选择 frp&#xff1f; 概念工作原理代理类型 内网穿透教程服务端安装和配置本地Windows&#xff08;客户端&#xff09;安装和配置本地Linux虚拟机&#xff08;客户端&#xff09;安装和配置使用 systemd 管理服务端注意事项 简介 f…

GPT学术优化推荐(gpt_academic )

GPT学术优化 (GPT Academic):支持一键润色、一键中英互译、一键代码解释、chat分析报告生成、PDF论文全文翻译功能、互联网信息聚合GPT等等 ChatGPT/GLM提供图形交互界面&#xff0c;特别优化论文阅读/润色/写作体验&#xff0c;模块化设计&#xff0c;支持自定义快捷按钮&…

在线培训考试系统在线考试功能注意事项

在线培训考试系统在线考试功能注意事项 考试前务必注意是否开启防切屏、摄像头监考等防作弊措施&#xff0c;系统一旦检测到触发了疑似作弊行为会立刻自动交卷&#xff0c;考试终止&#xff1b; 答题者准备好后&#xff0c;可点击“开始答题”按钮进入考试&#xff0c;注意考…

【Vue】如何创建一个Vue-cli程序

一、准备工作 1、下载Node.js 官网地址 https://nodejs.org/en 2、查看版本 cmd下通过node-v,查看版本号&#xff1b; cmd下通过npm-v,查看是否打印版本号。 3、安装淘宝加速器 npm install cnpm -g 4、安装Vue-cli cnpm install vue-cli -g 二、创建Vue程序 1、创建一个V…

Aurora-64B/10B、XDMA与DDR结合设计高速数据流通路设计/Aurora光纤设计/XDMA读取DDR设计/基于FPGA的高速数据传输设计

因最近想通过FPGA把数据从光纤传到PC&#xff0c;借此机会和大家一起学习Aurora、XDMA结合DDR 制作不易&#xff0c;记得三连哦&#xff0c;给我动力&#xff0c;持续更新&#xff01;&#xff01;&#xff01; 完整工程文件下载&#xff1a;XDMA读写DDR工程 提取码&…

微信小程序的常用API②

一、动画API &#xff08;1&#xff09;作用&#xff1a;用于在微信小程序中完成动画效果的制作 &#xff08;2&#xff09;使用&#xff1a;创建实例 wx.createAnimation() &#xff08;3&#xff09;常用属性&#xff1a; duration 【number型】 动画持续时间&…

《C++学习笔记---入门篇2》---传值引用与传引用返回详解

先看这个程序&#xff0c;随着Count栈帧的销毁&#xff0c;会创建一个临时变量将n的值带回&#xff0c;可以实现我们的目的。 再看这个情况的时候&#xff0c;对于n来说他存放的位置在静态区&#xff0c;他不会随着函数栈帧的销毁而销毁&#xff0c;返回的时候依旧靠着临时变量…

Jmeter05:配置环境变量

1 Jmeter 环境 1.1 什么是环境变量&#xff1f;path什么用&#xff1f; 系统设置之一&#xff0c;通过设置PATH&#xff0c;可以让程序在DOS命令行直接启动 1.2 path怎么用 如果想让一个程序可以在DOS直接启动&#xff0c;需要将该程序目录配置进PATH 1.3 PATH和我们的关系…

Python脚本抢票【笔记】

Python脚本抢票【笔记】 前言版权推荐Python脚本抢票【Python】microsoft edge驱动器下载以及使用最后 前言 2024-4-17 18:19:15 以下内容源自《【笔记】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是ht…

容器工作流

背景 目前某平台使用计算容器和解析容器&#xff0c;这两种容器目前通过rabbitmq消息来进行链接&#xff0c;形成容器工作流&#xff0c;使用容器工作流框架可以省去两个容器中间环节的控制&#xff0c;不需要再使用java代码对容器的操作&#xff0c;通过容器工作流框架即可控…

SpringMVC进阶(数据格式化以及数据校验)

文章目录 1.数据格式化1.基本介绍1.基本说明2.环境搭建 2.基本数据类型和字符串转换1.需求分析2.环境搭建1.data_valid.jsp首页面2.Monster.java封装请求信息3.MonsterHandler.java处理请求信息4.monster_addUI.jsp添加妖怪界面5.单元测试 3.保存妖怪信息1.MonsterHandler.java…

运维笔记:基于阿里云跨地域服务器通信(上)

运维笔记 阿里云&#xff1a;跨地域服务器通信&#xff08;上&#xff09; - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this a…

git变更远端仓库名之后如何修改本地仓库配置的另一种方法?(删remote指针、添加、绑定master)

背景 如果某个远端的仓库地址变化后&#xff0c;本地仓库可以修改对应的remote。 之前谈过几种方法&#xff0c;比如重新设置一个新的remote的指针&#xff0c;绑定到新地址。然后删除origin&#xff0c;然后把新指针mv到origin。比如直接seturl修改&#xff08;git remote se…

深度学习从入门到精通——词向量介绍及应用

词向量介绍 词向量&#xff08;Word embedding&#xff09;&#xff0c;即把词语表示成实数向量。“好”的词向量能体现词语直接的相近关系。词向量已经被证明可以提高NLP任务的性能&#xff0c;例如语法分析和情感分析。词向量与词嵌入技术的提出是为了解决onehot的缺陷。它把…

ESP32-S3的MQTT实战

昨天&#xff0c;我们讲了socket通信&#xff0c;当服务器和客户端建立起连接时&#xff0c;就可以互相通信了。在互联网应用大多使用WebSocket接口来传输数据。而在物联网的应用中&#xff0c;常常出现这种情况&#xff1a;海量的传感器&#xff0c;需要时刻保持在线&#xff…