6. 唤醒进程 时间过的很快,十二月份了。十二月份的南京已经颇冷,蚊子也没有了。但天气着实冷,晚上睡不安稳。后来垫上厚褥子,盖上两层被子。厚实的保护下,寒气也无从侵入,终于能睡安稳了。在这个起床靠鞭子抽的季节里,联想起进程的唤醒和休眠也无非如此罢了。进程休眠的时候,自己找个安稳的休眠队列往上一躺,设置一个标志,调用sched函数就休眠了。而唤醒就不是进程自己能办到的了,需要借助外力,这就好比冬天起床的过程,没个闹钟你能起来吗?北方有暖气的除外,那个环境起床一点困难的没有,暖气开足了还闹流鼻血。闲话少扯,唤醒进程的外力就是try_to_wake_up函数了
try_to_wake_up函数首先调用update_rq_clock更新一下cfs调度队列上的clock时间。如果该进程已经是TASK_RUNNING状态,直接退出该函数,如果这个进程在运行队列上,就直接跳到check_preempt_curr函数就可以了。如果确实是刚唤醒的进程,调用active_task,这个函数主要的作用就是调整task的vruntime,进程在休眠的时候vruntime是不会一直更新的,所以等唤醒进程的时候必须更新这个变量。之后将task放入到运行队列上去。
/* * activate_task - move a task to the runqueue. */ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup) { if (task_contributes_to_load(p)) rq->nr_uninterruptible--; enqueue_task(rq, p, wakeup); inc_nr_running(rq); } |
/* * The enqueue_task method is called before nr_running is * increased. Here we update the fair scheduling stats and * then put the task into the rbtree: */ static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup) { struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; for_each_sched_entity(se) { if (se->on_rq) break; cfs_rq = cfs_rq_of(se); enqueue_entity(cfs_rq, se, wakeup); wakeup = 1; } hrtick_update(rq); } |
static void enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup) { /* * Update run-time statistics of the 'current'. */ update_curr(cfs_rq); account_entity_enqueue(cfs_rq, se); if (wakeup) { place_entity(cfs_rq, se, 0); enqueue_sleeper(cfs_rq, se); } update_stats_enqueue(cfs_rq, se); check_spread(cfs_rq, se); if (se != cfs_rq->curr) __enqueue_entity(cfs_rq, se); } |
Activate_task最主要的工作还是将task放入到运行队列中去,但是,需要注意到是place_entity操作,对于被唤醒的进程,系统试着奖励一点运行时间(vruntime -= thresh;)
阅读(1268) | 评论(0) | 转发(0) |