diff --git a/docs/.vuepress/sidebar.js b/docs/.vuepress/sidebar.js index 93ea43b..8abae34 100755 --- a/docs/.vuepress/sidebar.js +++ b/docs/.vuepress/sidebar.js @@ -3,7 +3,7 @@ const sidebar = { '/doc/intro', ], 'kernel': [ - '/doc/kernel/task/', + '/doc/kernel/task', '/doc/kernel/mm', '/doc/kernel/int', '/doc/kernel/tmr' diff --git a/docs/doc/kernel/README.md b/docs/doc/kernel/README.md index 3338434..0bc5923 100644 --- a/docs/doc/kernel/README.md +++ b/docs/doc/kernel/README.md @@ -2,7 +2,7 @@ --- -- [任务管理](/doc/kernel/task/) +- [任务管理](/doc/kernel/task.md) - [内存管理](/doc/kernel/mm.md) diff --git a/docs/doc/kernel/synchron.md b/docs/doc/kernel/synchron.md deleted file mode 100755 index 3ba5e03..0000000 --- a/docs/doc/kernel/synchron.md +++ /dev/null @@ -1 +0,0 @@ -# 资源管理 diff --git a/docs/doc/kernel/task.md b/docs/doc/kernel/task.md index ad4ca79..a75b882 100644 --- a/docs/doc/kernel/task.md +++ b/docs/doc/kernel/task.md @@ -1,24 +1,44 @@ -# 任务管理 +# 任务 + +* [任务管理](#management) + * [任务状态](#state) + * [任务调度](#sched) + * [任务结构定义](#struct) + * [任务函数接口](#api) +* [任务通信](#communication) + * [消息队列](#msg_quque) + * [信号量](#sem) + * [互斥量](#mutex) + * [事件集](#event) +* [使用场景](#situation) + + + +## 任务管理 + 任务(task)是XiUOS中处理器使用权分配的最小单位。每个任务有自己的程序栈与寄存器上下文,在多处理器平台上可以互不干扰地同时运行,但单个处理器上任意时刻只能有一个任务在运行。用户可以使用XiUOS提供的接口创建任意数量的任务。内核会对系统中的所有任务按照一定策略(抢占式优先级或先来先服务)进行调度,以最大限度地利用处理器资源。用户可以使用XiUOS提供的接口创建任意数量的任务。 + -## 任务状态 - +### 任务状态 + 系统中的任务在任意时刻都处于就绪(ready)、运行(running)、阻塞/挂起(suspend)、退出(quit)四种状态之一。状态之间的变化关系如下图所示。 ![task_status](task_status.png) 任务在创建完成后会进入就绪状态并被加入就绪队列等待内核调度。当任务被调度开始运行时,任务会进入运行状态。若任务在运行过程中被更高优先级的任务抢占,则被强占的任务会回到就绪队列并再次进入就绪状态。当任务在运行过程中申请资源失败时,任务会被挂起并进入挂起状态,并在所申请资源能够被满足时回到就绪状态。当任务执行完成,即从入口函数返回时,会进入终止状态,并由内核回收其相关资源。 + -## 任务调度 +### 任务调度 任务调度即从系统就绪队列中按一定策略选择任务,使其进入运行状态的过程。XiUOS支持以下调度方式: * 抢占式优先级调度:在创建任务时可以指定任务的优先级,内核总是选取就绪队列中优先级最高的任务。当新创建的任务优先级高于正在运行的任务的优先级时,当前运行的任务会被抢占。若就绪队列中最高优先级任务有多个,则这些任务会按时间片轮转交替运行。 * 先来先服务(FIFO)调度:任务按照被创建的顺序依次被执行。当一个任务运行完成后,系统才会让下一个任务开始运行。 * 时间片轮转(RR)调度:任务按照分配的时间片执行,时间片结束,调度一个新的就绪任务执行,当前任务重新就绪,等待下一次的调度。 + -## 任务结构定义 +### 任务结构定义 每个任务在内核中由一个task_descriptor结构表示,二者一一对应。 @@ -94,8 +114,9 @@ struct smp_info { ``` struct smp_info结构包含多处理器相关的信息,其成员分别表示该任务绑定的CPU ID与正在运行的CPU ID。 + -## 任务函数接口 +### 任务函数接口 ```c struct xs_utask @@ -168,6 +189,350 @@ struct task_descriptor* xs_UserTaskSearch(char *name) | --- | --- | | name | 任务名称 | + + + +## 任务通信 + +XiUOS提供多种任务间通信机制,包括消息队列、信号量、互斥量与事件集。 + + +### 消息队列 + +消息队列(message queue)提供可供多个任务读或写的消息缓冲区,其中消息指固定长度的任意数据块。消息队列的容量有限。当消息队列满时,向消息队列写入的任务会被挂起;当消息队列空时,从消息队列读取的任务会被挂起。 + +#### 消息队列结构定义 + +```c +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 | 系统中所有消息队列构成的链表 | + +#### 消息队列函数接口 + +```c +xs_int32 xs_UserMsgQueueCreate(xs_uint16 msg_len, xs_uint16 max_msgs); +``` + +该函数用于创建一个消息队列。创建成功后,新的消息队列会被加入内核的消息队列管理链表,并返回该消息队列的ID,ID默认范围0-255,可配置。 + +| 参数 | 描述 | +| --- | --- | +| msg_len | 每条消息的长度,单位为字节 | +| max_msgs | 缓冲区中最多存放的消息数量 | + +```c +void xs_UserMsgQueueDelete(xs_uint16 id); +``` + +该函数用于删除一个已创建的消息队列。 + +| 参数 | 描述 | +| --- | --- | +| id | 待删除的消息队列ID | + +```c +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,则不等待 | + +```c +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,则不等待 | + +```c +xs_int32 xs_UserMsgQueueReinit(xs_uint16 id); +``` + +该函数用于将一个消息队列复位。 + +| 参数 | 描述 | +| --- | --- | +| id | 来源消息队列ID | + + +### 信号量 + +信号量(semaphore)具有一个给定的初值。任务可以获取或释放一个信号量。当任务获取信号量时信号量的值递减,释放信号量时值递增。当信号量值递减至0时,后续尝试获取信号量的任务会被挂起。每当一个已获取信号量的任务释放信号量时,内核会从信号量挂起队列上唤醒一个任务。信号量可以用于实现任务间的同步与互斥。 + +#### 信号量结构定义 + +```c +struct xs_Semaphore +{ + xs_uint16 id; + xs_uint16 value; + + XS_DOUBLE_LINKLIST pend_list; + XS_DOUBLE_LINKLIST link; +}; +``` + +| 成员 | 描述 | +| --- | --- | +| id | 信号量ID,用于唯一标识一个信号量 | +| value | 信号量的当前值 | +| pend_link | 挂起任务链表 | +| link | 系统中所有信号量构成的链表 | + +#### 信号量函数接口 + +```c +xs_int32 xs_UserSemaphoreCreate(xs_uint16 val); +``` + +该函数用于创建一个信号量。创建成功后,新的信号量会被加入内核的信号量管理链表,并返回该信号量的ID,ID默认范围0-255,可配置。 + +| 参数 | 描述 | +| --- | --- | +| val | 信号量的初值| + +```c +void xs_UserSemaphoreDelete(xs_uint16 id); +``` + +该函数用于删除一个已创建的信号量。 + +| 参数 | 描述 | +| --- | --- | +| id | 待删除的信号量的ID | + +```c +xs_int32 xs_UserSemaphoreObtain(xs_uint16 id, xs_ticks_x wait_time); +``` + +该函数用于获取一个信号量。若获取成功则返回XS_EOK,若不成功(等待超时)则返回-XS_ETIMEOUT。 + +| 参数 | 描述 | +| --- | --- | +| id | 欲获取的信号量的ID | +| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | + +```c +xs_int32 xs_UserSemaphoreAbandon(xs_uint16 id); +``` + +该函数用于释放一个信号量。 + +| 参数 | 描述 | +| --- | --- | +| id | 待释放的信号量的ID | + +```c +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 | 系统中所有互斥量构成的链表 | + +#### 互斥量函数接口 + +```c +xs_int32 xs_UserMutexCreate(void); +``` + +该函数用于创建一个互斥量。创建成功后,新的互斥量会被加入内核的互斥量管理链表,并返回该互斥量的ID,ID默认范围0-255,可配置。 + +```c +void xs_UserMutexDelete(xs_uint16 id); +``` + +该函数用于删除一个已创建的互斥量。 + +| 参数 | 描述 | +| --- | --- | +| id | 待删除的互斥量的ID | + +```c +xs_int32 xs_UserMutexObtain(xs_uint16 id, xs_ticks_x wait_time); +``` + +该函数用于获取一个互斥量。若获取成功则返回XS_EOK,若不成功(等待超时)则返回-XS_ETIMEOUT。 + +| 参数 | 描述 | +| --- | --- | +| id | 欲获取的互斥量的ID | +| wait_time | 等待时间上限,单位ticks;若为0,则不等待 | + +```c +xs_int32 xs_UserMutexAbandon(xs_uint16 id); +``` + +该函数用于释放一个互斥量。 + +| 参数 | 描述 | +| --- | --- | +| id | 待释放的互斥量的ID | + + +### 事件集 + +事件集(event set)允许用户定义一个事件集合,集合中的每个事件都可以被任务触发或等待。任务可以同时等待多个事件,此时等待触发的条件可以配置为AND或者OR:当等待触发条件配置为AND时,只有所有被等待的事件均被触发才视作等待结束;当等待触发条件配置为OR时,任意一个被等待的事件触发即视作等待结束。使用事件集可以实现多对多的任务间同步与互斥。 + +#### 事件集结构定义 + +```c +#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 | 系统中所有事件集构成的链表 | + +#### 事件集函数接口 + +```c +xs_int32 xs_UserEventCreate(xs_uint32 options); +``` + +该函数用于创建一个事件集。options参数用于配置事件集的属性。可配置的属性有等待触发方式(XS_EVENT_AND或XS_EVENT_OR)及等待触发后是否自动清空其他已触发的事件(XS_EVENT_AUTOCLEAN)。创建成功后,新的事件集会被加入内核的事件集管理链表,并返回该事件集的ID,ID默认范围0-255,可配置。 + +| 参数 | 描述 | +| --- | --- | +| options | 事件集配置选项,须在XS_EVENT_AND及XS_EVENT_OR中指定其一,并可以按位或上XS_EVENT_AUTOCLEAN | + +```c +void xs_UserEventDele## +该函数用于删除一个已创建的事件集。 + +| 参数 | 描述 | +| --- | --- | +| id | 待删除的事件集的ID | + +```c +xs_int32 xs_UserEventTrigger(xs_uint16 id, xs_uint32 events); +``` + +该函数用于触发事件集中的一组事件。 + +| 参数 | 描述 | +| --- | --- | +| id | 事件集ID | +| events | 欲触发的事件,其中被置1的位标识被触发的事件 ,可以使用XS_EVENTS宏按位或发送事件类型| + +```c +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,则不等待 | + +```c +xs_int32 xs_UserEventConfig(xs_uint16 id, xs_uint32 options); +``` + +该函数用于配置事件集中的一种事件类型。若等配置成功则返回XS_EOK,options参数用于配置事件集的属性。可配置的属性有等待触发方式(XS_EVENT_AND或XS_EVENT_OR)及等待触发后是否自动清空其他已触发的事件(XS_EVENT_AUTOCLEAN)。 + +| 参数 | 描述 | +| --- | --- | +| id | 事件集ID | +| options | 事件集配置选项,须在XS_EVENT_AND及XS_EVENT_OR中指定其一,并可以按位或上XS_EVENT_AUTOCLEAN | + +```c +xs_int32 xs_UserEventReinit(xs_uint16 id); +``` + +该函数用于将一个事件的值进行重置。 + +| 参数 | 描述 | +| --- | --- | +| id | 来源消息队列ID | + + ## 使用场景 * 在多处理器设备上,多个任务可以并行运行,从而提高处理器的利用率。 diff --git a/docs/doc/kernel/task/README.md b/docs/doc/kernel/task/README.md deleted file mode 100644 index 1a1de66..0000000 --- a/docs/doc/kernel/task/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# 任务管理 - ---- - -- [线程管理](/doc/kernel/task.md) - -- [线程ipc](/doc/kernel/ipc.md) - diff --git a/docs/doc/kernel/threadcommunication.md b/docs/doc/kernel/threadcommunication.md deleted file mode 100644 index f077f2b..0000000 --- a/docs/doc/kernel/threadcommunication.md +++ /dev/null @@ -1,179 +0,0 @@ -# 线程间通信 -XiUOS 的线程间通信使用管道和消息队列进行通信。下面将分别介绍。 - -## 消息队列 -### 消息队列的工作机制 -消息队列能够接收线程或中断产生的不固定长度的消息,并储存到自己的内存空间中。其他线程可以从消息队列中读取相应的消息。当消息队列为空时,挂起读取线程,当有新的消息到达时,唤醒读取线程进行读取。 -### 结构体定义和函数接口 -#### 结构体定义 -```C -struct xs_MessageQueue -{ - char name[XS_NAME_MAX]; - xs_uint8 style; - - xs_uint8 sign; - - - xs_list_t link; - - xs_list_t pend_list; - - void *msg_buf; - - xs_uint16 size; - xs_uint16 max_msgs; - - xs_uint16 index; - - void *mq_listhead; - void *mq_listtail; - void *mq_free; - - xs_list_t pend_sender_thread; -}; -typedef struct xs_MessageQueue *xs_messagequeue_t; -``` -| 参数 | 描述 | -| ------ | ------ | -| name | 消息队列名称 | -| style | 线程等待的方式,可以取FIFO或PRIO | -| sign | 标记消息队列的创建方式,静态创建或动态创建 | -| link | 消息队列存放的列表 | -| pend_list | 线程等待队列 | -| msg_buf | 存放消息的缓存区 | -| size | 缓存区大小 | -| max_msgs | 一条消息的最大长度 | -| index | 当前消息数 | -| mq_listhead | 消息链表头 | -| mq_listtail | 消息链表尾 | -| mq_free | 空闲消息链表 | -| pend_sender_thread | 发送线程的挂起等待队列 | - - -#### 函数接口 -```C -xs_err_t xs_InitMessageQueue(xs_messagequeue_t mq, - const char *name, - void *msgpool, - xs_size_t msg_size, - xs_size_t pool_size, - xs_uint8 flag) -``` -该函数用于初始化一个静态消息队列,并将它加入消息队列管理列表中。创建成功后返回`XS_OK`。
-| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -| name | 消息队列名称 | -| msgpool | 指向存放消息的内存空间的指针 | -| msg_size | 一条消息的最大长度 | -| pool_size | 存放消息的内存区大小 | -| flag | 消息队列采用的等待方式,可取FIFO或PRIO | -
- -```C -xs_err_t xs_DetachMessageQueue(xs_messagequeue_t mq) -``` -该函数用于将一个静态消息队列从消息队列管理列表中移除。移除成功则返回`XS_OK`。
-| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -
- -```C -xs_messagequeue_t xs_CreateMessageQueue(const char *name, - xs_size_t msg_size, - xs_size_t max_msgs, - xs_uint8 flag) -``` -该函数用于动态创建一个消息队列,并将消息队列加入消息队列管理列表。
-| 参数 | 描述 | -| ------ | ------ | -| name | 消息队列名称 | -| msg_size | 缓冲区的大小 | -| max_msgs | 一条消息的最大长度 | -| flag | 消息队列采用的等待方式,可取FIFO或PRIO | -
- -```C -xs_err_t xs_DeleteMessageQueue(xs_messagequeue_t mq) -``` -该函数用于将由`xs_CreateMessageQueue`创建的消息队列从消息队列管理列表中删除。
-| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -
- -```C -xs_err_t xs_MessageQueueSendwait(xs_messagequeue_t mq, - const void *buffer, - xs_size_t size, - xs_int32 timeout) -``` -发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,把线程或者中断服务程序发送的消息内容复制到消息块上,然后把该消息块挂到消息队列的尾部,成功则返回`XS_EOK`。如果消息长度大于最大长度,则返回`XS_ERROR`。如果消息队列满了,则根据超时时间设定进行等待,超时则返回`-XS_EFULL`。
- -| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -| buffer | 消息内容 | -| size | 消息大小 | -| timeout | 超时时间 | -
- -```C -xs_err_t xs_MessageQueueSend(xs_messagequeue_t mq, const void *buffer, xs_size_t size) -``` -该函数是timeout为0的`xs_MessageQueueSendwait`。 -
- -| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -| buffer | 消息内容 | -| size | 消息大小 | -
- -```C -xs_err_t xs_MessageQueueUrgentSend(xs_messagequeue_t mq, const void *buffer, xs_size_t size) -``` - -发送紧急消息和发送普通消息的区别是:当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。
- -| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -| buffer | 消息内容 | -| size | 消息大小 | -
- -```C -xs_err_t xs_MessageQueueReceive(xs_messagequeue_t mq, - void *buffer, - xs_size_t size, - xs_int32 timeout) -``` -当队列中有消息时,接收消息。队列中没有消息时,根据超时时间设定进行等待。接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。成功收到消息返回`XS_EOK`,超时返回`XS_ETIMEOUT`。接收消息失败返回`-XS_ERROR`。 -
- -| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -| buffer | 消息内容 | -| size | 消息大小 | -| timeout | 超时时间 | -
- -```C -xs_err_t xs_CmdControlMessageQueue(xs_messagequeue_t mq, int cmd, void *arg) -``` -该函数用于获取或设置消息队列的其他属性。目前当cmd == XS_LINKLIST_CMD_RESET时,重新初始化消息队列。 -
- -| 参数 | 描述 | -| ------ | ------ | -| mq | 消息队列对象指针 | -| cmd | 需要执行的命令 | -| arg | 命令的参数 | -
- -## 管道 \ No newline at end of file