请选择 进入手机版 | 继续访问电脑版
查看: 268|回复: 2

[技术交流] AliOS的任务创建和执行

[复制链接]

15

主题

38

帖子

154

积分

利尔达员工

Rank: 9Rank: 9Rank: 9

积分
154
发表于 2019-8-28 16:04:46 | 显示全部楼层 |阅读模式
1、前言

每个任务都具有上下文,上下文是指当任务被调度执行时此任务可见的CPU资源和系统资源。当任务发生切换时,任务的上下文被保存在任务控制块(ktask_t)中,这些上下文包括当前任务的CPU指令地址(PC指针)、当前任务的栈空间、当前任务的CPU寄存器状态等。

2、系统task

依据不同的系统配置,rhino内核将在系统启动阶段创建一些默认的task,且这些task将会一直运行而不退出。常见的默认系统task包括:

(1)timer_task(定时器任务):当有需要把在处理的工作推迟一些时间时,可以启动一个定时器,指定延时时间和工作内容,并将此工作加入timer_task的内部队列,当定时器到了约定的时间时,timer_task将会执行此工作内容。从另一个方面看,rhino内核的定时器执行上下文是任务上下文,而不是中断上下文,也有某些操作系统将定时器的执行上下文放在中断上下文来处理。配置定时器任务的系统选项是RHINO_CONFIG_TIMER,此任务默认优先级是5,可用系统选项RHINO_CONFIG_TIMER_TASK_PRO来控制。

(2)DEFAULT-WORKQUEUE(工作队列):在当前代码执行上下文无法完成某些工作时,可以把此工作排入工作队列,由工作队列在任务上下文中执行,配置此任务的系统选项是RHINO_CONFIG_WORKQUEUE。

(3)rhino kernel shell任务: 此任务提供一个shell界面,用户可以通过此shell界面来运行命令与os交互,比如查看当前系统任务列表、空余内存等。

(4)idle_task(空闲任务):当CPU没有需要执行的指令时,则切入此task执行,此task执行一个while循环,直到有任何一个其他task需要被调度。

(5)dyn_mem_proc_task(动态释放内存):配置此任务的系统选项是RHINO_CONFIG_KOBJ_DYN_ALLOC。

3、task状态转移和迁移

在kernel shell中使用命令tasklist可以列出当前系统中所有task的信息。

(1)任务调度

rhino支持两种任务调度模式:基于优先级的抢占式调度、Round-Robin,基于时间片的轮转调度。

①基于优先级的抢占式调度

rhino对每一个不同的任务优先级,都维护了一个FIFO模式的ready queue,里面包含了当前所有可以运行的task列表。此列表中的task状态都处于RDY状态。当CPU可用时,最高优先级的ready queue里面排在第一个的task将得到CPU,并开始执行。

当有一个task就绪且优先级高于当前task,那么OS将立即切换到高优先级的task执行,并在切换之前保存当前task的上下文。

②Round-Robin

Round-Robin调度机制可以通过系统配置选项RHINO_CONFIG_SCHED_RR来开启。在Round-Robin调度机制下,同一优先级的task依次获得CPU,而不会因为某一个task不放弃CPU而导致bug。

Round-Robin调度机制会在同一优先级的task开始时共同分享CPU,每个task至多可以运行的时间片(time slice)是固定的,当某个task的时间片用完以后,此task将被放到此优先级对应的ready queue的末尾,然后调度ready queue上排在第一位的task来运行。

注意:rhino内核Round-Robin是考虑了task的优先级的,如果有一个高优先级的task就绪了,不论当前task的时间片是否用完,CPU都会立即去执行高优先级的task,当被中断的task恢复执行时,它将继续执行剩下的时间片。

(2)ready queue

rhino系统支持最多256个优先级,用户可以根据应用需求配置系统支持的最大优先技术。对于每个优先级,rhino维护了一个ready queue。

4、task创建

rhino内核支持两种task创建方式:

(1)静态创建:krhino_task_create()。

(2)动态创建:krhino_task_dyn_create()。

静态创建task的代码示例如下:


ktask_t            g_timer_task;

cpu_task_t      g_timer_task_stack[RHINO_CONFIG_TIMER_TASK_STACK_SIZE];

krino_task_create(&g_timer_task,"timer_task",NULL,RHINO_CONFIG_TIMER_TASK_PRI,0u,g_timer_task_stack,

                                RHINO_CONFIG_TIMER_TASK_STACK_SIZE,timer_task,1u);


动态创建task的代码示例如下:


ktask_t            *g_aos_init;

krino_task_dyn_create(&g_aos_init,"aos-init",0,AOS_DEFAULT_APP_PRI,0,AOS_START_STACK,

                               sys_init,1);


