Guo XIn
291e661666
|
5 months ago | |
---|---|---|
.. | ||
.TestbedReport | 5 months ago | |
build | 5 months ago | |
examples | 5 months ago | |
sources | 5 months ago | |
tools | 5 months ago | |
LICENSE | 5 months ago | |
README.md | 5 months ago | |
cloc-2.00.exe | 5 months ago |
README.md
KLite 参考手册
更新日期: 2023.04.08
一、简介
KLite 是由个人开发者于2015年编写的嵌入式操作系统内核,并以MIT协议开放源代码。
KLite的定位是一款入门级的嵌入式实时操作系统内核,以简洁易用为设计目标,旨在降低嵌入式RTOS的入门难度。
代码干净工整、架构清晰、函数接口简单易用、不使用条件编译、移植简单、无需配置和裁减。
可能是目前最简洁易用的RTOS。
功能特性:
- 资源占用极小(ROM:2KB,RAM:0.5KB)
- 优先级抢占
- 时间片抢占(相同优先级)
- 支持创建相同优先级的线程
- 丰富的线程通信机制
- 动态内存管理
- 多编译器支持(GCC,IAR,KEIL)
作者简介: 蒋晓岗,男,现居成都,毕业于成都信息工程大学,从事嵌入式软件开发十年。
二、开始使用
KLite目前支持ARM7、ARM9、Cortex-M0、Cortex-M3、Cortex-M4、Cortex-M7内核。
以上平台如:全志F1C100S、STM32FXXX、NRF528XX等,请参考相关例程。
对于Cortex-M架构的MCU,实际上只需要修改cmsis.c里面的#include,比如#include "stm32f10x.h"
由于KLite不使用条件编译,因此可以预编译kernel源码为kernel.lib,并保留kernel.h,可以有效减少重复编译的时间。
main.c的推荐写法如下:
//只需要包含这一个头文件
#include "kernel.h"
//用于初始化应用程序的线程
void init(void *arg)
{
//在这里完成外设和驱动初始化
//并创建更多线程实现不同的功能
//thread_create(...)
}
//空闲线程,只需调用kernel_idle即可
void idle(void *arg)
{
kernel_idle();
}
//C语言程序入口
void main(void)
{
static uint8_t heap[HEAP_SIZE]; /* 定义堆内存 */
kernel_init(heap, sizeof(heap)); /* 系统初始化 */
thread_create(idle, 0, 0); /* 创建idle线程 */
thread_create(init, 0, 0); /* 创建init线程 */
kernel_start(); /* 启动系统 */
}
三、核心功能
核心功能的源码在sources/kernel/目录,是KLite最核心的部分。
使用这些功能,只需要包含头文件
#include "kernel.h"
3.1 内核管理
- void kernel_init(void *heap_addr, uint32_t heap_size);
参数:heap_addr
动态分配起始地址
参数:heap_size
动态分配内存大小
返回:无
描述:用于内核初始化在调用内核初始化时需保证中断处于关闭状态, 此函数只能执行一次,在初始化内核之前不可调用内核其它函数。
- void kernel_start(void);
参数:无
返回:无
描述:用于启动内核,此函正常情况下不会返回,在调用之前至少要创建一个线程
- uint32_t kernel_version(void);
参数:无
返回:KLite版本号,BIT[31:24]主版本号,BIT[23:16]次版本号,BIT[15:0]修订号
描述:此函数可以获取KLite的版本号命名规则:
主版本:架构调整,比较大的修改,与旧版本可能会不兼容
次版本:功能调整,主要涉及新增或删除功能
修订号:细节优化或BUG修复
- void kernel_idle(void);
参数:无
返回:无
描述:处理内核空闲事务,回收线程资源此函数不会返回。必须单独创建一个线程来调用。由用户创建空闲线程是为了实现灵活配置空闲线程的stack大小,不使用宏定义来进行stack的配置。 如果使用宏定义来配置stack大小,那么代码编译成lib之后就无法修改了,失去了灵活性。
- uint32_t kernel_idle_time(void);
参数:无
返回:系统空闲时间(毫秒)
描述:获取系统从启动到现在空闲线程占用CPU的总时间,可使用此函数和kernel_tick_count()
一起计算CPU占用率
- void kernel_tick(uint32_t time);
参数:滴答周期(毫秒)
返回:无
描述:此函数不是用户API,而是由CPU的滴答时钟中断程序调用,为系统提供时钟源。
滴答定时器的周期决定了系统计时功能的细粒度,主频较低的处理器推荐使用10ms周期,主频较高则使用1ms周期。在这里把滴答时间转为毫秒单位,应用层就不必使用宏定义来进行单位转换,起到简化调用的目的。
如果硬件定时器不能产生1ms的时钟,比如RTC=32768Hz,只能产生1024Hz的中断源,周期为0.97ms,这就很尴尬!
方案一:软件修正误差,在1024个周期内,均匀地跳过24次中断。
方案二:设置中断周期为125ms,这是在32768Hz时钟下能得到的最小整数时间。
方案三:放弃毫秒为时间单位,老老实实用滴答数做为时间单位。
- uint32_t kernel_tick_count(void);
参数:无
返回:系统运行时间(毫秒)
描述:此函数可以获取内核从启动到现在所运行的总时间
3.2 内存管理
- heap_t heap_create(void *addr, uint32_t size);
参数:addr
待创建堆内存起始地址
size
该堆内存的长度
返回:堆内存对象,申请失败返回NULL
描述:用户在指定内存创建一个用于动态管理的堆内存为系统中不同的模块创建一个独立的堆可以提高稳定性和运行效率。
- void *heap_alloc(heap_t heap, uint32_t size);
参数:heap
堆内存对象
size
要申请的内存大小
返回:申请成功返回内存指针,申请失败返回NULL
描述:从堆中申请一段连续的内存,功能和标准库的malloc()
一样严格来说调用此函数应该检查返回值是否为
NULL
, 但每次heap_alloc
都要写检查返回值的代码可能有点繁琐或者容易有遗漏的地方, 所以此函数在返回NULL
之前会调用一个HOOK函数,原型void heap_fault(void);
对于嵌入式系统来说申请内存失败是严重错误,所以我们可以偷懒只在heap_fault()
函数中统一处理错误。
- void heap_free(heap_t heap, void *mem);
参数:heap
堆内存对象
mem
要释放的内存指针
返回:无
描述:释放由heap_malloc()
申请的内存,功能和标准库的free()
一样
- void heap_usage(heap_t heap, uint32_t *used, uint32_t *free);
参数:
heap
堆内存对象
used
输出已使用内存数量(字节),此参数可以为NULL
free
输出空闲内存数量(字节),此参数可以为NULL
返回:无
描述:获取内存用量信息,可使用此函数关注系统内存消耗,以适当调整内存分配
3.3 线程管理
- thread_t thread_create(void(entry)(void), void *arg, uint32_t stack_size);
参数:entry
线程入口函数
参数:arg
线程入口函数的参数
参数:stack_size
线程的栈大小(字节),为0则使用系统默认值(1024字节)
返回:成功返回线程句柄,失败返回NULL
描述:创建新线程,并加入就绪队列系统自动为新线程分配内存和栈空间,如果栈设置太小运行过程中可能会产生栈溢出
- void thread_delete(thread_t thread);
参数:thread
被删除的线程标识符
返回:无
描述:删除线程,并释放内存该函数不能用来结束当前线程如果想要结束当前线程请使用thread_exit()
或直接使用return退出主循环不推荐直接删除线程,可能会造成系统不稳定,因为被删除线程可能进入了临界区未释放,需考虑清楚再使用
-
void thread_set_priority(thread_t thread, uint32_t prio);
参数:thread
线程标识符
参数:prio
新的优先级THREAD_PRIORITY_HIGHEST
最高优先级
THREAD_PRIORITY_HIGHER
更高优先级
THREAD_PRIORITY_HIGH
高优先级
THREAD_PRIORITY_NORMAL
默认优先级
THREAD_PRIORITY_LOW
低优先级
THREAD_PRIORITY_LOWER
更低优先级
THREAD_PRIORITY_LOWEST
最低优先级
THREAD_PRIORITY_IDLE
空闲优先级返回:无
描述:重新设置线程优先级,立即生效。
- uint32_t thread_get_priority(thread_t thread);
参数:thread
线程标识符
返回:目标线程的优先级
描述:获取指定线程的优先级
- thread_t thread_self(void);
参数: 无
返回: 调用线程的标识符
描述: 用于获取当前线程标识符
- void thread_sleep(uint32_t time);
参数:time
休眠时间(毫秒)
返回:无
描述:将当前线程休眠一段时间,释放CPU控制权
- void thread_yield(void);
参数:无
返回:无
描述:使当前线程立即释放CPU控制权,并进入就绪队列
- void thread_exit(void);
参数:无
返回:无
描述:退出当前线程,此函数不会立即释放线程占用的内存,需等待系统空闲时释放
-
void thread_suspend(void); -
void thread_resume(thread_t thread);由于直接挂起其它线程不安全,因此移除了这两个函数。 推荐使用信号量来阻塞线程,达到挂起线程和唤醒线程的目的。
这也是为什么C11标准和POSIX标准都没有定义线程挂起和恢复的接口。
- uint32_t thread_time(thread_t thread)
参数:thread
线程标识符
返回:指定线程运行时间(毫秒)
描述:获取线程自创建以来所占用CPU的时间在休眠期间的时间不计算在内.可以使用此函数来监控某个线程的CPU占用率
3.4 互斥锁
- mutex_t mutex_create(void)
参数:无
返回:成功返回互斥锁标识符,失败返回NULL
描述:创建一个互斥锁对象,支持递归锁
- void mutex_delete(mutex_t mutex)
参数:mutex
被删除的互斥锁标识符
返回:无
描述:删除一个互斥锁,并释放内存注意:在删除互斥锁的时候不会释放等待这个锁的线程,因此在删除之前请确认没有线程在使用它
- void mutex_lock(mutex_t mutex)
参数:mutex
互斥锁标识符
返回:无
描述:将mutex
指定的互斥锁标记为锁定状态,如果mutex
已被其它线程锁定,则调用线程将会被阻塞,直到另一个线程释放这个互斥锁参考:
C11:https://cloud.tencent.com/developer/section/1009716
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html
- bool mutex_try_lock(mutex_t mutex)
参数:mutex
互斥锁标识符
返回:如果锁定成功则返回true
,失败则返回false
描述:此函数是mutex_lock
的非阻塞版本参考:
C11:https://cloud.tencent.com/developer/section/1009721
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_trylock.html
- void mutex_unlock(mutex_t mutex)
参数:mutex
互斥锁标识符
返回:无
描述:释放mutex
标识的互斥锁,如果有其它线程正在等待这个锁,则会唤醒优先级最高的那个线程参考:
C11:https://cloud.tencent.com/developer/section/1009722
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_unlock.html
3.5 信号量
- sem_t sem_create(uint32_t value)
参数:value
信号量初始值
返回:成功返回信号量标识符,失败返回NULL
描述:创建信号量对象参考:
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html WIN32:https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea
- void sem_delete(sem_t sem)
参数:sem
信号量标识符
返回:无
描述:删除对象,并释放内存在没有线程使用它时才能删除,否则可能产生未知异常
- void sem_post(sem_t sem)
参数:
sem
信号量标识符
返回:无
描述:信号量计数值加1,如果有线程在等待信号量,此函数会唤醒优先级最高的线程参考:
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_post.html
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasesemaphore
- void sem_wait(sem_t sem)
参数:sem
信号量标识符
返回:无
描述:等待信号量,信号量计数值减1,如果当前信号量计数值为0,则线程阻塞,直到计数值大于0参考:
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_wait.html
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
- uint32_t sem_timed_wait(sem_t sem, uint32_t timeout)
参数:sem
信号量标识符
参数:timeout
超时时间(毫秒)
返回:剩余等待时间,如果返回0则说明等待超时
描述:定时等待信号量,并将信号量计数值减1,如果当前信号量计数值为0,则线程阻塞,直到计数值大于0,或者阻塞时间超过timeout
指定的时间参考:
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_timedwait.html
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
- uint32_t sem_value(sem_t sem)
参数:sem
信号量标识符
返回:信号量计数值
描述:返回信号量计数值参考:
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_getvalue.html
3.6 条件变量
- cond_t cond_create(void);
参数:无
返回:成功返回条件变量标识符,失败返回NULL
描述:创建条件变量对象
- void cond_delete(cond_t cond);
参数:cond
条件变量标识符
返回:无
描述:删除条件变量
- void cond_signal(cond_t cond);
参数:cond
条件变量标识符
返回:无
描述:唤醒一个被条件变量阻塞的线程,如果没有线程被阻塞则此函数什么也不做参考:
C11:https://cloud.tencent.com/developer/section/1009711
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html
- void cond_broadcast(cond_t cond);
参数:cond
条件变量标识符
返回:无
描述:唤醒全部被条件变量阻塞的线程,如果没有线程被阻塞则此函数什么也不做参考:
C11:https://cloud.tencent.com/developer/section/1009708
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html
- void cond_wait(cond_t cond, mutex_t mutex);
参数:cond
条件变量标识符
参数:mutex
互斥锁标识符
返回:无
描述:阻塞线程,并等待被条件变量唤醒参考:
C11:https://cloud.tencent.com/developer/section/1009713
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html
- uint32_t cond_timed_wait(cond_t cond, mutex_t mutex, uint32_t timeout);
参数:cond
条件变量标识符
参数:mutex
互斥锁标识符
参数:timeout
超时时间(毫秒)
返回:剩余等待时间,如果返回0则说明等待超时
功能:定时阻塞线程,并等待被条件变量唤醒参考:
C11:https://cloud.tencent.com/developer/section/1009712
POSIX:https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html
3.7 事件
- event_t event_create(bool auto_reset);
参数:auto_reset
是否自动复位事件
返回:创建成功返回事件标识符,失败返回NULL
描述:创建一个事件对象,当auto_reset
为true
时事件会在传递成功后自动复位参考:
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa
- void event_delete(event_t event);
参数:event
事件标识符
返回:无
描述:删除事件对象,并释放内存,在没有线程使用它时才能删除,否则可能产生未知异常
- void event_set(event_t event);
参数:event
事件标识符
返回:无
描述:标记事件为置位状态,并唤醒等待队列中的线程,如果auto_reset
为true
,那么只唤醒第1个线程,并且将事件复位, 如果auto_reset
为false
,那么会唤醒所有线程,事件保持置位状态参考:
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setevent
- void event_reset(event_t event);
参数:event
事件标识符
返回:无
描述:标记事件为复位状态,此函数不会唤醒任何线程参考:
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-resetevent
- void event_wait(event_t event);
参数:event
事件标识符
返回:无
描述:等待事件被置位参考:
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
- uint32_t event_timed_wait(event_t event, uint32_t timeout);
参数:event
事件标识符
参数:timeout
等待时间(毫秒)
返回:剩余等待时间,如果返回0则说明等待超时
描述:定时等待事件置位,如果等待时间超过timeout
设定的时间则退出等待参考:
WIN32:https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
四、可选功能
可选功能的源码在sources/opt/
目录,每个功能对应一个c文件和h文件。
c文件是功能的具体实现,h文件是模块声明的接口。
要使用哪个功能就包含对应的头文件和源代码。
4.1 事件组
#include "event_flags.h"
- event_flags_t event_flags_create(void);
参数:无
返回:创建成功返回事件标识符,失败返回NULL
描述:创建一个事件组对象
- void event_flags_delete(event_flags_t event);
参数:event
事件组标识符
返回:无
描述:删除事件组对象,并释放内存,在没有线程使用它时才能删除,否则可能产生未知异常
- void event_flags_set(event_flags_t event, uint32_t bits);
参数:event
事件组标识符
返回:无
描述:置位bits
指定的事件标志位,并唤醒等待队列中想要获取bits
的线程
- void event_flags_reset(event_flags_t event, uint32_t bits);
参数:event
事件组标识符
返回:无
描述:清除bits
指定的事件标志位,此函数不会唤醒任何线程
-
uint32_t event_flags_wait(event_flags_t event, uint32_t bits, uint32_t ops);
参数:
event
事件组标识符
bits
想要等待的标志位
ops
等待标志位的行为EVENT_FLAGS_WAIT_ANY: 只要
bits
中的任意一位有效,函数立即返回;
EVENT_FLAGS_WAIT_ALL: 只有bits
中的所有位都有效,函数才能返回;
EVENT_FLAGS_AUTO_RESET: 函数返回时自动清零获取到的标志位;返回:实际获取到的标志位状态
描述:等待1个或多个事件标志位
- uint32_t event_flags_timed_wait(event_flags_t event, uint32_t bits, uint32_t ops, uint32_t timeout);
参数:
event
事件组标识符
bits
想要等待的标志位
ops
等待标志位的行为
timeout
等待时间(毫秒)
返回:实际获取到的标志位状态
描述:等待1个或多个事件标志位,直到timeout
设定的时间。
4.2 软定时器
#include "soft_timer.h"
- soft_timer_t soft_timer_create(void (*handler)(void *), void *arg);
参数:
handler
定时器回调函数
arg
回调函数的参数
返回:创建成功返回软件定时器标识符,失败返回NULL
描述:创建一个软件定时器。
- void soft_timer_delete(soft_timer_t timer);
参数:
times
定时器标识符
返回:无
描述:删除软件定时器。
- void soft_timer_start(soft_timer_t timer, uint32_t timeout);
参数:
times
定时器标识符
返回:无
描述:启动软件定时器。
- void soft_timer_stop(soft_timer_t timer);
参数:
times
定时器标识符
返回:无
描述:停止软件定时器。
- void soft_timer_service(void);
参数:无
返回:此函数在正常情况下不会返回。
描述:处理软件定时器事件。如果要使用软件定时器功能,需要用户创建一个线程,调用这个函数,用来承载定时器的执行。
这样做的目的是让用户控制软件定时器的线程优先级和栈空间。
4.3 块内存池
#include "mpool.h"
- mpool_t mpool_create(uint32_t block_size, uint32_t block_count);
参数:
block_size
内存块大小
block_count
内存块总数
返回:创建成功返回标识符,失败返回NULL
描述:创建块内存池。
- void mpool_delete(mpool_t mpool);
参数:
mpool
标识符
返回:无
描述:删除块内存池。
- void *mpool_alloc(mpool_t mpool);
参数:
mpool
标识符
返回:申请成功返回内存指针,申请失败返回NULL
描述:从内存池中申请一块内存。
- void mpool_free(mpool_t mpool, void *block);
参数:
mpool
标识符
block
内存块指针
返回:无
描述:释放内存
4.4 数据队列
#include "queue.h"
queue_t queue_create(uint32_t item_size, uint32_t queue_depth);
参数:
item_size
队列数据块大小
queue_depth
队列深度
返回:创建成功返回标识符,失败返回NULL
描述:创建一个数据队列。
void queue_delete(queue_t queue);
参数:
queue
标识符
返回:无
描述:删除数据队列。
void queue_clear(queue_t queue);
参数:
queue
标识符
返回:无
描述:清空数据队列。
bool queue_send(queue_t queue, void *item, uint32_t timeout);
参数:
queue
标识符
item
数据指针
timeout
超时时间(毫秒)
返回:成功返回true
,超时返回false
描述:向队列中发送一条数据。
bool queue_recv(queue_t queue, void *item, uint32_t timeout);
参数:
queue
标识符
item
数据指针
timeout
超时时间(毫秒)
返回:成功返回true
,超时返回false
描述:从队列中取出一条数据。
4.5 消息邮箱
消息邮箱按照FIFO机制取出消息。取出的消息长度和发送的消息长度一致。
如果输入的buf长度小于消息长度,则丢弃超出buf长度的部分内容。
#include "mailbox.h"
mailbox_t mailbox_create(uint32_t size);
参数:
size
缓冲区长度
返回:创建成功返回标识符,失败返回NULL
描述:创建缓冲区。
void mailbox_delete(mailbox_t mbox);
参数:
mbox
标识符
返回:无
描述:删除缓冲区。
void mailbox_clear(mailbox_t mbox);
参数:
mbox
标识符
返回:无
描述:清空缓冲区。
uint32_t mailbox_post(mailbox_t mbox, void *buf, uint32_t len, uint32_t timeout);
参数:
mbox
标识符
buf
数据指针
len
数据长度
timeout
超时时间(毫秒)
返回:实际写入数据长度
描述:向缓冲区写入指定长度的数据。
uint32_t mailbox_wait(mailbox_t mbox, void *buf, uint32_t len, uint32_t timeout);
参数:
mbox
定时器标识符
buf
数据指针
len
数据长度
timeout
超时时间(毫秒)
返回:实际读出数据长度
描述:从缓冲区中读出指定长度的数据。
五、其它函数
其它函数是与操作系统本身无关的,但在实现过程中引用的通用功能。
5.1 通用链表
#include "list.h"
5.2 通用FIFO
#include "fifo.h"
六、硬件移植
KLite核心代码完全使用C语言实现,由于不同CPU平台的差异性,有一些功能依赖于目标CPU平台,这些无法统一实现的函数,可能需要使用汇编才能实现
这些函数的实现代码放在sources/port/
目录。
- void cpu_sys_init(void);
描述:初始化与操作系统有关的功能,在kernel_init()
阶段被调用
参数:无
返回:无
- void cpu_sys_start(void);
描述:启动与操作系统有关的功能,在kernel_start()
阶段被调用通常用于启动滴答时钟定时器,并打开中断滴答时钟使用硬件定时器中断,中断周期通常为1ms, 也可以为其它任意值,只需要在中断服务程序中调用一次kernel_tick(1)
即可这里的参数1则代表时钟周期,如果是10ms中断一次,则应该传入10作为参数。 参数:无
返回:无
- void cpu_sys_sleep(uint32_t time);
描述:实现低功耗休眠的接口,操作系统空闲时调用
参数:time
休眠的最长时间,单位毫秒
返回:无
- void cpu_enter_critical(void);
描述:实现操作系统进入临界区的接口,需要支持递归
参数:无
返回:无
- void cpu_leave_critical(void);
描述:实现操作系统退出临界区的接口,需要支持递归
参数:无
返回:无
- void cpu_contex_switch(void);
描述:实现切换线程上下文的接口,需要使用可挂起的中断来实现
参数:无
返回:无
- void *cpu_contex_init(void *stack_base, void *stack_top, void *entry, void *arg, void *exit);
描述:初始化线程栈的接口
参数:
stack_base
栈底指针
stack_top
栈顶指针
entry
线程入口函数地址
arg
线程入口函数参数
exit
线程出口函数地址
返回:新的栈指针对于ARM处理器使用的是满递减栈,因此返回的是新的栈顶指针。
七、设计思路
核心思想是通过调度器(sched.c)维护3个TCB链表(队列):
-
就绪链表(m_ready_list): 此版本使用了8条就绪表,每个优先级对应一个表。
在早期的版本中,为了使代码实现简单,使用的是一条双向排序链表,高优先级在头,低优先级在尾
但这种方案排序时间会随着优先级数量和线程数量上升,一致性较差。
为了使KLite有更广泛的应用,因此现在替换为目前主流的优先级列表和位图搜索算法来调度。
理论上可以支持32级优先级(就绪表),但经过反复推敲,8个优先级已经能满足绝大多数的场景了。 因此目前的设定最多8个优先级,如果想改为32级也很简单就能实现。 -
睡眠链表(m_sleep_list): 当线程休眠时,会加入此表,在每一次滴答周期内都会检查有否有线程休眠结束,将其移到就绪表中。
-
等待链表(tcb->list_wait): 用于线程等待对象的阻塞。
每当需要切换线程时,就从就绪表中取出优先级最高的线程,将sched_tcb_next
的值修改为新线程,调用硬件接口完成上下文切换。
硬件切换接口cpu_contex_switch()
挂起指定中断,在该中断服务程序中完成线程切换。
切换过程:将当前上下文保存到sched_tcb_now->sp
栈中,并更新sp值,
然后从sched_tcb_next->sp
中取出上下文,
最后将sched_tcb_next
赋值到sched_tcb_now
。
八、结语
KLite并不像其它物联网操作系统一样提供一站式的全家桶服务,它仅仅是个多线程调度内核,
但我们可以灵活选择适合自己的文件系统、网络协议栈、图形界面等更丰富的功能。
如果您在使用中发现任何BUG或者有好的改进建议,欢迎加入QQ群(317930646)或发送邮件至kerndev@foxmail.com