一篇讲透嵌入式操作系统任务调度「建议收藏」

一篇讲透嵌入式操作系统任务调度「建议收藏」进互联网公司操作系统和网络库是基础技能,面试过不去的看,这里基于嵌入式操作系统分几章来总结一下任务调度、内存分配和网络协议栈的基础原理和代码实现。处理器上电时会产生一个复位中断,接下来会…

大家好,又见面了,我是你们的朋友全栈君。

进互联网公司操作系统和网络库是基础技能,面试过不去的看,这里基于嵌入式操作系统分几章来总结一下任务调度、内存分配和网络协议栈的基础原理和代码实现。

处理器上电时会产生一个复位中断,接下来会执行复位中断服务函数,这才是软件执行的起始点。复位函数先后调用SystemInit和__main函数,SystemInit是处理器自带的库函数,一般执行各种时钟和外设的初始化;__main函数执行C语言运行环境的初始化,包括将目标程序从flash搬运到RAM、初始化全局变量等内存段初值,初始化C语言库函数等操作,最后跳转到main函数,执行用户程序。不同型号的处理器启动流程不太一致,如果不是需要设计bootloader,可以没必要关心。

mian的主要工作大致为:内存初始化、硬件中断初始化,此外还会分配基础的资源如锁、信号量等,最后创建idletask。idletask任务优先级最低,里面一般循环执行WFI指令使芯片保持低功耗状态。

任务相关结构初始化很简单,主要是分配任务块空间,并挂接在freelist链表上。后续分配任务时,从freelist链表上取就行。

                           

一篇讲透嵌入式操作系统任务调度「建议收藏」

接下来看看任务创建的步骤:

首先将需要回收的任务资源挂在freetasklist上去。这里是尽量延迟了任务的回收时间,不是在任务该回收的时候而是在新任务创建的时候回收旧任务。这样可以尽量减少CPU占用。所以每次新建任务,都是从freetasklist链表上取一个TCB下来然后根据用户需求分配栈大小,设置任务优先级和入口函数等。这里要注意操作freetasklist的过程中要关闭中断,防止操作过程中来了中断引起任务调度,导致crash。这里写代码需要注意因为参数检查、分配内存等流程都有可能出错,在设计程序的时候最好统一收口,所有错误有一个统一的出口处理,这样可以防止遗忘开中断等重要操作。大致流程如下:

一篇讲透嵌入式操作系统任务调度「建议收藏」

从freelist头部摘取一个任务块,并分配任务栈空间、设置优先级等,新创建的任务需要挂接到priqueue链表数组中等待任务调度:

一篇讲透嵌入式操作系统任务调度「建议收藏」

这里有个小知识点,一般的链表指向的都是结构体的首部,这样可以将链表指针直接强制转换成对应的数据结构(这里是任务块)。而在任务队列中链表位于任务块结构体中间,需要用宏来获取到链表指针对应的任务块首地址,这个宏的实现大同小异,各个操作系统都是借鉴Linux来实现的,详情百度:list_entry。

接下来就要说说操作系统是怎么做到常数级的任务切换时间的。初学者写的操作系统任务调度功能时可能会出现一种场景,那就是任务量少的时候任务切换时间快,任务量多的时候任务切换时间变慢,这种任务切换耗时不确定对用户任务影响时非常大的。我们来看看ucos系统是如何设计来保证常数级任务切换时间的。

一个全局的priqueue链表数组,上面挂接ready状态的任务队列,一个全局int32数,用于标记某优先级是否有需要调度的队列。要扩展到128位优先级也非常方便,设置4个int32数组即可。每次取优先级最高的任务,直接用CLZ汇编命令从bitmap中读出需要调度的最高优先级任务。

一篇讲透嵌入式操作系统任务调度「建议收藏」

插入ready任务的时候需要将bitmap对应位置1,任务从ready状态移除的时候需要检查该优先级是否还有需要调度的任务,如果没有了,bitmap对应位需要置0。讲完嵌入式操作系统的进程调度,再来看看Linux的CFS的基础原理,就好理解多了,嵌入式系统低优先级队列可能会存在饿死现象,Linux的CFS调度算法给每个优先级分配了不同权重,根据就绪队列里所有任务的权重之和来分配任务的时间,来保证完全公平调度。

内存分配

前面分配任务块、分配任务栈等都用到了内存分配动作,具体的内存分配算法有:best-fit算法、TLSF算法、LWIP中的最快匹配算法、伙伴算法等,基础原理类似,下期再分析。

时钟中断

适配操作系统首要任务就是把时钟tick给起起来,这是芯片的心跳,所有的任务切换和延时操作都是基于时钟tick中断驱动的。

以ARM芯片的Cortex-M3核为例,启动时钟中断主要是调用osSetVector将tick回调函数设置进中断向量表里面的15号中断:

一篇讲透嵌入式操作系统任务调度「建议收藏」

中断向量表长这样子:

一篇讲透嵌入式操作系统任务调度「建议收藏」

