就绪列表
RT-Thread 要支持多优先级,需要靠就绪列表的支持,从代码上看,就绪列表由两个在 scheduler.c 文件定义的全局变量组成,一个是线程就绪优先级组rt_thread_ready_priority_group,另一个是线程优先级表rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]。
将线程插入到线程优先级表,如图:
线程就绪优先级组
为了快速的找到线程在线程优先级表的插入和移除的位置,RT-Thread 专门设计了一个线程就绪优先级组。从代码上看,线程就绪优先级组就是一个 32 位的整形数,每一个位对应一个优先级。一个就绪优先级组最多只能表示 32 个优先级,如果优先级超过 32 个怎么办,则可以定义一个线程就绪优先级数组,每一个数组成员都可以表示 32 个优先级,具体支持到少由系统的 RAM 的大小决定
scheduler.c
/* 线程就绪优先级组 */
rt_uint32_t rt_thread_ready_priority_group;
线程就绪优先级组的每一个位对应一个优先级,位 0 对应优先级 0,位 1 对应优先级 1,以此类推。比如,当优先级为 10 的线程已经准备好,那么就将线程就绪优先级组的位 10 置 1,表示线程已经就绪,然后根据 10 这个索引值,在线程优先级表 10(rt_thread_priority_table[10])的这个位置插入线程。
寻找最高优先级的线程
RT-Thread kservice.c 文件中,有一个专门的函数__rt_ffs,用来寻找 32 位整形数第一个(从低位开始)置 1 的位号。
/**
* 该函数用于从一个32位的数中寻找第一个被置1的位(从低位开始),
* 然后返回该位的索引(即位号)
*
* @Return 返回第一个置1位的索引号。如果全为0,则返回0。
*/
int __rt_ffs(int value)
{
/* 如果值为0,则直接返回0 */
if (value == 0) return 0;
/* 检查 bits [07:00]
这里加1的原因是避免当第一个置1的位是位0时
返回的索引号与值都为0时返回的索引号重复 */
if (value & 0xff)
return __lowest_bit_bitmap[value & 0xff] + 1;
/* 检查 bits [15:08] */
if (value & 0xff00)
return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;
/* 检查 bits [23:16] */
if (value & 0xff0000)
return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;
/* 检查 bits [31:24] */
return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}
/*
* __lowest_bit_bitmap[] 数组的解析
* 将一个8位整形数的取值范围0~255作为数组的索引,索引值第一个出现1(从最低位开始)的位号作为该数组索引下的成员值。
* 举例:十进制数10的二进制为:0000 1010,从最低位开始,第一个出现1的位号为bit1,则有__lowest_bit_bitmap[10]=1
* 注意:只需要找到第一个出现1的位号即可
*/
const rt_uint8_t __lowest_bit_bitmap[] =
{
/* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
线程优先级表
线程优先级表是一个在 scheduler.c 中定义的全局数组
/* 线程优先级表 */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
1
2
一个空的线程优先级表,
有 5 个线程就绪的就绪列表(其中优先级 1 下有两个线程),
线程插入与删除
void rt_schedule_insert_thread(struct rt_thread *thread)
{
register rt_base_t temp;
/* 关中断 */
temp = rt_hw_interrupt_disable();
/* 改变线程状态 */
thread->stat = RT_THREAD_READY;
/* 将线程插入就绪列表 */
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
&(thread->tlist));
/* 设置线程就绪优先级组中对应的位 */
rt_thread_ready_priority_group |= thread->number_mask;
/* 开中断 */
rt_hw_interrupt_enable(temp);
}
void rt_schedule_remove_thread(struct rt_thread *thread)
{
register rt_base_t temp;
/* 关中断 */
temp = rt_hw_interrupt_disable();
/* 将线程从就绪列表删除 */
rt_list_remove(&(thread->tlist));
if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
{
rt_thread_ready_priority_group &= ~thread->number_mask;
}
/* 开中断 */
rt_hw_interrupt_enable(temp);
}
支持多优先级
线程控制块
线程控制块与优先级相关的成员
/*
*************************************************************************
* 线程结构体
*************************************************************************
*/
struct rt_thread
{
/* rt 对象 */
char name[RT_NAME_MAX]; /* 对象的名字 */
rt_uint8_t type; /* 对象类型 */
rt_uint8_t flags; /* 对象的状态 */
rt_list_t list; /* 对象的列表节点 */
rt_list_t tlist; /* 线程链表节点 */
void *sp; /* 线程栈指针 */
void *entry; /* 线程入口地址 */
void *parameter; /* 线程形参 */
void *stack_addr; /* 线程起始地址 */
rt_uint32_t stack_size; /* 线程栈大小,单位为字节 */
rt_ubase_t remaining_tick; /* 用于实现阻塞延时 */
rt_uint8_t current_priority; /* 当前优先级 */
rt_uint8_t init_priority; /* 初始优先级 */
rt_uint32_t number_mask; /* 当前优先级掩码 */
rt_err_t error; /* 错误码 */
rt_uint8_t stat; /* 线程的状态 */
};
typedef struct rt_thread *rt_thread_t;
错误码定义
rtdef.h
/*
*************************************************************************
* 错误码定义
*************************************************************************
*/
/* RT-Thread 错误码重定义 */
#define RT_EOK 0 /* 没有错误 */
#define RT_ERROR 1 /* 一个常规错误 */
#define RT_ETIMEOUT 2 /* 超时 */
#define RT_EFULL 3 /* 资源已满 */
#define RT_EEMPTY 4 /* 资源为空 */
#define RT_ENOMEM 5 /* 没有内存 */
#define RT_ENOSYS 6 /* No system */
#define RT_EBUSY 7 /* 忙*/
#define RT_EIO 8 /* IO错误 */
#define RT_EINTR 9 /* 中断系统调用 */
#define RT_EINVAL 10 /* 无效形参 */
线程状态定义
/*
* 线程状态定义
*/
#define RT_THREAD_INIT 0x00 /* 初始态 */
#define RT_THREAD_READY 0x01 /* 就绪态 */
#define RT_THREAD_SUSPEND 0x02 /* 挂起态 */
#define RT_THREAD_RUNNING 0x03 /* 运行态 */
#define RT_THREAD_BLOCK RT_THREAD_SUSPEND /* 阻塞态 */
#define RT_THREAD_CLOSE 0x04 /* 关闭态 */
#define RT_THREAD_STAT_MASK 0x0f
#define RT_THREAD_STAT_SIGNAL 0x10
#define RT_THREAD_STAT_SIGNAL_READY (RT_THREAD_STAT_SIGNAL | RT_THREAD_READY)
#define RT_THREAD_STAT_SIGNAL_SUSPEND 0x20
#define RT_THREAD_STAT_SIGNAL_MASK 0xf0
线程初始化函数
优先级、错误码、状态
rt_err_t rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority)
{
/* 线程对象初始化 */
/* 线程结构体开头部分的成员就是rt_object_t类型 */
rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
rt_list_init(&(thread->tlist));
thread->entry = (void *)entry;
thread->parameter = parameter;
thread->stack_addr = stack_start;
thread->stack_size = stack_size;
/* 初始化线程栈,并返回线程栈指针 */
thread->sp = (void *)rt_hw_stack_init( thread->entry,
thread->parameter,
(void *)((char *)thread->stack_addr + thread->stack_size - 4) );
thread->init_priority = priority;
thread->current_priority = priority;
thread->number_mask = 0;
/* 错误码和状态 */
thread->error = RT_EOK;
thread->stat = RT_THREAD_INIT;
return RT_EOK;
}
调度器初始化函数
/* 初始化系统调度器 */
void rt_system_scheduler_init(void)
{
register rt_base_t offset;
/* 线程优先级表初始化 */
for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
{
rt_list_init(&rt_thread_priority_table[offset]);
}
/* 初始化当前优先级为空闲线程的优先级 */
rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
/* 初始化当前线程控制块指针 */
rt_current_thread = RT_NULL;
/* 初始化线程就绪优先级组 */
rt_thread_ready_priority_group = 0;
}
线程启动函数
/**
* 启动一个线程并将其放到系统的就绪列表中
*
* @param thread 待启动的线程
*
* @return 操作状态, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_thread_startup(rt_thread_t thread)
{
/* 设置当前优先级为初始优先级 */
thread->current_priority = thread->init_priority;
thread->number_mask = 1L << thread->current_priority;
/* 改变线程的状态为挂起状态 */
thread->stat = RT_THREAD_SUSPEND;
/* 然后恢复线程 */
rt_thread_resume(thread);
if (rt_thread_self() != RT_NULL)
{
/* 系统调度 */
rt_schedule();
}
return RT_EOK;
}
rt_thread_t rt_thread_self(void)
{
return rt_current_thread;
}
/**
* 该函数用于恢复一个线程然后将其放到就绪列表
*
* @param thread 需要被恢复的线程
*
* @return 操作状态, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_thread_resume(rt_thread_t thread)
{
register rt_base_t temp;
/* 将被恢复的线程必须在挂起态,否则返回错误码 */
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
{
return -RT_ERROR;
}
/* 关中断 */
temp = rt_hw_interrupt_disable();
/* 从挂起队列移除 */
rt_list_remove(&(thread->tlist));
/* 开中断 */
rt_hw_interrupt_enable(temp);
/* 插入就绪列表 */
rt_schedule_insert_thread(thread);
return RT_EOK;
}
空闲中断初始化函数
/**
* @ingroup SystemInit
*
* 初始化空闲线程,启动空闲线程
*
* @NOTE 当系统初始化的时候该函数必须被调用
*/
void rt_thread_idle_init(void)
{
/* 初始化线程 */
rt_thread_init(&idle,
"idle",
rt_thread_idle_entry,
RT_NULL,
&rt_thread_stack[0],
sizeof(rt_thread_stack),
RT_THREAD_PRIORITY_MAX-1);
/* 启动线程 */
rt_thread_startup(&idle);
}
启动系统调度器
/* 启动系统调度器 */
void rt_system_scheduler_start(void)
{
register struct rt_thread *to_thread;
register rt_ubase_t highest_ready_priority;
/* 获取就绪的最高优先级 */
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
/* 获取将要运行线程的线程控制块 */
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
struct rt_thread,
tlist);
rt_current_thread = to_thread;
/* 切换到新的线程 */
rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
/* 永远不会返回 */
}
调度函数
void rt_schedule(void)
{
rt_base_t level;
register rt_ubase_t highest_ready_priority;
struct rt_thread *to_thread;
struct rt_thread *from_thread;
/* 关中断 */
level = rt_hw_interrupt_disable();
/* 获取就绪的最高优先级 */
highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
/* 获取就绪的最高优先级对应的线程控制块 */
to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
struct rt_thread,
tlist);
/* 如果目标线程不是当前线程,则要进行线程切换 */
if (to_thread != rt_current_thread)
{
rt_current_priority = (rt_uint8_t)highest_ready_priority;
from_thread = rt_current_thread;
rt_current_thread = to_thread;
rt_hw_context_switch((rt_uint32_t)&from_thread->sp,
(rt_uint32_t)&to_thread->sp);
/* 开中断 */
rt_hw_interrupt_enable(level);
}
else
{
/* 开中断 */
rt_hw_interrupt_enable(level);
}
}
阻塞延时函数
void rt_thread_delay(rt_tick_t tick)
{
register rt_base_t temp;
struct rt_thread *thread;
/* 失能中断 */
temp = rt_hw_interrupt_disable();
thread = rt_current_thread;
thread->remaining_tick = tick;
/* 改变线程状态 */
thread->stat = RT_THREAD_SUSPEND;
rt_thread_ready_priority_group &= ~thread->number_mask;
/* 使能中断 */
rt_hw_interrupt_enable(temp);
/* 进行系统调度 */
rt_schedule();
}
时基更新函数
void rt_tick_increase(void)
{
rt_ubase_t i;
struct rt_thread *thread;
rt_tick ++;
/* 扫描就绪列表中所有线程的remaining_tick,如果不为0,则减1 */
for(i=0; i
{
thread = rt_list_entry( rt_thread_priority_table.next,
struct rt_thread,
tlist);
if(thread->remaining_tick > 0)
{
thread->remaining_tick --;
if(thread->remaining_tick == 0)
{
//rt_schedule_insert_thread(thread);
rt_thread_ready_priority_group |= thread->number_mask;
}
}
}
/* 任务调度 */
rt_schedule();
}
main函数
/* 初始化线程 */
rt_thread_init( &rt_flag1_thread, /* 线程控制块 */
"rt_flag1_thread", /* 线程名字,字符串形式 */
flag1_thread_entry, /* 线程入口地址 */
RT_NULL, /* 线程形参 */
&rt_flag1_thread_stack[0], /* 线程栈起始地址 */
sizeof(rt_flag1_thread_stack), /* 线程栈大小,单位为字节 */
2); /* 优先级 */
/* 将线程插入到就绪列表 */
//rt_list_insert_before( &(rt_thread_priority_table[0]),&(rt_flag1_thread.tlist) );
rt_thread_startup(&rt_flag1_thread);
/* 初始化线程 */
rt_thread_init( &rt_flag2_thread, /* 线程控制块 */
"rt_flag2_thread", /* 线程名字,字符串形式 */
flag2_thread_entry, /* 线程入口地址 */
RT_NULL, /* 线程形参 */
&rt_flag2_thread_stack[0], /* 线程栈起始地址 */
sizeof(rt_flag2_thread_stack), /* 线程栈大小,单位为字节 */
3); /* 优先级 */
/* 将线程插入到就绪列表 */
//rt_list_insert_before( &(rt_thread_priority_table[1]),&(rt_flag2_thread.tlist) );
rt_thread_startup(&rt_flag2_thread);
原作者:橘长_
|