第八周 进程的切换和系统的一般执行过程【转】

转自:http://www.cnblogs.com/20135305yg/p/5379542.html

一.进程切换的关键代码switch_to分析

进程的调度时机与进程的切换:

操作系统中的进程调度算法是从运行队列中选择一个新进程,选择的过程中运用了不同的策略

进程调度的时机:

  • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule()
  • 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度
  • 用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度

进程的切换:

  • 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换
  • 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行
  • 进程上下文包含了进程执行需要的所有信息
    • 用户地址空间: 包括程序代码,数据,用户堆栈等
    • 控制信息 :进程描述符,内核堆栈等
    • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
  • schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换
    • next = pick_next_task(rq, prev);//进程调度算法都封装这个函数内部
    • context_switch(rq, prev, next);//进程上下文切换
    • switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

二.Linux系统的一般执行过程

Linux系统的一般执行过程最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

  1. 正在运行的用户态进程X
  2. 发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
  3. SAVE_ALL //保存现场
  4. 中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
  5. 标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
  6. restore_all//恢复现场
  7. iret - pop cs:eip/ss:esp/eflags from kernel stack
  8. 继续运行用户态进程Y

几种特殊情况:

    • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
    • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
    • 创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;
    • 加载一个新的可执行程序后返回到用户态的情况,如execve;

三.实验:使用gdb跟踪分析一个schedule()函数 ,验证对Linux系统进程调度与进程切换过程的理解

终端输入qemu –kernel linux-3.18.6/arch/x86/boot/bzImage –initrd rootfs.img –S –s 
然后打开另一个终端输入

gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)b schedule
(gdb)c

进行调试跟踪schedule的执行过程 

进程调度时,首先进入schedule()函数,将一个task_struct结构体的指针tsk赋值为当前进程
然后调用sched_submit_work(tsk) 
我们进入这个函数,查看一下做了什么工作 
我们在执行到sched_submit_work时,输入si进入函数


可以看到这个函数时检测tsk->state是否为0 (runnable)若为运行态时则返回
tsk_is_pi_blocked(tsk),检测tsk的死锁检测器是否为空,若非空的话就return

然后检测是否需要刷新plug队列,用来避免死锁
sched_submit_work主要是来避免死锁
然后我们进入__schedule()函数

__schedule()是切换进程的真正代码,我们来分析一下具体的关键代码 
1.创建一些局部变量

struct task_struct *prev, *next;//当前进程和一下个进程的进程结构体
unsigned long *switch_count;//进程切换次数
struct rq *rq;//就绪队列
int cpu;

2.关闭内核抢占,初始化一部分变量

need_resched:
preempt_disable();//关闭内核抢占
cpu = smp_processor_id();
rq = cpu_rq(cpu);//与CPU相关的runqueue保存在rq中
rcu_note_context_switch(cpu);
prev = rq->curr;//将runqueue当前的值赋给prev

3.选择next进程

next = pick_next_task(rq, prev);//挑选一个优先级最高的任务排进队列
clear_tsk_need_resched(prev);//清除prev的TIF_NEED_RESCHED标志。
clear_preempt_need_resched();

4.完成进程的调度

if (likely(prev != next)) {//如果prev和next是不同进程
        rq->nr_switches++;//队列切换次数更新
        rq->curr = next;
        ++*switch_count;//进程切换次数更新

        context_switch(rq, prev, next); /* unlocks the rq *///进程上下文的切换
        /*
         * The context switch have flipped the stack from under us
         * and restored the local variables which were saved when
         * this task called schedule() in the past. prev == current
         * is still correct, but it can be moved to another cpu/rq.
         */
cpu = smp_processor_id();
        rq = cpu_rq(cpu);
    } else//如果是同一个进程不需要切换
        raw_spin_unlock_irq(&rq->lock);

这段代码中context_switch(rq,prev,next)完成了从prev到next的进程上下文的切换。我们进入这个函数查看

