您的位置:首页 > 运维架构 > Linux

linux调度器(五)——进程管理与CFS

2015-09-09 09:45 513 查看
进程调度初始化

由于该过程涉及到进程的管理模块,这个模块的详细过程我们将在以后的机会介绍,所以这里,我们主要扣出与调度相关的内容。进程的创建内核入口为do_fork,首先我们简单的看一下它的主要行为:





图 do_fork与CFS的交互

上图我们只是画了do_fork最普通的fork操作,及正常的启动状态,上面的三个sched_class函数调用就是我们想要的进程调度初始化。我们分别来分析:

task_fork_fair:确定新进程的vruntime值。首先更新当前进程(父进程)的执行信息(update_curr),确定新进程的起始vruntime(place_entity),如果新的进程被设置了sysctl_sched_child_runs_first,并且父进程的vruntime大于子进程的,那么就交换它们的vruntime值,并且设置父进程的TIF_NEED_RESCHED,让它在下次主调度中结束运行,让其它更低vruntime的先运行(不能保证一定是它的子进程先运行,但在它退出运行后,它的子进程一定会比它先运行),然后标准化vruntime,因为现在的子进程还没有入队。

enqueue_task_fair:将子进程放入运行队列中。注意此时传入的flag=0,因为上面把vruntime标准化了,所以现在入队需要把它再反标准化(在CFS内部使用的是非标准化的vruntime,但在红黑树里存储的是标准化的值)。所以对于组调度来说,它需要先把它开始往上的不在运行队列里的se都进行入队操作,(enqueue_entity该函数需要注意的是:如果要入队的se是被ENQUEUE_WAKEUP,那么它的vruntime要进行调整补偿place_entity,显然这里不是被wakeup的),并且更新cfs_rq的load,se->on_rq
= 1, cfs_rq->h_nr_running++;对于已经在队列里的groupse只需要更新h_nr_running就可以了,所以再递归到group root更新这个变量就可以了。

check_preempt_wakeup:检查子进程是否应该抢占当前父进程。显然如果在task_fork_fair我们已经确定了子进程将抢占父进程,那么这里就直接返回;如果当前进程是idle进程(该函数不一定只检查父子进程之间的抢占与否,只是在现在的场景是这样的),那么它应该无条件被抢占,更新当前进程的执行时间,在确定是否要抢占前必须保证比较的两个se处于同一group之下(find_matching_se,即找到它们第一次分开的祖先为止,只有处理同一个层次它们才有可比较性),然后再判断这两个同级的se(可能是之前两个se的祖先),旧的se是否可以被新的se抢占(wakeup_preempt_entity),如果允许的话,更新set_next_buddy,这样在pick_next_entity时它就可以优先被获得;最后就是调用resched_task设置当前进程的TIF_NEED_RESCHED,以及更新set_last_buddy(这个的作用同样见pick_next_entity)。

我们总结一下上面的过程,父进程在执行copy_process时通过task_fork_fair确定子进程的vruntime,同时可能确定子进程是否该抢占父进程;创建完子进程结构及确定vruntime后就可以把子进程入放运行队列enqueue_task_fair,该过程就对组调度上的信息进程更新及入队而已;最后再次确定子进程是否该抢占父进程,并且更新buddy,以保证在pick的时候能够取到最合适的进程。这样我们就把进程fork时调度器为它完成的工作介绍完成。下面我们再考虑进程从不可运行状态唤醒到可运行状态调度器的处理逻辑。



进程唤醒调度过程

我们知道linux的唤醒入口在try_to_wake_up,通过查看该函数,我们可以发现它大多数在处理SMP的情况,对于非SMP的话,其实很简单,如果要被唤醒的进程已经在运行队列里,那么直接检查它是否可以抢占当前进程(check_preempt_curr),否则先把进程加入运行队列中activate_task,再check_preempt_curr。注意这里的activate_task及标志不再是do_fork时的0,而是ENQUEUE_WAKEUP,这样在CFS enqueue_entity时就会调用place_entity对睡眠进程进行vruntime补偿。
上面我们把CFS与调度相关的内容简单的介绍了,但我们并没有详细分析到每个函数里,如果要了解这些细节的话,可以看后面的OTHER CFS CLASS API及CFS主要的内部函数。下面我们再在应用层上来理解和观察CFS组调度的分配
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: