动手做一个自组网的网络 - 操作系统内核

本文介绍了作者动手制作一个MCU操作系统内核的过程,旨在实现简单、稳定的任务线程化调度。文章详细阐述了中断处理、栈管理、链表在任务管理中的应用以及阻塞机制。操作系统内核包括一个简单的调度器,利用中断如pendsv、svc和systick进行任务切换。此外,还讨论了内存管理和队列的实现,以及信号量和互斥锁的策略。作者强调了实际操作中的学习过程和无尽的技术探索。
摘要由CSDN通过智能技术生成

动手做一个自组网的网络 - 操作系统内核



介绍

  • 注意: 这不是一个真正意义上的操作系统,属于操作系统内核、微核心。
  • 起初,只是想自己做一个MCU上的操作系统调度内核来验证自己的一些想法,之前用过一些RTOS。因为我的源码阅读能力是很弱的,有时需要了解关于某个小问题的解释,还得网上翻翻别人的记录,就这样,从使用一个栈倒腾两个任务开始,再到使用两个栈切换两个任务,最后一个简单且脆弱的调度器雏形就跑起来了。
  • 写这篇主要是回顾之前写这个MCU操作系统内核的想法,是思路上的总结。
  • 源码 https://gitee.com/cyes/rtos

需要实现一个什么样目标

  • 简单、稳定的
  • 可以将任务线程化调度
  • 方便调试

一个简单的调度器

中断
  • 这里只讨论和系统调度有关的中断
    • pendsv - 可悬起系统调用,在一个任务运行时间片结束时标记该中断来延迟运行系统调度,这个中断的特性是只能在其他所有中断执行完毕后才会响应。

    • svc - 软件中断 - 一个调度器想要循环调度所有任务理论上只需要pendsv即可,只不过第一个任务比较特殊,因为在他之前没有任务堆栈被使用,所以需要把这部分特殊的前奏单独拿出来交给另一个中断进行,svc正好合适做这个,于是用他进入中断来切换第一个任务堆栈。

    • systick - 定时器中断,任何能提供周期性中断的中断源都可以用来做这件事,甚至可以拿按键配合gpio中断来手动切换这些任务,不嫌累的话。

    • 中断响应序列 - 中断发生时硬件做了什么

      中断发生
      入栈取向量
      更新寄存器
      中断处理
      中断返回
    • 上述流程中,只有中断处理是需要软件额外介入的,其余都是硬件自动完成

    • 注意: 在中断返回时,内核需要特定的 EXC_RETURN 来指导中断返回,否则一些中断返回过程会被终止。

      • 返回时需要将EXC_RETURN写入PC

        EXC_RETURN解释
        0xffffffff1 返回handler模式
        0xffffffff9 返回线程模式,并使用MSP
        0xffffffffd 返回线程模式,并使用PSP
      • 测试中在cortex-m3cortex-m4cortex-m7内核都需要这么做,否则不会正常返回。

      • cortex-m0/m0+EXC_RETURN写入通用寄存器返回也可以。

      • 这里顺带提一下 cortex-m0/m0+ ,由于支持的指令集较少,意味着在汇编阶段的栈操作需要使用其他指令实现,具体见portable文件内,另外他的通用寄存器也仅支持低位寄存器r0 ~ r7

寄存器
  • cortex-m4f 的寄存器有16个,分别是r0 ~ r15 ,带有32个浮点寄存器,分别是s0 ~ s31

  • 平时CPU在执行代码时就是以这些寄存器为空间,不断的处理数据,所谓的保护现场就是保护这些寄存器,因为在任意时刻,所有发生的事情都是在这些寄存器里面发生的,恢复了这些寄存器也就是还原了一个时间点。

  • 在发生中断时,硬件会自动将r0-r3,r12,r14(LR),r15(PC),xPSR这些寄存器压栈到栈地址,使用FPU的话,会额外保存s0 ~ s15,栈地址就是我们在运行一个任务前指定的堆栈地址,同样,中断返回时硬件也会从堆栈里面弹出这些寄存器,我们需要做的就是按照规则把堆栈的数据修改好,这样硬件弹出的就是我们需要的数据了。

  • 用任务比作人的话,栈就是他的背包,平时手里拿不了的东西都可以放到背包里。
  • 现在我想把AB两个函数分别切换为两个死循环执行不同功能函数,因为两个函数都需要调用其他函数,所以就要各指定一个栈地址
  • 当需要从A任务切换B任务时,需要做下面几件事
    • 保存当前所有的寄存器到A的堆栈
    • 将PC改为B任务的地址
    • 将B任务栈里的数据恢复到寄存器里

链表

  • 上面描述了调度器,主要是利用硬件特性对CPU进行分时复用,接下来是链表,他是任务管理的核心
  • 关于链表网上有很多介绍,任何人使用任何语言都能写出他的实现,所以我就不罗嗦直接抄了
  • 这里根据linux内核2.6list实现做了些主要汇总,这些实现妙就妙在 函数全部都是 static inline
struct list_head                                          // 链表结构体的指针的数据结构
LIST_HEAD_INIT                                            // 用于初始化这个头部编成独立结点
LIST_HEAD(name)                                           // 初始化一个变量
INIT_LIST_HEAD(ptr)                                       // 将这个指针初始化为孤立的结点
    
