linux2.4内核调度
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
*
* The goto is "interesting".
*
* NOTE!! Task 0 is the 'idle' task, which gets called when no other
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
* information in task[0] is never used.
*/
asmlinkage void schedule(void)
{
struct schedule_data * sched_data;
struct task_struct *prev, *next, *p;
struct list_head *tmp;
int this_cpu, c;
if (!current->active_mm) BUG();//调度时,线程的active_mm不可以为0,借用之前的空间
need_resched_back:
prev = current;//赋值获得当前pcb
this_cpu = prev->processor;
if (in_interrupt())//是否处于中断处理状态,一个bug,将调用bug()
goto scheduling_in_interrupt;
release_kernel_lock(prev, this_cpu);//对单核cpu是空语句
/*检查内核软中断服务请求是否在等待 Do "administrative" work here while we don't hold any locks */
if (softirq_active(this_cpu) & softirq_mask(this_cpu))
goto handle_softirq;//转到下面,进行请求服务
handle_softirq_back:
/*sched_data用于保存一下一次调度时,所需要的信息
* 'sched_data' is protected by the fact that we can run
* only one process per CPU.
*/
sched_data = & aligned_data[this_cpu].schedule_data;
spin_lock_irq(&runqueue_lock);//加锁此队列
/* move an exhausted RR process to be last.. */
if (prev->policy == SCHED_RR)//如果当前进程的调度策略为sched_rr也就是轮换调度,那就特殊处理
goto move_rr_last;//判断时间配额是否用完,用完移到run队列队尾,同时恢复最初时间配额,然后跳到这里
move_rr_back://对sched_rr特殊处理
switch (prev->state) {
case TASK_INTERRUPTIBLE:
if (signal_pending(prev)) {//检测当前进程是否有信号要进行处理
prev->state = TASK_RUNNING;
break;
}
default:
del_from_runqueue(prev);//从可运行队列中删除
case TASK_RUNNING:
}
prev->need_resched = ;//设置为不需要调度,因为所需求的调度已经在运行了
/*
* this is the scheduler proper:
*/
repeat_schedule://接下来挑选一进程来运行了
/*
* Default process to select..
*/
next = idle_task(this_cpu);//指向最佳候选进程
c = -;//设置c的权值为最低值,后面遍历有用
if (prev->state == TASK_RUNNING)//如果当前进程还是处于可运行状态
goto still_running;//如果当前进程还想继续运行,那就从当前进程计算权值开始,相同权值具有优先级
still_running_back:
list_for_each(tmp, &runqueue_head) {
p = list_entry(tmp, struct task_struct, run_list);
if (can_schedule(p, this_cpu)) {//遍历运行队列中的所有进程
int weight = goodness(p, this_cpu, prev->active_mm);//通过goodness计算机它当前所具有的权值
if (weight > c)
c = weight, next = p;
}
}
/* Do we need to re-calculate counters? */
if (!c)//如果已选择的进程(权值最高)为0,那就要从新计算机各个进程的时间配额,说明系统已经没有就绪的实时进程了
goto recalculate;
/*
* from this point on nothing can prevent us from
* switching to the next task, save this fact in
* sched_data.
*/
sched_data->curr = next;
#ifdef CONFIG_SMP
next->has_cpu = ;
next->processor = this_cpu;
#endif
spin_unlock_irq(&runqueue_lock);
if (prev == next)//如果挑选出来的进程是当前进程,那就直接返回
goto same_process;
#ifdef CONFIG_SMP
/*
* maintain the per-process 'last schedule' value.
* (this has to be recalculated even if we reschedule to
* the same process) Currently this is only used on SMP,
* and it's approximate, so we do not have to maintain
* it while holding the runqueue spinlock.
*/
sched_data->last_schedule = get_cycles();
/*
* We drop the scheduler lock early (it's a global spinlock),
* thus we have to lock the previous process from getting
* rescheduled during switch_to().
*/
#endif /* CONFIG_SMP */
kstat.context_swtch++;
/*
* there are 3 processes which are affected by a context switch:
*
* prev == .... ==> (last => next)
*
* It's the 'much more previous' 'prev' that is on next's stack,
* but prev is set to (the just run) 'last' process by switch_to().
* This might sound slightly confusing but makes tons of sense.
*/
prepare_to_switch();//准备调度
{
struct mm_struct *mm = next->mm;//下一进程的mm
struct mm_struct *oldmm = prev->active_mm;//当前进程的mm
if (!mm) {//下一要调度的是线程
if (next->active_mm) BUG();//如果线程连空间都木有,那就bug
next->active_mm = oldmm;//沿用前一进程的空间
atomic_inc(&oldmm->mm_count);//引用计数++
enter_lazy_tlb(oldmm, next, this_cpu);
} else {//下一要调度的是进程
if (next->active_mm != mm) BUG();
switch_mm(oldmm, mm, next, this_cpu);//切换空间
}
if (!prev->mm) {//前一进程为线程
prev->active_mm = NULL;//设置为NULL
mmdrop(oldmm);//释放,这里线程只是把引用计数--
}
}
/*
* This just switches the register state and the
* stack.
*/
switch_to(prev, next, prev);//开始调度------------------
__schedule_tail(prev);//对于新创建的进程,调用后,直接转到ret_from_sys_call返回到用户空间
same_process:
reacquire_kernel_lock(current);//空语句
if (current->need_resched)//前面已经清空为0,现在变成了非0,那就中断发生了有变化
goto need_resched_back;//再次调度
return;
recalculate:
{
struct task_struct *p;
spin_unlock_irq(&runqueue_lock);
read_lock(&tasklist_lock);
for_each_task(p)//将当前进程的时间配额除以2?nice换来的ticks数量
p->counter = (p->counter >> ) + NICE_TO_TICKS(p->nice);
read_unlock(&tasklist_lock);
spin_lock_irq(&runqueue_lock);
}
goto repeat_schedule;
still_running:
c = goodness(prev, this_cpu, prev->active_mm);
next = prev;
goto still_running_back;
handle_softirq:
do_softirq();
goto handle_softirq_back;
move_rr_last:
if (!prev->counter) {//一旦counter为0,表示运行时间配额为0,将从可执行进程队列当前位置移到队列尾部
prev->counter = NICE_TO_TICKS(prev->nice);//恢复最初的时间配额.将根据进程的优先级别换成可运行的时间配额.
move_last_runqueue(prev);
}
goto move_rr_back;
scheduling_in_interrupt://一个bug,在中断处理程序中调度了
printk("Scheduling in interrupt\n");
BUG();
return;
}
goodness函数解析
goodness对于非实时进程来说权重等于时间配额+1(如果是线程,+1)+(20-nice)
nice对于实时进程的权重计算没什么用,不过对sched_rr的时间配额有用
static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm)
{
int weight;
/*
* select the current process after every other
* runnable process, but before the idle thread.
* Also, dont trigger a counter recalculation.
*/
weight = -;
if (p->policy & SCHED_YIELD)//如果当前进程设置了此标志位,表示礼让,权值设置为-1.直接return
goto out;
/*
* Non-RT process - normal case first.
*/
if (p->policy == SCHED_OTHER) {//对于没有实时要求的进程来说
/*
* Give the process a first-approximation goodness value
* according to the number of clock-ticks it has left.
*
* Don't do any other calculations if the time slice is
* over..
*/
weight = p->counter;//weight等于时间配额
if (!weight)//用完了,权值为0,直接返回
goto out; #ifdef CONFIG_SMP
/* Give a largish advantage to the same processor... */
/* (this is equivalent to penalizing other processors) */
if (p->processor == this_cpu)
weight += PROC_CHANGE_PENALTY;
#endif
/* .. and a slight advantage to the current MM */
if (p->mm == this_mm || !p->mm)//如果是内核线程,或者用户空间与当前进程相同,唔需要切换用户空间,获得奖励+1s
weight += ;
weight += - p->nice;//nice也小,优先级越高,范围-20到19.
goto out;
}
/*
* Realtime process, select the first one on the
* runqueue (taking priorities within processes
* into account).//实时进程的nice与优先级无关,但对于sched_rr进程的时间配额大小有关,实时进程就绪时,非实时进程没机会运行
*///对于实时进程来说,则有一种正向优先级,那就是实时优先级rt_priority,由于时间要求,对进程赋予很高的全职
weight = + p->rt_priority;//rt_priotty对实时进程哟很重要的作用
out:
return weight;
}
linux2.4内核调度的更多相关文章
- Linux2.6内核实现的是NPTL
NPTL是一个1×1的线程模型,即一个线程对于一个操作系统的调度进程,优点是非常简单.而其他一些操作系统比如Solaris则是MxN的,M对应创建的线程数,N对应操作系统可以运行的实体.(N<M ...
- Linux2.6 内核的 Initrd 机制解析
文章来自:www.ibm.com/developerworks/cn/linux/l-k26initrd/ 1.什么是 Initrd initrd 的英文含义是 boot loader initial ...
- Linux2.6 内核的 Initrd 机制解析(转)
from: https://www.ibm.com/developerworks/cn/linux/l-k26initrd/ 简介: Linux 的 initrd 技术是一个非常普遍使用的机制,lin ...
- Linux 虚存 linux2.6内核特性
一.大型页面的支持 当代计算机体系结构大都支持多种页面大小,例如,IA-32体系结构支持4KB或4MB的页面, Linux操作系统只是将大型页面用于映射实际的内核映像.大型页面的使用主要是为了改进高性 ...
- Linux 内核调度器源码分析 - 初始化
导语 上篇系列文 混部之殇-论云原生资源隔离技术之CPU隔离(一) 介绍了云原生混部场景中CPU资源隔离核心技术:内核调度器,本系列文章<Linux内核调度器源码分析>将从源码的角度剖析内 ...
- 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度 | 百篇博客分析OpenHarmony源码 | v9.07
百篇博客系列篇.本篇为: v09.xx 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度过程 | 51.c.h .o 前因后果相关篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 ...
- 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 百篇博客分析OpenHarmony源码 | v4.05
百篇博客系列篇.本篇为: v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- Linux2.6内核进程调度系列--scheduler_tick()函数1.总体思想
参考的是ULK第三版,Linux2.6.11.12内核版本. 调度程序依靠几个函数来完成调度工作,其中最重要的第一个函数是scheduler_tick函数,主要步骤如下: /** * 维持当前最新的t ...
- Linux2.6内核--进程调度理论
从1991年Linux的第1版到后来的2.4内核系列,Linux的调度程序都相当简陋,设计近乎原始,见0.11版内核进程调度.当然它很容易理解,但是它在众多可运行进程或者多处理器的环境下都难以胜任. ...
随机推荐
- tcl之内容
- mysql中的FROM_UNIXTIME()函数和UNIX_TIMESTAMP()函数
unix_timestamp 是时间戳,可以用数据库里的存储时间数据的字段 from_unixtime 是将时间戳格式化为你想要时间
- day 44 前端HTML
前端HTML HTML介绍 Web服务本质 import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) sk ...
- python3.7 time模块
#!/usr/bin/env python __author__ = "lrtao2010" #python3.7 time模块 #time模块没有time.py文件,是内置到解释 ...
- 2 - JVM随笔分类(JVM堆的内存回收)
JVM常用的回收算法是: 标记/清除算法 标记/复制算法 标记/整理算法 其中上诉三种算法都先具备,标记阶段,通过标记阶段,得到当前存活的对象,然后再将非标记的对象进行清除,而对象内存中对象的标记过程 ...
- SSH进阶之路
[SSH进阶之路]Hibernate基本原理(一) 在开始学Hibernate之前,一直就有人说:Hibernate并不难,无非是对JDBC进一步封装.一句不难,难道是真的不难还是眼高手低 ...
- django项目在uwsgi+nginx上部署遇到的坑
本文来自网易云社区 作者:王超 问题背景 django框架提供了一个开发调试使用的WSGIServer, 使用这个服务器可以很方便的开发web应用.但是 正式环境下却不建议使用这个服务器, 其性能.安 ...
- leetcode 【 Convert Sorted List to Binary Search Tree 】python 实现
题目: Given a singly linked list where elements are sorted in ascending order, convert it to a height ...
- poj1111(单身快乐)
...
- [oldboy-django][1初始django]模态对话框 + 动态加载gif (多对多数据库表)
ajax+对话框(多对多) - 遮罩层,动态加载gif层,对话框层, a.一点击添加,绑定事件: - 出现遮罩层和动态gif层 - ajax向后台发送请求获取所有班级数据 - success,隐藏动态 ...