static inline void
context_switch(struct rq *rq, struct task_struct *prev,
           struct task_struct *next)
{
    struct mm_struct *mm, *oldmm;//初始化进程地址管理结构体mm和oldmm
    prepare_task_switch(rq, prev, next);//完成进程切换的准备工作
    mm = next->mm;
    oldmm = prev->active_mm;
    /*完成mm_struct的切换*/
if (!mm) {
        next->active_mm = oldmm;
        atomic_inc(&oldmm->mm_count);
        enter_lazy_tlb(oldmm, next);
    } else
        switch_mm(oldmm, mm, next);
    if (!prev->mm) {
        prev->active_mm = NULL;
        rq->prev_mm = oldmm;
    }
switch_to(prev, next, prev);//进程切换的核心代码
barrier();
finish_task_switch(this_rq(), prev);
}

我们看到在context_switch中使用switch_to(prev,next,prev)来切换进程。我们查看一下switch_to的代码
switch_to是一个宏定义,完成进程从prev到next的切换,首先保存flags,然后保存当前进程的ebp,然后把当前进程的esp保存到prev->thread.sp中,然后把标号1:的地址保存到prev->thread.ip中
然后把next->thread.ip压入堆栈。这里,如果之前B也被switch_to出去过,那么next->thread.ip里存的就是下面这个1f的标号,但如果next进程刚刚被创建,之前没有被switch_to出去过,那么next->thread.ip里存的将是ret_ftom_fork__switch_canqry应该是现代操作系统防止栈溢出攻击的金丝雀技术
jmp __switch_to使用regparm call, 参数不是压入堆栈,而是使用寄存器传值,来调用__switch_to 
eax存放prev,edx存放next。这里为什么不用call __switch_to而用jmp,因为call会导致自动把下面这句话的地址(也就是1:)压栈,然后__switch_to()就必然只能ret到这里,而无法根据需要ret到ret_from_fork 
当一个进程再次被调度时,会从1:开始执行,把ebp弹出,然后把flags弹出。

5.开启抢占

sched_preempt_enable_no_resched();
if (need_resched())
        goto need_resched;

到此,进程的切换过程就完成了

时间: 2024-09-22 06:05:32

第八周 进程的切换和系统的一般执行过程【转】的相关文章

进程的切换和系统的一般执行过程【转】

转自:http://www.cnblogs.com/20135124freedom/p/5391170.html 陈民禾 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一.关于进程调度的基本知识       进程的几种不同分类:第一种分类:类型一:I/O-bound:频繁的进行I/O,通常会花费很多的时间等待I/O操作的完成:类型二:CPU-bound:计算密集型 ,需要大量的CPU

惠普董事会早在八周前就在密谋解聘李艾科

北京时间9月24日消息,据国外媒体报道,惠普董事长雷·兰恩(Ray Lane)9月21日通知李艾科(Leo Apotheker)他已经被解聘.此前八周,董事会就开始考虑解聘李艾科了. 李艾科成为过去7年中被惠普董事会解聘的第三位CEO,他的继任者eBay前CEO梅格·惠特曼(Meg Whitman)继承的是一个增长缓慢,过去6个月股价下跌47%的"烂摊子". 甚至在批准加速李艾科下课的战略转变的同时,惠普董事会还在考虑解聘李艾科的问题.惠普8月18日宣布斥资103亿美元收购英国软件厂商

美旧金山市政府遭遇网络政变 电脑瘫痪八周

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 美国旧金山市政府电脑软件工程师查尔兹被控非法窜改市府网络系统的主密码,让获得授权进入电脑系统的市政府员工不得其门而入.案发后,查尔兹因拒绝提交多达500万美元的保释金而遭羁押,但他仍不愿透露动过手脚的密码为何,让市政府电脑瘫痪至今. 恐需八周才能破解 据台湾<中国时报>报道,旧金山地区检察官表示,现年43岁的查尔兹涉嫌对市政府花了