list_for_each(pos, head)                                  // 从前到后遍历链表
list_for_each_safe(pos, n, head)                          // 删除当前结点不会造成断链
list_entry(ptr, type, member)                             // 获得这个指针的所再的项的开头
list_del(struct list_head *entry)                         // 删除这个结点, 没有切断联系
list_empty(struct list_head *head)                        // 判断这个链表是否为空
list_add(struct list_head *new, struct list_head *head)   // 将新元素放到链表头
list_move(struct list_head *list, struct list_head *head) // 移动链表到第二个链表
    
  • 了解一个新的东西,我一般会想这个东西是为了解决什么问题而存在的,只有了解 了他能解决什么问题,为什么别的方式解决不了这个问题时,才算学会了
  • 这里,我用它来管理多个任务。

怎么实现阻塞

  • 阻塞的方法是不执行,不执行的本质是将任务从链表移除

    • 这里的任务运行仅有运行态 阻塞态 就绪态 三种,为了方便,阻塞态位于各自的阻塞事件链表上
  • 当任务创建时放到就绪链表,当任务需要被阻塞时就放到其他链表。因为调度器只在就绪链表里寻找任务,所以就产生了阻塞效果。

  • 任务需要执行时,则将该任务移回即可,这一切都依赖于链表的特性

内存管理

  • 我实现的算法没有任何策略,且不满足实时性。
  • 舍弃速度照顾碎片化,写了这么一个功能,因为能保证安全有效且简单
  • 内存需要监控,可以通过LCD直观看到内存动态分配情况,这能很好的监控运行中的内存使用情况。图片ref

队列

  • 队列有很多种实现方式

    • 链表队列 — 默认不分配内存,写入即分配内存并写入链表,读取即移除链表并释放内存
    • 定长预分配内存队列 — 预先分配内存并分割一定数量,写入即填充数据,数据只能读写固定长度
    • 不定长预分配内存队列 — 参考定长预分配内存模式,数据可以跨多块读写
  • 目前仅实现了定长预分配内存队列,其他两种都有各自的优点。

  • 可以升级为动态链表队列,这样长度可以限定,内存也会有效利用(需要解决内存分配的时间确定性)。

信号量和互斥锁

  • 信号量就是队列的特殊实现方式

  • 互斥锁的本质就是在信号量的基础上增加额外功能,目前只实现了优先级天花板策略。

后续更新

  • 组件接口 - 可以快速使用的一些常用硬件库
  • 动态任务栈 - 动态管理栈空间,无需指定大小
  • 多核调度和新平台支持

总结

  • 到这里,一个可以实现调度多任务的简单操作系统内核就可以使用了。
  • 当开始写的时候,总有一些卡点不知道怎么做,在工程初具雏形后思维就开始跳跃了,时刻与技术人的偏执做斗争。慢慢地越往后写越觉得这玩意就是一个无底洞,哪里有什么完美,linux现在不也在持续提交代码嘛,能用就行吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FTKernelAPI 是一套完全免费(对于非商业性程序而言)的实现了BitTorrent 网络协议内核。在兼容官方BitTorrent协议的同时针对国内的网络带宽状况进行了优化,增加了一个侦听端口支持多个任务同时运行, 文件选择下载,断点续传, 自动配置支持UPnP协议的路由器, 对于全局或者单个任务进行速度限制等功能。FTKernelAPI BT协议内核以及示例源码 BitZam 的出现,使BT软件开发不再高深。只要你愿意,不必关心网络编程,BT协议,只需简单的调用FTKernelAPI的接口在3天的时间里就能开发出满足你自己需要的BT下载软件。假如你正在想自己开发一个BT下载软件或者你正在为你的公司的程序寻找一种省钱省时的下载解决方案, FTKernelAPI将是你的理想选择...FTKernelAPI 成熟可靠吗? 可以被那些开发语言使用?BT下载软件FlashBT(变态快车) 就是使用的本内核. 从2004年开发至今,经过了大约100万以上用户的测试使用,已经非常成熟和可靠。而且作者长期从事P2P和IM软件的开发,积累了丰富的开发经验,还在不断的改进和完善FTKernelAPI 之中。FTKernelAPI 是使用C++开发, 以标准C API 接口的方式提供外部调用接口. 所以FTKernelAPI 不但可以应用于C++开发的程序中, 同样可以应用于VB/Delphi/C++ Builder 的语言开发的程序中. 目前FTKernelAPI 已经被国内和国外的几家公司成功的应用于他们的商业程序中, 包括C++和Delhpi开发的程序.FTKernelAPI 如何使用? 有什么例子可以参照吗?为了便于大家使用, 作者提供了一个使用FTKernelAPI 开发的开放源码的BT下载程序 - BitZam. 关于使用FTKernelAPI, 你可以下载BitZam的C++源码看看. 使用起来非常简单. 你可以在BitZam的基础上在很短的时间内开发出通用的BitTorrent下载程序或者自己专用的禁止其他人的BitTorrent软件下载的程序. 你不必再关心BitTorrent协议的细节, 这些都已经被封装在了内核中.FTKernelAPI 和FlashBT的使用的内核有差别吗?FlashBT同样使用的是 FTKernelAPI 内核. 你得到的内核和FlashBT使用的没有任何差别. 这意味着, 只要你愿意, 你可以开发出和FlashBT一样强大的BT下载程序.FTKernelAPI 是完全免费的吗? 可以将它应用于商业程序中吗?对于非商业性非盈利性软件你可以自由免费使用它. 没有任何时间和功能限制. 对于商业性程序, 你只需要支付少量的费用,就可以获取到本内核的商业使用权, 并且获得到作者的免费长期技术支持。另外对于商业应用的特殊需求,FTKernelAPI提供了特别的接口,就是使用FTKernelAPI可以制作出使用DE算法加密的只有FTKernelAPI能够识别和下载的Torrent件,保护您的商业利益不受侵犯!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值