鸿蒙内核源码分析(任务切换篇) | 看汇编怎样切换任务

[复制链接]
发表于 2026-2-4 15:51:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在鸿蒙的内核线程就是任务,系列篇中说的任务和线程当一个东西去明确.
一样平常二种场景下须要切换任务上下文:

      
  • 在线程环境下,从当火线程切换到目标线程,这种方式也称为软切换,能由软件控制的自主式切换.哪些环境下会出现软切换呢?
         
    • 运行的线程申请某种资源(好比各种锁,读/写消息队列)失败时,须要自动开释CPU的控制权,将自己挂入等候队列,调理算法重新调理新任务运行.   
    • 每隔10ms就实行一次的OsTickHandler节奏处置惩罚函数,检测到任务的时间片用完了,就发起任务的重新调理,切换到新任务运行.   
    • 不管是内核态的任务照旧用户态的任务,于切换而言是同一处置惩罚,等量齐观的,由于切换是须要换栈运行,寄存器有限,须要频仍的复用,这就须要将当前寄存器值老师存到任务自己的栈中,以便别人用完了轮到自己再用时规复寄存器其时的值,确保老任务还能继续跑下去. 而生存寄存器次序的布局体叫:任务上下文(TaskContext).   
       
  • 在停止环境下,从当火线程切换到目标线程,这种方式也称为硬切换.不由软件控制的被动式切换.哪些环境下会出现硬切换呢?
         
    • 由硬件产生的停止,好比 鼠标,键盘外部装备每次点击和敲打,屏幕的触摸,USB的插拔等等这些都是硬停止.同样的须要切换栈运行,须要复用寄存器,但与软切换不一样的是,硬切换会切换工作模式(停止模式).以是会更复杂点,但原理照旧一样要生存和规复切换现场寄存器的值, 而生存寄存器次序的布局体叫:任务停止上下文(TaskIrqContext).   
      
本篇详细说清楚以下几个题目:

      
  • 任务上下文(TaskContext)怎么生存的?  
  • 代码的实现细节是怎样的?  
  • 怎样包管切换不会发生错误,指令不会丢失?
前置条件

一个任务要跑起来,须要两个必不可少的硬性条件:

      
  • 1.从代码段哪个位置取指令? 也就是入口所在,main函数是应用步调的入口所在, 留意main函数也是一个线程,只是不须要你来new而已,加载步调阶段会默认创建好. run()是new一个线程实行的入口所在.高级语言是这么叫,但到了汇编层的叫法就是PC寄存器.给PC寄存器赋什么值,指令就从那边开始实行.
      
  • 2.运行的园地(栈空间)在那边? ARM有7种工作模式,到了历程层面只须要思量内核模式和用户模式两种,对应到任务会有内核态栈空间和用户态栈空间.内核模式的任务只有内核态的栈空间,用户模式任务二者都有.栈空间是在初始化一个任务时就分配指定好的.以下是两种栈空间的初始化过程.为了简洁省去了部分代码,留下了核心部分.

  1. //任务控制块中对两个栈空间的描述
  2. typedef struct {
  3.     VOID            *stackPointer;      /**< Task stack pointer */  //内核态栈指针,SP位置,切换任务时先保存上下文并指向TaskContext位置.
  4.     UINT32          stackSize;          /**< Task stack size */     //内核态栈大小
  5.     UINTPTR         topOfStack;         /**< Task stack top */      //内核态栈顶 bottom = top + size
  6.     // ....
  7.     UINTPTR         userArea;       //使用区域,由运行时划定,根据运行态不同而不同
  8.     UINTPTR         userMapBase;    //用户态下的栈底位置
  9.     UINT32          userMapSize;    /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
  10. } LosTaskCB;   
复制代码
<hr>
  1. //内核态运行栈初始化
  2. LITE_OS_SEC_TEXT_INIT VOID *OsTaskStackInit(UINT32 taskID, UINT32 stackSize, VOID *topStack, BOOL initFlag)
  3. {
  4.     UINT32 index = 1;
  5.     TaskContext *taskContext = NULL;
  6.     taskContext = (TaskContext *)(((UINTPTR)topStack + stackSize) - sizeof(TaskContext));//上下文存放在栈的底部
  7.     /* initialize the task context */ //初始化任务上下文
  8.     taskContext->PC = (UINTPTR)OsTaskEntry;//程序计数器,CPU首次执行task时跑的第一条指令位置
  9.     taskContext->LR = (UINTPTR)OsTaskExit;  /* LR should be kept, to distinguish it's THUMB or ARM instruction */
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表