7.5 KiB
任务管理
任务(task)是XiUOS中处理器使用权分配的最小单位。每个任务有自己的程序栈与寄存器上下文,在多处理器平台上可以互不干扰地同时运行,但单个处理器上任意时刻只能有一个任务在运行。用户可以使用XiUOS提供的接口创建任意数量的任务。内核会对系统中的所有任务按照一定策略(抢占式优先级或先来先服务)进行调度,以最大限度地利用处理器资源。用户可以使用XiUOS提供的接口创建任意数量的任务。
任务状态
系统中的任务在任意时刻都处于就绪(ready)、运行(running)、阻塞/挂起(suspend)、退出(quit)四种状态之一。状态之间的变化关系如下图所示。
任务在创建完成后会进入就绪状态并被加入就绪队列等待内核调度。当任务被调度开始运行时,任务会进入运行状态。若任务在运行过程中被更高优先级的任务抢占,则被强占的任务会回到就绪队列并再次进入就绪状态。当任务在运行过程中申请资源失败时,任务会被挂起并进入挂起状态,并在所申请资源能够被满足时回到就绪状态。当任务执行完成,即从入口函数返回时,会进入终止状态,并由内核回收其相关资源。
任务调度
任务调度即从系统就绪队列中按一定策略选择任务,使其进入运行状态的过程。XiUOS支持以下调度方式:
- 抢占式优先级调度:在创建任务时可以指定任务的优先级,内核总是选取就绪队列中优先级最高的任务。当新创建的任务优先级高于正在运行的任务的优先级时,当前运行的任务会被抢占。若就绪队列中最高优先级任务有多个,则这些任务会按时间片轮转交替运行。
- 先来先服务(FIFO)调度:任务按照被创建的顺序依次被执行。当一个任务运行完成后,系统才会让下一个任务开始运行。
- 时间片轮转(RR)调度:任务按照分配的时间片执行,时间片结束,调度一个新的就绪任务执行,当前任务重新就绪,等待下一次的调度。
任务结构定义
每个任务在内核中由一个task_descriptor结构表示,二者一一对应。
struct task_descriptor
{
void *stack_pointer;
struct dync_sched_member dync_sched_member_x;
struct t_baseinfo t_baseinfo_x;
#ifdef XS_USING_SMP
struct smp_info smp_info_x;
#endif
#if defined(XS_USING_EVENT)
xs_uint32 event_ctrl1:3;
xs_uint32 event_ctrl2:29;
#endif
xs_err_t error;
XS_DOUBLE_LINKLIST link;
};
其中stack_pointer成员表示该任务的栈的起始地址,dync_sched_member_x成员包含与任务调度相关的信息,t_baseinfo_x包含任务的基本信息,smp_info_x包含与多处理器相关的信息,event_ctrl1/event_ctrl2用于实现事件集机制(见任务间通信部分文档),error为任务调用内核接口时最近的错误码,link用于将系统中的所有任务组织成一个双链表。各复合成员的详细定义如下:
struct task_baseinfo {
char name[XS_NAME_MAX];
void *func_entry;
void *func_param;
xs_uint32 stack_size;
xs_uint8 origin_prio;
};
struct task_baseinfo结构记录了任务的基本属性,包括任务的名称(name)、入口函数和参数(func_entry、func_param)、栈大小(stack_size)、优先级(origin_prio)。
struct dync_sched_member {
xs_uint8 stat;
xs_uint8 advance_cnt;
xs_uint8 cur_prio;
xs_ubase origin_timeslice;
xs_ubase rest_timeslice;
#ifdef XS_USING_TASK_ISOLATION
xs_uint8 isolation_flag;
void *isolation;
#endif
union {
XS_DOUBLE_LINKLIST sched_link;
XS_AVL sched_avl;
}
XS_DOUBLE_LINKLIST pend_link;
xs_Timer_t task_timer;
};
#define XS_SUSPEND ((1) << (0))
#define XS_READY ((1) << (1))
#define XS_RUNNING ((1) << (2))
#define XS_QUIT ((1) << (3))
struct dync_sched_member结构的成员用于记录与调度相关的信息。stat表示任务的当前状态,可以为挂起(XS_SUSPEND)、就绪(XS_READY)、运行(XS_RUNNING)或退出(XS_QUIT)。advance_cnt表示在配置成短作业预先调度时优先处理的时间片周期个数。cur_prio表示任务当前的优先级:为防止出现优先级反转,该优先级可以高于任务创建时配置的优先级。origin_timeslice表示在时间片轮转调度中该任务每次运行的时间片。地址空间隔离信息(isolation_flag变量和指针isolation)。sched_link、sched_avl构成的联合体为就绪队列节点,XiUOS中就绪队列可以配置为双链表(sched_link)或AVL树(sched_avl)。pend_link为任务挂起时使用的等待队列节点。task_timer用于任务睡眠的计时。
struct smp_info {
xs_uint8 combined_coreid;
xs_uint8 runing_coreid;
};
struct smp_info结构包含多处理器相关的信息,其成员分别表示该任务绑定的CPU ID与正在运行的CPU ID。
任务函数接口
struct xs_utask
{
char name[XS_NAME_MAX];
void *func_entry;
void *func_param;
xs_uint32 stack_size;
xs_uint8 prio;
};
typedef struct xs_utask struct xs_utask;
struct task_descriptor* xs_UserTaskCreate(xs_utask_x task);
该函数用于用户态创建一个任务。任务的各个属性由一个struct xs_utask结构表示,包括任务的名称、入口函数及参数、栈大小和优先级,在调用该函数时需要传入该结构的实例用于配置任务。任务创建成功后,内核会为其分配指定大小的栈及其他结构(如struct task_descriptor)结构,并返回任务描述符指针。
参数 | 描述 |
---|---|
task | 任务配置属性 |
xs_int32 xs_UserTaskDelete(struct task_descriptor task);
该函数用于删除一个任务,强制使其进入退出状态。若删除成功则返回XS_EOK,若失败则返回-XS_ERROR。
参数 | 描述 |
---|---|
task | 待删除的任务描述符 |
xs_int32 xs_UserTaskCoreCombine(struct task_descriptor task, xs_uint8 coreid);
该函数用于将任务绑定至指定的处理器上。若绑定成功则返回XS_EOK,若失败则返回-XS_ERROR。
参数 | 描述 |
---|---|
task_id | 待绑定的任务描述符 |
coreid | 带绑定的处理器ID |
xs_int32 xs_UserTaskCoreUncombine(struct task_descriptor task);
该函数用于解除任务与处理器的绑定。若解除成功则返回XS_EOK,若失败则返回-XS_ERROR。
参数 | 描述 |
---|---|
task | 待解除绑定的任务描述符 |
xs_int32 xs_UserTaskDelay(xs_ticks_x ticks);
该函数用于将当前任务挂起一定时间,单位为tick。挂起时间结束后,任务会进入就绪状态,可以继续被调度。
参数 | 描述 |
---|---|
ticks | 任务挂起时间,单位为tick |
struct task_descriptor* xs_UserTaskSearch(char *name)
该函数用于从任务名称获取任务描述符。
参数 | 描述 |
---|---|
name | 任务名称 |
使用场景
- 在多处理器设备上,多个任务可以并行运行,从而提高处理器的利用率。
- 在一些中断驱动的应用中,如果中断需要处理的工作过于复杂,则可以创建一个任务专门用于处理相关工作,从而改善中断延迟。