Linux内核分析-9/进程的调度时机
上篇博客已经讲了调度的路径 明白了 1/调度都是在内核中间进行的,调用调度函数的函数A都是在内核态 2/调用调度函数的函数A都是由两个路径
1/用户态陷入内核态,调用 调度 (时机根据内核版本不同而不同,但都是在内核态调用) 2/因为中断,进入中断处理函数,调用 调度 (中断处理函数在内核态中)
linux-0.11中的调度时机
linux-0.11中调用 schedule 函数的次数 屈指可数,总共8次
这个函数在时钟中断函数中被调用的, 函数 do_timer 直接调用了 schedule
这个函数是 在exit 和wait uname 的 底层路径 中调用的 ,函数 release 直接调用了 release
这个函数是 被 exit 和 signal do_no_page(页异常中断处理函数) 和其他系统调用 调用的 .
这个函数是被 waitpid 调用的
这个函数是被 pause 调用的
这个函数 是被 sync dev open mount setup mkdir read umount execv 调用
这个函数是 不可中断的睡眠,相对于 sleep_on(可中断) 来说用的地方要少 ,被 open mount setup write read 调用
这个函数的调用路径 tty_write(sys_write->rw_char->crw_table->rw_tty->rw_ttyx->tty_write- 写阻塞 ->schedule)
从上面可以看到,linux-0.11中的调用时机只有两种:
linux(高版本)的调度时机
可见linux-0.11中的调度时机分为两种,一种是系统调用,一种是中断处理函数,但归结起来,都是中断引起的. 不过一个是软中断,一个是硬中断 但是后来的东西怎么变了呢?哪里变了呢?CHANGELOG
分类变了,但还是哪两种?现在被称呼为主动调度 和被动调度 1.主动调度就是之前的系统调用. 2.被动调度还是之前的中断处理和部分系统调用(都走 ret_from_sys_call ),不过这次不是在中断处理过程中调用的 schedule 函数,而是在中断处理函数返回之后,进入用户态之前(即 ret_from_sys_call 之后)根据 进程调度标志 need_resched 调用的. 3.另外linux-2.6之前的内核只支持从用户态开始的的调度,不支持从内核态的调度.如果在内核态下,发生调度什么的,只能先出内核态(即到达用户态),再陷入内核态做调度,这样增加了消耗(内核态->用户态->内核态 的 过程).内核态的抢占是通过 ( ret_from_sys_call ) 后的 preempt_schedule_irq 进行的 要细分的话可以分为很多种,请看下面的分类
1 /主动调度
1.1 /正在执行的进程执行完毕。 例如 exit
1.2 /正在执行的进程发出IO请求。例如 read
1.3 /正在执行的进程要等待其他进程或系统发出的事情时。 wait
1.4 / 正在执行的进程中那是得不到所要的系统资源。 pthread_mutex_lock
2 /被动调度(都是在ret_from_sys_call中被调用的,通过检测 need_resched )
2.1 /当中断处理程序处理完中断 IO中断
2.2 /进程释放独占资源 pthread_mutex_unlock
2.3 /某进程发“发送消息”系统调用 signal
2.4 /其他任何原因引起有进程从其他状态变成就绪状态
3 /没有新就绪进程,但原进程时间片到或优先级发生变化。
3.1 /时钟中断函数中的 调用 调度
3.2 /系统调用改变进程的优先级变化后的 调度
Linux的进程调度时机与现代操作系统中的调度时机基本一致,为了判断是否可以执行内核的进程调度程序来调度进程,Linux中设置了进程调度标志 need_resched ,当标志为1 时,可执行调度程序.
通常,Linux调度时机分以下两种情况:
(1 )主动调度:指显式调用schedule()函数明确释放CPU,引起新一轮调度.一般发生在当前进程状态改变,如:进程终止、进程睡眠、进程对某些信号处理过程中等.
(2 )被动调度:指不显示调用schedule()函数,只是PCB中的 need_resched 进程调度标志,该域置位为1 将引起新的进程调度,而每当中断处理和系统调用返回时,核心调度程序都会主动查询need_resched的状态(若置位,则主动调用 schedule ()函数。一般发生在新的进程产生时、某个进程优先级改变时、某个进程等待的资源可用被唤醒时、当前进程时间片用完等.
1 、进程状态转换的时刻:进程终止、进程睡眠;
2 、当前进程的时间片用完时(current->counter=0 );
3 、设备驱动程序
4 、进程从中断、异常及系统调用返回到用户态时;
void resched_task(struct task_struct *p)
{
int cpu;
assert_raw_spin_locked(&task_rq(p)->lock);
if (test_tsk_need_resched(p))
return ;
set_tsk_need_resched(p);
cpu = task_cpu(p);
if (cpu == smp_processor_id())
return ;
smp_mb();
if (!tsk_is_polling(p))
smp_send_reschedule(cpu);
}
资料
linux调度器源码分析 - 概述(一)
need_resched 是怎么使用的(ZT)
调度时机分析之被动调度(之内核态抢占调度)
进程调度的时机与进程的切换
深入分析linux调度机制 Linux进程调度机制