链表
初始化双向链表
rt_inline void rt_list_init(rt_list_t *l)
{l->next = l->prev = l;
}
插入
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
{l->next->prev = n;n->next = l->next;l->next = n;n->prev = l;
}
在NODE1
后面插入节点n,可以理解为:NODE3
的前一个结点为n
,n
的后一个节点为NODE3
,NODE3
即l->next
删除
rt_inline void rt_list_remove(rt_list_t *n)
{n->next->prev = n->prev;n->prev->next = n->next;n->next = n->prev = n;
}
就绪列表
就是一个rt_list_t
类型的数组。
/* 线程就绪列表 */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
每个线程控制块都有一个成员tlist
,类型为rt_list_t
.我们将线程插入到就绪列表里面,就是通过将线程控制块的 tlist 这个节点插入到就绪列表中来实现的。
/* 初始化线程 */
rt_thread_init( &rt_flag1_thread, /* 线程控制块 */flag1_thread_entry, /* 线程入口地址 */RT_NULL, /* 线程形参 */&rt_flag1_thread_stack[0], /* 线程栈起始地址 */sizeof(rt_flag1_thread_stack) ); /* 线程栈大小,单位为字节 */
/* 将线程插入到就绪列表 */
rt_list_insert_before( &(rt_thread_priority_table[0]),&(rt_flag1_thread.tlist) );
系统调度初始化
/*** @ingroup SystemInit* This function will initialize the system scheduler*/
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_thread = RT_NULL;
}
此时的链表为空
启动调度器
/*** @ingroup SystemInit* This function will startup scheduler. It will select one thread* with the highest priority level, then switch to it.*/
void rt_system_scheduler_start(void)
{register struct rt_thread *to_thread;register rt_ubase_t highest_ready_priority;#if RT_THREAD_PRIORITY_MAX > 32register rt_ubase_t number;number = __rt_ffs(rt_thread_ready_priority_group) - 1;highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#elsehighest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#endif/* get switch to thread */to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);rt_current_thread = to_thread;/* switch to new thread */rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);/* never come back */
}
临界段保护
PRIMASK寄存器
这个寄存器只有一个位,置1后,将关闭所有可屏蔽中断的异常,只剩NMI和硬fault,默认值为0
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable PROCEXPORT rt_hw_interrupt_disableMRS r0, PRIMASKCPSID IBX LRENDP;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable PROCEXPORT rt_hw_interrupt_enableMSR PRIMASK, r0BX LRENDP
为什么不直接这样写?
;/*
; * void rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable PROC
EXPORT rt_hw_interrupt_disable
CPSID I
BX LR
ENDP;/*
; * void rt_hw_interrupt_enable(void);
; */
rt_hw_interrupt_enable PROC
EXPORT rt_hw_interrupt_enable
CPSIE I
BX LR
ENDP
避免在嵌套的临界段失效,如下所示
/* 临界段代码 */
{/* 临界段 1 开始 */rt_hw_interrupt_disable(); /* 关中断,PRIMASK = 1 */{/* 临界段 2 */rt_hw_interrupt_disable(); /* 关中断,PRIMASK = 1 */{}rt_hw_interrupt_enable(); /* 开中断,PRIMASK = 0 */ //(注意)}/* 这里已经开启了中断,而临界段1还未结束 *//* 临界段 1 结束 */rt_hw_interrupt_enable(); /* 开中断,PRIMASK = 0 */
}
正确做法如下:
PRIMASK = 0; /* PRIMASK 初始值为 0,表示没有关中断 */
rt_base_t level1;
rt_base_t level2;/* 临界段代码 */
{/* 临界段 1 开始 */level1 = rt_hw_interrupt_disable(); /* 关中断,level1=0,PRIMASK=1 */{/* 临界段 2 */level2 = rt_hw_interrupt_disable(); /* 关中断,level2=1,PRIMASK=1 */ {}rt_hw_interrupt_enable(level2); /* 开中断,level2=1,PRIMASK=1 */}/* 临界段 1 结束 */rt_hw_interrupt_enable(level1); /* 开中断,level1=0,PRIMASK=0 */
}
对象
软件定时器