线程的调度分为两种:主动调度、被动调度。
调度的本质就是从就绪队列中找到最高优先级的线程来执行。
void acoral_sched()
{
if(!acoral_need_sched) //是否需要调度标志,仅当就绪队列acoral_ready_queues有线程加入或取下时,该标志置为true;仅当aCoral在调度线程时,该标志位置为false
return;
if(acoral_intr_nesting)
return;
if(acoral_sched_is_lock)
return;
if(!acoral_start_sched)
return;
HAL_SCHED_BRIDGE();
return;
}
第一个判断条件need_sched失效的频率是最高的,放在最开始有助于提高性能。
将aCoral移植到stm32时,HAL_SCHED_BRIDGE会直接跳到汇编代码的HAL_SCHED_BRIDGE,再执行PENDSV中断。
HAL_SCHED_BRIDGE:
ldr r0, =NVIC_INT_CTRL
ldr r1, =NVIC_PENDSVSET
CPSIE I
str r1, [r0]
bx lr
PENDSV_CALL:
mrs r8,primask
CPSID I
push {r0,lr}
mrs r0,psp
stmfd r0!,{r1,r4-r11}
msr psp,r0
bl acoral_real_intr_sched
pop {r0,lr}
mrs r0,psp
ldmfd r0!,{r1,r4-r11}
msr psp,r0
msr primask,r8
bx lr
调度前的准备工作完成后,便是调用acoral_real_intr_sched()
void acoral_real_intr_sched()
{
acoral_thread_t *prev;
acoral_thread_t *next;
acoral_set_need_sched(false);
prev = acoral_cur_thread;
acoral_select_thread();
next = acoral_ready_thrad;
if(prev != next)
{
acoral_set_running_thread(next);
if(prev->state == ACORAL_THREAD_STATE_EXIT)
{
prev->state = ACORAL_THREAD_STATE_RELEASE;
HAL_INTR_SWITCH_TO($next->stack);
}
HAL_INTR_CTX_SWITCH(&prev->stack, &next->stack);
}
}
//从就绪队列中找出最高优先级的线程
void acoral_select_thread()
{
unsigned int index;
acoral_rdy_queue_t *rdy_queue;
acoral_list_t *head;
acoral_thread_t *thread;
acoral_list_t *queue;
rdy_queue = &acoral_ready_queues;
index = acoral_get_highprio(rdy_queue);
queue = rdy_queue->queue + index;
head = queue;
thread = list_entry(head->next, acoral_thread_t, ready);
acoral_set_ready_thread(thread);
}
typedef struct{
unsigned int num;
unsigned int bitmap[PRIO_BITMAP_SIZE];
acoral_list_t queue[ACORAL_MAX_PRIO_NUM];
}acoral_rdy_queue_t;
unsigned int acoral_get_highprio(acoral_rdy_queue_t *array)
{
return acoral_find_first_bit(array->bitmap, PRIO_BITMAP_SIZE);
}
unsigned int acoral_find_first_bit(const unsigned int *b, unsigned int length)
{
unsigned int v;
unsigned int off;
for(off =0; v=b[off],off<length;off++){
if(v) //选择第一个数值不为0的32位bitmap
break;
}
return acoral_ffs(v) + off*32;//将这个值交给acoral_ffs进一步确定最低一位为1的是哪位。
}
unsigned int acoral_ffs(unsigned int word)
{
unsigned int k;
k = 31;
if(word & 0x0000ffff)
{
k -= 16;
word <<= 16;
}
if(word & 0x00ff0000)
{
k -= 8;
word <<= 8;
}
if (word & 0x0f000000) { k -= 4; word <<= 4; }
if (word & 0x30000000) { k -= 2; word <<= 2; }
if (word & 0x40000000) { k -= 1; }
return k;
}
如果低16位有为1的,则肯定为1的那一位少于16,所以减去16,并且去掉高16位。