65、【OS】【Nuttx】任务休眠与唤醒:nxsig_clockwait
背景
之前的 blog
63、【OS】【Nuttx】任务休眠与唤醒:sleep
64、【OS】【Nuttx】任务休眠与唤醒:clock_nanosleep
分析了任务休眠中的 sleep 函数,下面继续来分析下 clock_nanosleep 函数中的核心功能 nxsig_clockwait
nxsig_clockwait
函数描述
先来看函数描述
nxsig_clockwait 检查传入的信号集(由 set 参数指定)。。。看到这里就不用往下看了,因为这个函数压根没有 set 入参,这个函数描述应该是很久没更新了,下面直接看函数实现
函数实现
函数入参:
- clockid:指定要使用的时钟源
- flags:用绝对时间还是相对时间
- rqtp:要休眠的时间
- rmtp:剩余待休眠的时间
参数检查,rqtp 时间要合法,主要是纳秒单位 tv_nsec
当前正在执行的任务 this_task() 是 ready 队列中第一个任务
当请求休眠时间 rqtp 为 0 时,sleep(0) 的行为在 POSIX 标准没有明确规定,不同系统表现会不一样
- 在 Linux 中,当调用 sleep(0) 时,会进入系统内核并调用 schedule(),主动让出当前 CPU 时间片,此时当前任务暂停运行,直到下一次被调度器重新选中
- 在 BSD 系统,当调用 sleep(0) 会直接返回,不做任何实际的休眠或调度操作,相当于空操作,此时当前任务不会主动让出 CPU
在 Nuttx 中,表现和 Linux 类似,下面来看下 sched_yield 这个函数的功能(从名字上看,yield 的含义有放弃,让步的意思,sched_yield 的功能就与调度让出有关):
从函数描述可以看出
- sched_yield 强制当前正在运行的任务(线程或进程)主动放弃当前使用的 CPU
- 只允许优先级相同的其他任务运行,不会让低优先级任务获得 CPU
来看下 sched_yield 函数的实现:
核心的就是这段注释:
- 首先 sched_yield 不是直接通过调度器(如 Linux 中的 schedule()),而是通过将当前任务的优先级重新设置为原来的值来触发一次调度
- 在 Nuttx 中,当任务的优先级被重新设置时,即使优先级没有变化,调度器也会将该任务放到同优先级队列的末尾,然后通过上下文切换,使得当前任务主动放弃当前时间片,让其他同优先级任务先运行
等下篇 blog 再来分析 nxsched_set_priority,先接着往下看 nxsig_clockwait
- 接下来就是根据标志位 flags (相对时间&绝对时间)来启动看门狗定时器了,看门狗定时器之前 blog 29、【OS】【Nuttx】【最小系统】tickless 有分析过一些,主要就是通过普通定时器的后处理函数 nxsched_process_timer 的执行不断去判断看门狗任务有没有超时
- 另外,这里的编码不太好,rqtp 应该用卫语句,在函数一进来时就应该先判空,而不是后面每次用到的时候都要判断一下非空
- 启动完定时器后,接下来把当前任务从 ready 队列中去掉,然后当前任务设置成 TSTATE_WAIT_SIG,加入信号等待队列,等待被唤醒
- 接着切换上下文
- 等被信号唤醒后,重新回到该任务,开始执行下一行 wd_cancel,将该看门狗定时器去掉
- 最后更新下 rmtp 剩余休眠时间,休眠任务就结束了
下篇 blog 继续分析下 nxsched_set_priority