Linux中进程前后台切换相关命令

我们使用Linux时大多数是用shell命令行.一个命令窗口是无法直接执行多任务的.我们可以把某个任务先切到后台,再切别的任务到前台来操作.这个帖子整理一下这些常用的命令. 后台进程查看: jobs是用于后台进程查看的很方便的命令. jobs -l 可以显示出进程的pid. 注意一点:shell收到了SIGHUP信号后在退出前将SIGHUP转发给所有的作业(jobs).jobs由于收到SIGHUP而终止运行.(这取决于shell的) 将前台任务放到后台: 按下ctrl + z ,就将任务移到后台

winform-C#关闭进程,如何判断系统是否正在运行此进程

问题描述 C#关闭进程,如何判断系统是否正在运行此进程 准备用C#关闭某进程,比如explorer进程,如何判断系统是否正在运行此进程,从而避免因为系统不存在此进程而报错? 用的是这个方法,但是如果系统中未运行该进程,就会报错 string ProcessName = ""explorer""; Process[] MyProcess = Process.GetProcessesByName(ProcessName); MyProcess[0].Kill(); 解决

百度切换广告系统让Google得利还是站长得利

中介交易 SEO诊断 淘宝客 云主机 技术大厅 路透社发表分析文章称,百度切换广告系统,让Google有机会提高其在中国互联网搜索市场的份额,以下为原文内容: 2005年,中国在一个搜索市场报告中进行了一次拼写测试,要求受访者拼出"Google"一词,结果只有60%的人通过测试,而20%多的人则拼错.4年后,在全世界多数地区,Google公司的名称已经成为互联网搜索的代名词,但是在中国这个全球最大的互联网市场,Google依然在为努力获得认可,本土竞争对手百度通知了该市场. 然而,百度

光纤自动切换保护系统应用探讨

1.引言要在现有几十万千米高速干线光缆通信网上实现无阻断通信,除传输设备外,运营商首先要考虑的是如何实现光传输物理路由的自动保护.光纤自动切换保护系统是一个集监测.保护和管理为一体的.独立于传输系统的.完全建立在光缆物理层上的自动监测保护系统.该系统能进行光纤运行状态.性能指标的实时.在线.远程.自动监测与主备光缆的切换保护,保证光缆网络安全可靠地运行.2.工作原理自动切换模块可分为单片机控制电路.光功率监测电路.光切换电路.测试 光源电路几部分,其工作原理如图1所示.控制电路控制其他模块电路协

央行公开市场连续八周净回笼资金面暂时无虞

12月第一周,央行公开市场操作延续紧缩风格.通过发行央行票据和正回购交易,央行周内累计净回笼220亿元,这也是央行自国庆后连续第八周净回笼资金.不过,分析人士表示,尽管央行加大了回笼力度,货币市场资金面仍将继续保持宽裕. 利率未动 数量先行 12月3日,央行以价格招标方式发行了2009年第六十三期央行票据,并开展了正回购操作.本期央票发行量为700亿元,期限3个月,发行价格99.67元,参考收益率为1.328%,与上一期持平:同时,央行在公开市场中进行了91天期正回购交易,交易量300亿元,中标

一次Linux系统被攻击的分析过程

IT行业发展到现在,安全问题已经变得至关重要,从最近的"棱镜门"事件中,折射出了很多安全问题,信息安全问题已变得刻不容缓,而做为运维人员,就必须了解一些安全运维准则,同时,要保护自己所负责的业务,首先要站在攻击者的角度思考问题,修补任何潜在的威胁和漏洞. 一次Linux被入侵后的分析 下面通过一个案例介绍下当一个服务器被rootkit入侵后的处理思路和处理过程,rootkit 攻击是Linux系统下最常见的攻击手段和攻击方式. 1.受攻击现象 这是一台客户的门户网站服务器,托管在电信机