- schedule()片段
进程next被唤醒后(唤醒前处于TASK_INTERRUPTIBLE状态),现在已经被schedule()选中即将投入运行,在得到CPU控制权之前需要重新计算其sleep_avg和prio:
if
(
!
rt_task(next)
&&
next
->
activated
>
0
)
{
unsigned long long delta = now - next->timestamp; //(1)
if (unlikely((long long)(now - next->timestamp) < 0)) //(2)
delta = 0;
if (next->activated == 1)
delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
array = next->array;
dequeue_task(next, array); //(3)
recalc_task_prio(next, next->timestamp + delta); //(4)
enqueue_task(next, array); //(5)
}
unsigned long long delta = now - next->timestamp; //(1)
if (unlikely((long long)(now - next->timestamp) < 0)) //(2)
delta = 0;
if (next->activated == 1)
delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
array = next->array;
dequeue_task(next, array); //(3)
recalc_task_prio(next, next->timestamp + delta); //(4)
enqueue_task(next, array); //(5)
}
next->timestamp now
--------------+ +-------------
running | |
| |
| sleeping |
+------------------------+
//(2) 计算delta
//(3) 进程next退出活跃队列
//(4) 重新计算平均睡眠时间和动态优先级
//(5) 根据新计算的动态优先级将进程next重新插入活跃队列
- recalc_task_prio( )
The recalc_task_prio( ) function updates the average sleep time and the dynamic priority of a process. It receives as its parameters a process descriptor pointer p and a timestamp now computed by the sched_clock( ) function.
static void recalc_task_prio(task_t *p, unsigned long long now)
{
1. 计算本次睡眠时间(sleep_time)
|-------------------------------------------------------------|
| /* Caller must always ensure 'now >= p->timestamp' */ |
| unsigned long long __sleep_time = now - p->timestamp; |
| unsigned long sleep_time; |
| |
| if (__sleep_time > NS_MAX_SLEEP_AVG) |
| sleep_time = NS_MAX_SLEEP_AVG; |
| else |
| sleep_time = (unsigned long)__sleep_time; |
|-------------------------------------------------------------|
2. 如果sleep_time不大于0(没有睡眠),就不用更新进程的平均睡眠时间,直接进入第8步
|----------------------------------|
| if (likely(sleep_time > 0)) { |
|----------------------------------|
3. 如果该进程不是内核线程;唤醒前不处于TASK_UNINTERRUPTIBLE状态;其连续睡眠时间超过给定的睡眠时间极限;则该进程的sleep_avg = 1000 - 100 = 900ms
Checks whether the process is not a kernel thread, whether it is awakening from the TASK_UNINTERRUPTIBLE state (p->activated field equal to -1), and whether it has been continuously asleep beyond a given sleep time threshold.
|----------------------------------------------------------------|
| if (p->mm && p->activated != -1 && |
| sleep_time > INTERACTIVE_SLEEP(p)) { |
| p->sleep_avg = |
| JIFFIES_TO_NS(MAX_SLEEP_AVG - DEF_TIMESLICE);|
|----------------------------------------------------------------|
} else {
4. 根据当前bonus倍增本次连续睡眠时间sleep_time
执行CURRENT_BONUS宏计算进程 " 原来的平均睡眠时间 "(更新前的平均睡眠时间)所对应的bonus值。如果(10 - bonus)大于 0,函数用这个值与sleep_time相乘(放大本次 连续睡眠时间sleep_time)。 因为要把sleep_time加到进程的平均睡眠时间上, 所以当前平均睡眠时间越短(sleep_avg对应的bonus值越小), sleep_time增加的倍数就越多。
|----------------------------------------------------------------|
| sleep_time *= (MAX_BONUS - CURRENT_BONUS(p)) ? : 1; |
|----------------------------------------------------------------|
5. 如果进程p唤醒前处于TASK_UNINTERRUPTIBLE状态;不是内核线程;
a. 如果更新前的平均睡眠时间已经超过了 给定的睡眠时间极限,那么将没有必要更新平均睡眠时间了(就算加上本次连续睡眠时间sleep_time也没有意义),所以将sleep_time置为0,直接进入第6步
b. 如果 更新前的平均睡眠时间加上本次连续睡眠时间超过了 给定的睡眠时间极限,那么就把p->sleep_avg字段置为睡眠 极限 时间并把sleep_avg设置为 0
|------------------------------------------------------------|
| if (p->activated == -1 && p->mm) { |
| if (p->sleep_avg >= INTERACTIVE_SLEEP(p)) |
| sleep_time = 0; |
| else if (p->sleep_avg + sleep_time >= |
| INTERACTIVE_SLEEP(p)) { |
| p->sleep_avg = INTERACTIVE_SLEEP(p); |
| sleep_time = 0; |
| } |
| } |
|------------------------------------------------------------|
6. 把本次连续睡眠时间(sleep_time)加到进程 更新前的 平均睡眠时间上(p->sleep_avg)
|-----------------------------------------|
| p->sleep_avg += sleep_time; |
|-----------------------------------------|
7. 检查更新后的平均睡眠时间(p->sleep_avg)是否超过1000个时钟节拍(以纳秒为单位),如果是,函数就把它减到1000个时钟节拍(以纳秒为单位)
|------------------------------------------------|
| if (p->sleep_avg > NS_MAX_SLEEP_AVG) |
| p->sleep_avg = NS_MAX_SLEEP_AVG; |
|------------------------------------------------|
}
}
8. 根据新的平均睡眠时间sleep_avg更新动态优先级prio
|---------------------------------|
| p->prio = effective_prio(p); |
|---------------------------------|
}