概述
基于 3.10.90 内核代码
在 kernelschedcore.c 里, 对于 __schedule 有如下注释:
/*
* __schedule() is the main scheduler function.
*
* The main means of driving the scheduler and thus entering this function are:
*
* 1. Explicit blocking: mutex, semaphore, waitqueue, etc.
* (1) mutext:
* mutex_lock --> might_sleep --> might_resched --> 定义了 CONFIG_PREEMPT_VOLUNTARY ,则 _cond_resched
* --> if (should_resched()) __cond_resched() --> __schedule
* (2) semaphore:
* void down(struct semaphore *sem) --> __down --> __down_common --> schedule_timeout --> schedule
* void up(struct semaphore *sem) --> __up --> wake_up_process --> try_to_wake_up --> ttwu_queue
* --> ttwu_do_activate --> ttwu_do_wakeup --> check_preempt_curr
* --> resched_task(rq->curr); --> set_tsk_need_resched 没有直接调用 schedule, 而是只设置 TIF_NEED_RESCHED 标志位。
* (3) waitqueue
* wake_up_interruptible --> __wake_up --> __wake_up_common --> default_wake_function --> try_to_wake_up
*
* 2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return
* paths. For example, see arch/x86/entry_64.S.
*
* To drive preemption between tasks, the scheduler sets the flag in timer
* interrupt handler scheduler_tick().
* scheduler_tick 设置 TIF_NEED_RESCHED 的流程如下:
* scheduler_tick --> curr->sched_class->task_tick --> task_tick_fair
* --> check_preempt_tick --> resched_task --> set_tsk_need_resched
* --> set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
*
* 3. Wakeups don't really cause entry into schedule(). They add a
* task to the run-queue and that's it.
* wakeups 设置 TIF_NEED_RESCHED 的过程为:
* wake_up_process --> try_to_wake_up --> ttwu_queue
* --> ttwu_do_activate --> ttwu_do_wakeup --> check_preempt_curr
* --> resched_task(rq->curr); --> set_tsk_need_resched
*
* Now, if the new task added to the run-queue preempts the current
* task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
* called on the nearest possible occasion: *
*
* - If the kernel is preemptible (CONFIG_PREEMPT=y):
*
* - in syscall or exception context, at the next outmost
* preempt_enable(). (this might be as soon as the wake_up()'s
* spin_unlock()!)
* (1) syscall 流程: vector_swi --> ret_fast_syscall (disable_irq) -->
* --> fast_work_pending --> work_pending --> do_work_pending -->
* if (likely(thread_flags & _TIF_NEED_RESCHED)) {
* schedule();
* (2) exception 流程:
* __dabt_usr --> ret_from_exception --> ret_to_user
* --> ret_slow_syscall(disable_irq) --> ret_to_user_from_irq --> work_pending
* 后续流程与上面的 syscall 流程相同
* __dabt_svc --> svc_exit --> 没有调用到 schedule
* (3) preempt_enable --> preempt_check_resched -->
* 当设置了 TIF_NEED_RESCHED 时,preempt_schedule -->
* 当中断未禁止并且未被抢占,则进行抢占并 __schedule
*
* (4) spin_unlock --> raw_spin_unlock --> _raw_spin_unlock --> __UNLOCK --> preempt_enable 与上面的流程相同
*
* - in IRQ context, return from interrupt-handler to
* preemptible context
* (1) __irq_svc --> 当定义了 CONFIG_PREEMPT 时,如果当前未抢占,且 _TIF_NEED_RESCHED置位,则
* 调用 svc_preempt --> preempt_schedule_irq --> 先禁止抢占,然后使能中断后 __schedule 。
* (2) __irq_usr --> ret_to_user_from_irq --> work_pending 和上面的 syscall 流程相同
*
* - If the kernel is not preemptible (CONFIG_PREEMPT is not set)
* then at the next:
*
* - cond_resched() call
* - explicit schedule() call
* - return from syscall or exception to user-space --- 即上面的 syscall 流程 和 exception 流程 __dabt_usr
* - return from interrupt-handler to user-space --- 即上面的 __irq_usr 流程
*/
最后
以上就是风趣小馒头为你收集整理的linux arm 进程调度时机的全部内容,希望文章能够帮你解决linux arm 进程调度时机所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复