5、任务栈

没有办法可以保证当前任务栈不溢出,操作系统所能做的和需要做的事情有两个:第一是侦测任务栈溢出;第二是悬起溢出的task,防止此task给系统带来更大的危害。

(1)栈溢出侦测

①在支持内存管理单元MMU的操作系统中,可以给任务栈上下各自加入一个警戒区,,一般是一个页的空间,并且设置此警戒区为不可访问,一旦有任务栈上溢出或者下溢出,那么将会导致一个硬件异常,从而可以在异常处理中捕捉这个错误,并定位是哪个task导致的,从而做出进一步处理。

②在不支持MMU的操作系统中,我们可以在任务栈的边缘写入一个特定的初始值,然后检测该初始值是否变化,如果数值发生了变化,则说明发生了栈溢出,因为栈的边缘被修改了。

基于当前的rhino内核,因为还不支持MMU,所以采取了第二种方法来侦测任务栈溢出。任务栈的边缘在创建任务时初始化成一个固定的值RHINO_TASK_STACK_OVF_MAGIC。

rhino内核提供了一个函数krhino_stack_ovf_check(),可以用来检测当前task是否有栈溢出的情况。

(2)栈空间检测

在编写应用程序时,一般很难知道应用程序所在task的精确栈空间耗费尺寸数据。为了防止栈溢出,可以在开始时把栈空间分配的大一些,在程序运行以后,可以通过rhino内核提供的任务栈空间剩余检测功能来查看任务实际栈空间剩余大小。然后再调整任务栈空间的大小。相关函数如下:

①检测任务栈空间历史最小剩余:

kstart_t krhino_task_stack_min_free(ktask_t *task,size_t *free)

②检测当前时刻任务栈空间的剩余大小:

kstart_t krhino_task_stack_cur_free(ktask_t *task,size_t *free)

③获取任务的调度机制:

kstart_t krhino_sched_policy_get(ktask_t *task,uint8_t *policy)

④获取任务关联信息:

kstart_t krhino_task_info_get(ktask_t *task,size_t idx,void **info)

6、任务执行控制

任务执行控制主要包括任务休眠、任务避让、任务悬起、任务继续、任务强行放弃等待。

(1)任务睡眠:kstart_t krhino_task_sleep(tick_t ticks)

将当前任务推迟一些时间在继续执行。这个函数会将当前task从ready queue中删除,并插入g_tick_head队列,当给定的时间过去了,如果没有更高级的任务需要处理,则继续执行被推迟的task。

(2)任务避让:kstart_t krhino_task_yield(void)

将当前task从ready queue中取出,并重新排入ready queue的尾部,目的是让当前task让出CPU,让其他task得到执行。

(3)任务悬起:kstart_t task_suspend(ktask_t *task)

将当前task悬起,悬起当前task后,OS将调度新的task继续执行。

(4)任务继续:kstart_t task_resume(ktask_t *task)

将悬起的任务插入ready queue队列,且将任务状态改为RDY。

(5)任务强行放弃等待:kstart_t krhino_task_wait_abort(ktask_t *task)

将处于等待状态的任务从相应等待资源队列中删除,并插入ready queue尾部,标记task的状态为RDY。如果目标任务正在睡眠,那么可以使用此功能使目标task立即苏醒。

7、调度机制的控制

rhino内核支持两种内核调度机制,基于优先级的抢占模式和Round-Robin模式。设定某一个task的调度机制的接口函数是:

kstart_t krhino_sched_policy_set(ktask_t *task,uint8_t policy)





回复

使用道具 举报

168

主题

184

帖子

515

积分

工程师

Rank: 2

积分
515
发表于 2019-11-8 08:58:48 | 显示全部楼层
kstart_t krhino_sched_policy_set()这里不是可以设置为FIFO 或RR吗?如果同一个优先级列表既有FIFO任务,又有RR任务时应该怎么执行。比如:有4个任务处于就绪态,2个是FIFO的,2个是RR的,则是怎么执行的。
回复

使用道具 举报

15

主题

38

帖子

154

积分

利尔达员工

Rank: 9Rank: 9Rank: 9

积分
154
 楼主| 发表于 2019-11-11 11:36:51 | 显示全部楼层
13675829026 发表于 2019-11-8 08:58
kstart_t krhino_sched_policy_set()这里不是可以设置为FIFO 或RR吗?如果同一个优先级列表既有FIFO任务, ...

我不是很懂你说的场景,但是在AliOS Things的RR模式下,rhino是考虑到task'的优先级的,如果有一个高优先级的task就绪,不论当前的task的时间片是否用完,CPU都会立即去执行高优先级的task,当被中断的task恢复执行时,他将继续执行剩下的时间片。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表