The try_to_wake_up( ) function awakes a sleeping or stopped process by setting its state to TASK_RUNNING and inserting it into the runqueue of the local CPU.
The function receives as its parameters:
1. The descriptor pointer (p) of the process to be awakened
2. A mask of the process states (state) that can be awakened(要唤醒的进程状态集)
3. A flag (sync) that forbids the awakened process to preempt the process currently running on the local CPU
(如果sync为1则表示禁止唤醒进程p抢占当前进程)
static int try_to_wake_up(task_t * p, unsigned int state, int sync)
{
int cpu, this_cpu, success = 0;
unsigned long flags;
long old_state;
runqueue_t *rq;
#ifdef CONFIG_SMP
unsigned long load, this_load;
struct sched_domain *sd;
int new_cpu;
#endif
1. 关闭本地中断并给本地可执行队列rq加锁
Invokes the task_rq_lock( ) function to disable local interrupts and to acquire the lock of the runqueue rq owned by the CPU that was last executing the process (it could be different from the local CPU). The logical number of that CPU is stored in the p->thread_info->cpu field.
|----------------------------------|
| rq = task_rq_lock(p, &flags); |
|----------------------------------|
2. 如果当前进程状态p->state不在要唤醒的进程状态集中,则不能唤醒该进程
Checks if the state of the process p->state belongs to the mask of states state passed as argument to the function; if this is not the case, it jumps to step 9 to terminate the function.
|----------------------------------|
| old_state = p->state; |
| if (!(old_state & state)) |
| goto out; |
|----------------------------------|
3. 如果当前进程本身就在可执行队列中,则无需唤醒本进程
If the p->array field is not NULL, the process already belongs to a runqueue; therefore, it jumps to step 8.
|----------------------------------|
| if (p->array) |
| goto out_running; |
|----------------------------------|
task_cpu(p)返回当前进程p所使用的CPU编号(p所归属的runqueue所在的CPU编号)
|----------------------------------|
| cpu = task_cpu(p); |
| this_cpu = smp_processor_id(); |
|----------------------------------|
4. 多处理器系统:
--------------------------------------------------------------------------------
#ifdef CONFIG_SMP
if (unlikely(task_running(rq, p)))
goto out_activate;
#ifdef CONFIG_SCHEDSTATS
schedstat_inc(rq, ttwu_cnt);
if (cpu == this_cpu) {
schedstat_inc(rq, ttwu_local);
} else {
for_each_domain(this_cpu, sd) {
if (cpu_isset(cpu, sd->span)) {
schedstat_inc(sd, ttwu_wake_remote);
break;
}
}
}
#endif
new_cpu = cpu;
if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
goto out_set_cpu;
load = source_load(cpu);
this_load = target_load(this_cpu);
if (sync)
this_load -= SCHED_LOAD_SCALE;
if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2)
goto out_set_cpu;
new_cpu = this_cpu;
for_each_domain(this_cpu, sd) {
unsigned int imbalance;
imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2;
if ((sd->flags & SD_WAKE_AFFINE) &&
!task_hot(p, rq->timestamp_last_tick, sd)) {
if (cpu_isset(cpu, sd->span)) {
schedstat_inc(sd, ttwu_move_affine);
goto out_set_cpu;
}
} else if ((sd->flags & SD_WAKE_BALANCE) &&
imbalance*this_load <= 100*load) {
if (cpu_isset(cpu, sd->span)) {
schedstat_inc(sd, ttwu_move_balance);
goto out_set_cpu;
}
}
}
new_cpu = cpu;
out_set_cpu:
new_cpu = wake_idle(new_cpu, p);
if (new_cpu != cpu) {
set_task_cpu(p, new_cpu);
task_rq_unlock(rq, &flags);
rq = task_rq_lock(p, &flags);
old_state = p->state;
if (!(old_state & state))
goto out;
if (p->array)
goto out_running;
this_cpu = smp_processor_id();
cpu = task_cpu(p);
}
out_activate:
#endif
--------------------------------------------------------------------------------
5.If the process is in the TASK_UNINTERRUPTIBLE state, it decreases the nr_uninterruptible field of the target runqueue, and sets the p->activated field of the process descriptor to -1.
|----------------------------------------------|
| if (old_state == TASK_UNINTERRUPTIBLE) { |
| rq->nr_uninterruptible--; |
| p->activated = -1; |
| } |
|----------------------------------------------|
6.更新唤醒进程p的平均睡眠时间sleep_avg和动态优先级prio;记录该进程唤醒前的睡眠状态;将该进程插入活跃优先级数组
|----------------------------------------------|
| activate_task(p, rq, cpu == this_cpu); |
|----------------------------------------------|
7. 如果唤醒进程p的动态优先级prio比当前进程current的动态优先级高则当前进程的TIF_NEED_RESCHED就需要设置
If either the target CPU is not the local CPU or if the sync flag is not set, it checks whether the new runnable process has a dynamic priority higher than that of the current process of the rq runqueue (p->prio < rq->curr->prio); if so, invokes resched_task( ) to preempt rq->curr.
|----------------------------------------------|
| if (!sync || cpu != this_cpu) { |
| if (TASK_PREEMPTS_CURR(p, rq)) |
| resched_task(rq->curr); |
| } |
| success = 1; |
|----------------------------------------------|
8. Sets the p->state field of the process to TASK_RUNNING.
|---------------------------------|
|out_running: |
| p->state = TASK_RUNNING; |
|---------------------------------|
9. Invokes task_rq_unlock( ) to unlock the rq runqueue and reenable the local interrupts.
|---------------------------------|
|out: |
| task_rq_unlock(rq, &flags); |
|---------------------------------|
return success;
}
阅读(3808) | 评论(0) | 转发(1) |