Linux进程调度

来源:互联网 发布:手机制作遗像软件 编辑:程序博客网 时间:2024/05/16 06:27

说明如下引用代码对应的kernel版本是2.6.34

I. Linux进程调度的函数schedule,先看一下schedule的实现。

/* * schedule() is the main scheduler function. */asmlinkage void __sched schedule(void){struct task_struct *prev, *next;unsigned long *switch_count;struct rq *rq;int cpu;need_resched:preempt_disable();//禁止抢占,实际操作是将current_thread_info的preempt_count加1,其他进程/线程不会抢占当前线程了cpu = smp_processor_id();//获取当前CPU号,逻辑CPU号rq = cpu_rq(cpu);  // 获取当前CPU的runqueue队列,该CPU上所有就绪状态的进程放在该队列中rcu_sched_qs(cpu); //prev = rq->curr;switch_count = &prev->nivcsw;release_kernel_lock(prev);//如果当前进程持有big kernel lock锁则释放,因为当前进程要切换出去了,不能占有该锁need_resched_nonpreemptible:schedule_debug(prev);if (sched_feat(HRTICK))hrtick_clear(rq);spin_lock_irq(&rq->lock);//runqueue队列加锁update_rq_clock(rq);clear_tsk_need_resched(prev);//清除标志TIF_NEED_RESCHED        if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {/*如果当前进程非就绪,并且没有被抢占*/if (unlikely(signal_pending_state(prev->state, prev)))//如果当前进程是task_interruptible或者有信号送达,状态更改为就绪prev->state = TASK_RUNNING;elsedeactivate_task(rq, prev, 1); //将当前进程从就绪队列中摘除;非就绪进程怎么会在就绪队列中?就绪任务在获取锁或者主动睡眠时将任务状态修改为非就绪,但是没有立即从就绪队列中出队列,此时才出队列switch_count = &prev->nvcsw;}pre_schedule(rq, prev);if (unlikely(!rq->nr_running))//如果运行队列上进程数是0,则先通过idle_balance函数从其他CPU上调度,进行负载均衡idle_balance(cpu, rq);             /*put_prev_task->put_prev_task_fair->put_prev_entity->__enqueue_entity将要调度出去的任务插入红黑树,当然插入红黑树的任务是R状态的,即没有被从就绪队列中摘除的*/       put_prev_task(rq, prev);       next = pick_next_task(rq);//挑选下一个要运行的进程将其排进就绪队列,挑选原则是选择红黑树上的最左边节点进程    if (likely(prev != next)) {        sched_info_switch(prev, next);        perf_event_task_sched_out(prev, next, cpu);         rq->nr_switches++;//队列切换次数更新        rq->curr = next;         ++*switch_count;//进程切换次数更新        context_switch(rq, prev, next); /* unlocks the rq *///进程之间上下文切换        /*             * the context switch might have flipped the stack from under         * us, hence refresh the local variables.         */        cpu = smp_processor_id();        rq = cpu_rq(cpu);    } else        spin_unlock_irq(&rq->lock);    post_schedule(rq);    if (unlikely(reacquire_kernel_lock(current) < 0))         goto need_resched_nonpreemptible;    preempt_enable_no_resched();    if (need_resched())//如果该进程被其他进程设置了TIF_NEED_RESCHED标志,则函数重新执行进行调度        goto need_resched;}


可见schedule的作用是将当前进程从就绪队列摘除,从就绪队列中选择一个其他符合条件的进程调度运行。何谓符合条件,后面详细分解。其中if (prev->state && !(preempt_count() & PREEMPT_ACTIVE))条件判断中的抢占计数如果PREEMPT_ACTIVE置位对应场景是当前进程被抢占了,此时不再从就绪队列中摘除当前进程,直接调度当前进程释放CPU,以加快选择下一个进程。

II. 哪些场景调用schedule进行调度呢?即调度时机有哪些?汇总如下,后面针对每种场景结合代码分析。

1. 中断,异常

2. 进程退出,睡眠

3. 进程创建,被唤醒,优先级改变时

4. 进程阻塞,如阻塞在信号量,互斥锁

其中2是进程主动调度,其他是被动调度。

III. 概念辨析

1. 禁止抢占就是禁止调度吗?

    看到许多资料提到禁止抢占就意味着禁止调度,何解?首先禁止抢占是针对进程(线程)来说的,所以标题的意思是禁止本进程的抢占意味着本进程不可调度了,和内核抢占配置CONFIG_PREEMPT宏不要混淆,配置宏打开意思是内核态可以抢占,是对所有进程而言的。进程A切换到进程B,有两种情况,一 A主动出让CPU 称作yielding,二 A被调度出让CPU称作preemption,两种都是调度,如果禁止抢占,即是禁止了preemption调度。


参考:http://blog.csdn.net/su_linux/article/details/15500053

http://blog.csdn.net/gatieme/article/details/51872618


0 0
原创粉丝点击