xuos-web/docs/doc/kernel/task.md

18 KiB
Raw Blame History

任务

任务管理

任务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  running_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 任务名称

任务通信

XiUOS提供多种任务间通信机制包括消息队列、信号量、互斥量与事件集。

消息队列

消息队列message queue提供可供多个任务读或写的消息缓冲区其中消息指固定长度的任意数据块。消息队列的容量有限。当消息队列满时向消息队列写入的任务会被挂起当消息队列空时从消息队列读取的任务会被挂起。

消息队列结构定义

struct xs_MsgQueue
{
    xs_uint16            id; 

    void                 *msg_buf;
	xs_uint16            index;
    xs_uint16            num_msgs;
    xs_uint16            each_len;
    xs_uint16            max_msgs;

    XS_DOUBLE_LINKLIST   send_pend_list;
    XS_DOUBLE_LINKLIST   recv_pend_list;
	XS_DOUBLE_LINKLIST   link;
};
成员 描述
id 消息队列ID用于唯一标识一个消息队列
msg_buf 用于存储消息的缓冲区的首地址
index 当前缓冲区中第一个消息的序号
num_msgs 当前缓冲区中的消息数量
each_len 每条消息的大小,单位为字节
max_msgs 缓冲区中最多能存放的消息数量
send_pend_list 被挂起的发送任务链表
recv_pend_list 被挂起的接收任务链表
link 系统中所有消息队列构成的链表

消息队列函数接口

xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_len, xs_uint16 max_msgs);

该函数用于创建一个消息队列。创建成功后新的消息队列会被加入内核的消息队列管理链表并返回该消息队列的IDID默认范围0-255可配置。

参数 描述
msg_len 每条消息的长度,单位为字节
max_msgs 缓冲区中最多存放的消息数量
void xs_UserMsgQueueDelete(xs_uint16 id);

该函数用于删除一个已创建的消息队列。

参数 描述
id 待删除的消息队列ID
xs_int32 xs_UserMsgQueueSend(xs_uint16 id, const void *msg, xs_uint16 size, xs_ticks_x wait_time);

该函数用于向消息队列发送一个消息。若消息发送成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。

参数 描述
id 目标消息队列ID
msg 消息数据首地址
size 消息长度
wait_time 等待时间上限单位ticks若为0则不等待
xs_int32 xs_UserMsgQueueRecv(xs_uint16 id, void *buf, xs_uint16 size, xs_ticks_x wait_time);

该函数用于从消息队列接收一个消息。若消息接收成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。

参数 描述
id 来源消息队列ID
buf 用于接收消息数据的缓冲区
size 缓冲区大小
wait_time 等待时间上限单位ticks若为0则不等待
xs_int32 xs_UserMsgQueueReinit(xs_uint16 id);

该函数用于将一个消息队列复位。

参数 描述
id 来源消息队列ID

信号量

信号量semaphore具有一个给定的初值。任务可以获取或释放一个信号量。当任务获取信号量时信号量的值递减释放信号量时值递增。当信号量值递减至0时后续尝试获取信号量的任务会被挂起。每当一个已获取信号量的任务释放信号量时内核会从信号量挂起队列上唤醒一个任务。信号量可以用于实现任务间的同步与互斥。

信号量结构定义

struct xs_Semaphore
{
	xs_uint16                id;
	xs_uint16                value;
	
	XS_DOUBLE_LINKLIST       pend_list;
	XS_DOUBLE_LINKLIST       link;
};
成员 描述
id 信号量ID用于唯一标识一个信号量
value 信号量的当前值
pend_link 挂起任务链表
link 系统中所有信号量构成的链表

信号量函数接口

xs_int32 xs_UserSemaphoreCreate(xs_uint16 val);

该函数用于创建一个信号量。创建成功后新的信号量会被加入内核的信号量管理链表并返回该信号量的IDID默认范围0-255可配置。

参数 描述
val 信号量的初值
void xs_UserSemaphoreDelete(xs_uint16 id);

该函数用于删除一个已创建的信号量。

参数 描述
id 待删除的信号量的ID
xs_int32 xs_UserSemaphoreObtain(xs_uint16 id, xs_ticks_x wait_time);

该函数用于获取一个信号量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。

参数 描述
id 欲获取的信号量的ID
wait_time 等待时间上限单位ticks若为0则不等待
xs_int32 xs_UserSemaphoreAbandon(xs_uint16 id);

该函数用于释放一个信号量。

参数 描述
id 待释放的信号量的ID
xs_int32 xs_UserSemaphoreSetValue(xs_uint16 id, xs_uint16 val);

该函数用于将一个信号量的值进行重置。

参数 描述
id 来源消息队列ID
val 重置的信号量的值

互斥量

互斥量mutex可以视作一个初值为1的信号量同样有获取和释放操作。互斥量一般用于任务间的互斥。

互斥量结构定义

struct xs_Mutex
{
	xs_uint16                     id;
	
