Zephyr内核调度之代码分析5--设置优先级

Creative Commons
本作品采用知识共享署名

本文分析设置优先级如何引发调度。

前文参考

[1] Zephyr内核调度之调度方式与时机
[2] Zephyr线程阻塞和超时机制分析
[3] Zephyr用户模式-系统调用
[4] Zephyr内核调度之代码分析2-调度关键函数
[5] Zephyr内核调度之代码分析3–线程睡眠和挂起

在[1]中提到了17种调度时机,本文分析其中1种:设置优先级

  • z_impl_k_thread_priority_set

由于系统调用的关系可被应用调用的内核函数实际实现对应到sched.c中(参考[3]):
k_thread_priority_set->z_impl_k_thread_priority_set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
void z_impl_k_thread_priority_set(k_tid_t thread, int prio)
{
//判断优先级合法性
Z_ASSERT_VALID_PRIO(prio, NULL);

//ISR中不能调整线程优先级
__ASSERT(!arch_is_in_isr(), "");

struct k_thread *th = (struct k_thread *)thread;

//设置优先级
z_thread_priority_set(th, prio);
}

void z_thread_priority_set(struct k_thread *thread, int prio)
{
//设置优先级,并返回是否需要调度
bool need_sched = z_set_prio(thread, prio);

//需要调度,且没有锁调度,执行上下文切换。z_reschedule_unlocked参考[5]
if (need_sched && _current->base.sched_locked == 0U) {
z_reschedule_unlocked();
}
}


bool z_set_prio(struct k_thread *thread, int prio)
{
bool need_sched = 0;

LOCKED(&sched_spinlock) {
//修改就绪线程的优先级,意味着就绪列表会重新排列,需要进行调度
need_sched = z_is_thread_ready(thread);

if (need_sched) {
//线程在就绪列表内,将线程从ready_q中取出,修改优先级后再重新加入到ready_q中,想当于进行了重排
if (!IS_ENABLED(CONFIG_SMP) || z_is_thread_queued(thread)) {
dequeue_thread(&_kernel.ready_q.runq, thread);
thread->base.prio = prio;
queue_thread(&_kernel.ready_q.runq, thread);
} else {
thread->base.prio = prio;
}

//重排后,选出最优的线程
update_cache(1);
} else {
//如果线程处于挂起状态,直接修改优先级
thread->base.prio = prio;
}
}

return need_sched;

dequeue_thread,queue_thread,update_cache参考[4].