前面15个中断号属于系统中断,后面预留中断号可供用户配置,M3是240个,M0是32个。

结合PendSV中断,可以在tick中断中完成别的事物(如定时器处理等),通过低优先级的PendSV中断来执行任务切换动作,从而减少中断响应时间。具体的分析在之前文章中:嵌入式操作系统的任务调度

一篇讲透嵌入式操作系统任务调度「建议收藏」

在设置tick中断的时候还需要配置systick定时器的中断间隔。systick定时器是个简单的向下计数的24位计数器,寄存器位置位于系统控制空间基址SysTick_BASE偏移16字节,将需要的频率数值写入即可。systick寄存器的内部细节为:

一篇讲透嵌入式操作系统任务调度「建议收藏」

详情可参考《ARM Cortex-M3 Cortex-M4权威指南》9.5节systick相关部分,其余相关linux中断知识可参考:Linux中断编程

顺带说一下,如果职业规划是往互联网方向转,那么寄存器硬件知识了解即可。如果想在物联网嵌入式领域深耕,不同ARM芯片之间的区别是一定要掌握的。

我们可以给tick中断配置为每10ms中断一次,防止过多的任务上下文切换占用CPU资源。中断到来后系统都要处理哪些事务呢?通常情况下会维护一个全局计数器,该中断到来时变量自增,然后会处理定时器任务和超时任务。

超时任务是什么呢?比如用户任务等待某个资源(锁、信号量等),如果获取不到就会设置超时时间阻塞等待,直到资源可用或者任务超时。因此每次时钟中断到来都需要判断是否有任务超时。

定时器任务就比较简单了,可以使用全局链表有序挂接定时任务,每次只需要判断链表头的任务是否到时,到时了摘取下来执行对应的回调函数即可。

一篇讲透嵌入式操作系统任务调度「建议收藏」

不同的操作系统可能会在tick中断里面做一些别的事情,比如定时器对齐等。

貌似还有很多没写完,下周末再来总结。最后推荐嵌入式操作系统入门的三本书:《嵌入式操作系统内核调度–底层开发者手册》、《嵌入式网络那些事–STM32物联实战》、《ARM Cortex-M3 Cortex-M4权威指南》

一篇讲透嵌入式操作系统任务调度「建议收藏」

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/151206.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • administrator改名字_计算机名和用户名

    administrator改名字_计算机名和用户名重命名计算机必须以管理员或Administrators组成员身份登录才能完成该过程。如果计算机与网络连接,则网络策略设置也可以阻止您完成此步骤。在控制面板中打开系统。在“计算机名称”选项卡,单击“更改”。在“计算机名”下键入计算机的新名称,然后单击“确定”。如果计算机是域的成员,则提示您提供用户名和用户密码才能重命名域中的计算机。注意要打开“系统”,请单击“开始”,指向“设置”,单击“控制面…

    2022年10月14日
    2
  • IDEA 将项目打包war包[通俗易懂]

    IDEA 将项目打包war包[通俗易懂]IntelliJIDEA将项目打包war包1、准备工作IntelliJIDEA开发工具可以正常运行的Java项目2、打包war包流程使用快捷键Ctrl+Alt+Shift+s或者鼠标点击选中项目名按F4打开ProjectStructure界面选择Artifacts,点击右边+,依次选择WebApplication:Archive和For’myP…

    2025年5月28日
    6
  • java闰年_java 判断闰年

    java闰年_java 判断闰年题目:在l.jsp中,设置一个表单,可以输入年份,提交到另外一个action进行计算,如果算出来是闰年,那么就跳转到a1.jsp(显示闰年),如果是平年就跳转到a2.jsp(显示平年)。要求:需要把计算是否闰年的算法,封装到一个工具类Year中isLeap方法中。第一步:创建1.jsp页面,并跳到action.jsp请输入年份:如下图:第二步:封装year工具类创建一个class类,取名year…

    2022年7月17日
    17
  • webstorm激活码(注册激活)

    (webstorm激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月28日
    198
  • VBoxGuestAdditions加载不了

    VBoxGuestAdditions加载不了未能加载虚拟光盘D:\ProgramFiles(x86)\oraclevm\VBoxGuestAdditions.iso到虚拟电脑centeros7_8.Couldnotmountthemedia/drive’D:\ProgramFiles(x86)\oraclevm\VBoxGuestAdditions.iso'(VERR_PDM_MEDIA_LOCKED).返回代码: E_FAIL(0x80004005) 组件: ConsoleWrap 界…

    2022年6月16日
    139
  • python3基础:操作mysql数据库

    python3基础:操作mysql数据库mysql登陆基本操作:登陆:mysql-uroot-h127.0.0.1-P3306-pmysql-uroot-p(本机不用写host)退出mysql:ctrl+z+回车,或者exit端口号默认是3306,但是可以通过安装目录下的配置文件修改。使用流程引用API模块获取与数据库的连接执行sql语句与存储过程关闭数据库连接安装pymysqlpython3与…

    2022年6月1日
    63

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号