	xs_uint8                      origin_prio;
	xs_uint8                      recursive_cnt;
	
	struct task_descriptor        *holder;

	XS_DOUBLE_LINKLIST            pend_list;
	XS_DOUBLE_LINKLIST            link;
};
成员 描述
id 互斥量ID用于唯一标识一个互斥量
origin_prio 持有互斥量的任务的原优先级,用于避免优先级反转
recursive_cnt 持有互斥量的任务获取互斥量的次数,用于实现递归锁
holder 持有互斥量的任务
pend_list 挂起任务链表
link 系统中所有互斥量构成的链表

互斥量函数接口

xs_int32 xs_UserMutexCreate(void);

该函数用于创建一个互斥量。创建成功后新的互斥量会被加入内核的互斥量管理链表并返回该互斥量的IDID默认范围0-255可配置。

void xs_UserMutexDelete(xs_uint16 id);

该函数用于删除一个已创建的互斥量。

参数 描述
id 待删除的互斥量的ID
xs_int32 xs_UserMutexObtain(xs_uint16 id, xs_ticks_x wait_time);

该函数用于获取一个互斥量。若获取成功则返回XS_EOK若不成功等待超时则返回-XS_ETIMEOUT。

参数 描述
id 欲获取的互斥量的ID
wait_time 等待时间上限单位ticks若为0则不等待
xs_int32 xs_UserMutexAbandon(xs_uint16 id);

该函数用于释放一个互斥量。

参数 描述
id 待释放的互斥量的ID

事件集

事件集event set允许用户定义一个事件集合集合中的每个事件都可以被任务触发或等待。任务可以同时等待多个事件此时等待触发的条件可以配置为AND或者OR当等待触发条件配置为AND时只有所有被等待的事件均被触发才视作等待结束当等待触发条件配置为OR时任意一个被等待的事件触发即视作等待结束。使用事件集可以实现多对多的任务间同步与互斥。

事件集结构定义

#define XS_EVENT_AND        (1 << 29)   
#define XS_EVENT_OR         (1 << 30)
#define XS_EVENT_AUTOCLEAN  (1 << 31)
#define XS_EVENTS(x)        (1 << x)

struct xs_event
{
	xs_uint16                    id; 
	xs_uint32                    trigge_way;
	
	XS_DOUBLE_LINKLIST           pend_list;
	XS_DOUBLE_LINKLIST           link;
};
成员 描述
id 事件集ID用于唯一标识一个事件集
trigge_way 高3位用于记录事件集属性等待触发条件、是否自动清空低29位用于表示至多29个事件
pend_list 等待任务链表
link 系统中所有事件集构成的链表

事件集函数接口

xs_int32 xs_UserEventCreate(xs_uint32 options);

该函数用于创建一个事件集。options参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN。创建成功后新的事件集会被加入内核的事件集管理链表并返回该事件集的IDID默认范围0-255可配置。

参数 描述
options 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN
void xs_UserEventDele(xs_uint16 id);

该函数用于删除一个已创建的事件集。

参数 描述
id 待删除的事件集的ID
xs_int32 xs_UserEventTrigger(xs_uint16 id, xs_uint32 events);

该函数用于触发事件集中的一组事件。

参数 描述
id 事件集ID
events 欲触发的事件其中被置1的位标识被触发的事件 ,可以使用XS_EVENTS宏按位或发送事件类型
xs_int32 xs_UserEventProcess(xs_uint16 id, xs_uint32 events, xs_ticks_x wait_time);

该函数用于等待事件集中的一组事件。若等待成功则返回XS_EOK此时若XS_EVENT_AUTOCLEAN被打开则事件集中所有已触发事件会被清空若等待失败超时则返回-XS_ETIMEOUT。

参数 描述
id 事件集ID
events 欲等待的事件其中被置1的位标识被等待的事件可以使用XS_EVENTS宏按位或接收事件类型
wait_time 等待时间上限单位ticks若为0则不等待
xs_int32 xs_UserEventConfig(xs_uint16 id, xs_uint32 options);

该函数用于配置事件集中的一种事件类型。若等配置成功则返回XS_EOKoptions参数用于配置事件集的属性。可配置的属性有等待触发方式XS_EVENT_AND或XS_EVENT_OR及等待触发后是否自动清空其他已触发的事件XS_EVENT_AUTOCLEAN

参数 描述
id 事件集ID
options 事件集配置选项须在XS_EVENT_AND及XS_EVENT_OR中指定其一并可以按位或上XS_EVENT_AUTOCLEAN
xs_int32 xs_UserEventReinit(xs_uint16 id);

该函数用于将一个事件的值进行重置。

参数 描述
id 来源消息队列ID

使用场景

  • 在多处理器设备上,多个任务可以并行运行,从而提高处理器的利用率。
  • 在一些中断驱动的应用中,如果中断需要处理的工作过于复杂,则可以创建一个任务专门用于处理相关工作,从而改善中断延迟。