第一次作业:深入源码分析进程模型

Posted lzpbk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第一次作业:深入源码分析进程模型相关的知识,希望对你有一定的参考价值。

前言:源代码下载地址:https://elixir.bootlin.com/linux/v2.6.39/source  

一、操作系统是怎么组织进程的

 1.进程是什么?

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。(参考https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B/382503?fr=aladdin)

2.怎么组织进程?

1)Linux通过task_struct结构体来描述一个进程的所有信息,结构体被定义在 include/linux/sched.h中。

struct task_struct {

.....
volatile long state; //进程状态
void *stack; //内存指针
atomic_t usage;
unsigned int flags; //进程标号(进程名字)
unsigned int ptrace;

int lock_depth; //BLK 锁深度

#ifdef CONFIG_SMP
#ifdef __ARCH_WANT_UNLOCKED_CTXSW //配置多核多线程
int oncpu;
#endif
#endif

int prio, static_prio, normal_prio; //进程的优先级
unsigned int rt_priority; //实时进程的优先级
const struct sched_class *sched_class; //调度器的指针
struct sched_entity se; //调度器 实例化的对象
struct sched_rt_entity rt; //实时 调度器的一个对象

#ifdef CONFIG_PREEMPT_NOTIFIERS //配置抢占通知器
/* struct preempt_notifier列表 */
struct hlist_head preempt_notifiers;
#endif
....

};

 

2)task_struct结构体即是PCB。PCB是进程的唯一标识,PCB由链表实现(为了动态插入和删除)。进程创建时,为该进程生成一个PCB;进程终止时,回收PCB

进程控制块PCB的组织方式有:1)线性表方式,2)索引表方式,3)链接表方式。
 
进程控制块PCB的组织方式
1)线性表方式:不论进程的状态如何,将所有的PCB连续地存放在内存的系统区。这种方式适用于系统中进程数目不多的情况。
2)索引表方式:该方式是线性表方式的改进,系统按照进程的状态分别建立就绪索引表、阻塞索引表等。
3)链接表方式:系统按照进程的状态将进程的PCB组成队列,从而形成就绪队列、阻塞队列、运行队列等。

(参考https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E5%9D%97%E7%BB%84%E7%BB%87%E6%96%B9%E5%BC%8F)

 

二.进程状态如何转换(给出进程状态转换图)

 1. 进程状态(State)

进程执行时,它会根据具体情况改变状态 。进程状态是调度和对换的依据。Linux中的进程主要有如下状态

·可运行状态

处于这种状态的进程,要么正在运行、要么正准备运行。正在运行的进程就是当前进程(由current所指向的进程),而准备运行的进程只要得到CPU就可以立即投入运行,CPU是这些进程唯一等待的系统资源。系统中有一个运行队列(run_queue),用来容纳所有处于可运行状态的进程,调度程序执行时,从中选择一个进程投入运行。在后面我们讨论进程调度的时候,可以看到运行队列的作用。当前运行进程一直处于该队列中,也就是说,current总是指向运行队列中的某个元素,只是具体指向谁由调度程序决定。

·等待状态

处于该状态的进程正在等待某个事件(event)或某个资源,它肯定位于系统中的某个等待队列(wait_queue)中。Linux中处于等待状态的进程分为两种:可中断的等待状态和不可中断的等待状态。处于可中断等待态的进程可以被信号唤醒,如果收到信号,该进程就从等待状态进入可运行状态,并且加入到运行队列中,等待被调度;而处于不可中断等待态的进程是因为硬件环境不能满足而等待,例如等待特定的系统资源,它任何情况下都不能被打断,只能用特定的方式来唤醒它,例如唤醒函数wake_up()等。

·暂停状态

此时的进程暂时停止运行来接受某种特殊处理。通常当进程接收到SIGSTOP、SIGTSTP、SIGTTIN或 SIGTTOU信号后就处于这种状态。例如,正接受调试的进程就处于这种状态。

·僵死状态

进程虽然已经终止,但由于某种原因,父进程还没有执行wait()系统调用,终止进程的信息也还没有回收。顾名思义,处于该状态的进程就是死进程,这种进程实际上是系统中的垃圾,必须进行相应处理以释放其占用的资源。

 

(参考 https://blog.csdn.net/mu0206mu/article/details/7348618  https://www.cnblogs.com/hanxiaoyu/p/5549212.html)

三.进程是如何调度的

1. 进程调度信息

调度程序利用这部分信息决定系统中哪个进程最应该运行,并结合进程的状态信息保证系统运转的公平和高效。这一部分信息通常包括进程的类别(普通进程还是实时进程)、进程的优先级等等。

2.进程的调度策略有三种

 

注:只有root用户能通过sched_setscheduler()系统调用来改变调度策略。

 

asmlinkage void __sched schedule(void)
{
struct task_struct *prev, *next; //当前进程、下一个进程的结构体
unsigned long *switch_count; //进程切换次数
struct rq *rq; //就绪队列
int cpu;

need_resched:
preempt_disable(); //关闭内核抢占
cpu = smp_processor_id(); //找到当前CPU上的就绪队列rq
rq = cpu_rq(cpu);
rcu_note_context_switch(cpu);
prev = rq->curr; //将正在运行的进程保存在prev

.......

switch_count = &prev->nivcsw; //切换次数记录

if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { //当前进程非运行状态,并且非内核抢占

if (unlikely(signal_pending_state(prev->state, prev))) { //设置进程为就绪状态
prev->state = TASK_RUNNING;
} else { //若为非挂起信号,则将其从队列中移出

......

pre_schedule(rq, prev); //通知调度器,即将发生进程切换

if (unlikely(!rq->nr_running))
idle_balance(cpu, rq);

put_prev_task(rq, prev); //通知调度器,即将用另一个进程替换当前进程
next = pick_next_task(rq); //挑选可运行的任务
clear_tsk_need_resched(prev); //清除pre的TIF_NEED_RESCHED标志
rq->skip_clock_update = 0;

if (likely(prev != next)) { //如果不是同一个进程
rq->nr_switches++;
rq->curr = next; //将当前进程切换成挑选的那个进程
++*switch_count; //切换次数更新

context_switch(rq, prev, next); /* unlocks the rq */ //进程上下文切换
.....

post_schedule(rq); //完成进程切换

preempt_enable_no_resched();
if (need_resched()) //如果该进程被其他进程设置了TIF_NEED_RESCHED标志,则函数重新执行进行调度
goto need_resched;
}

(参考 https://www.cnblogs.com/hanxiaoyu/p/5549212.html)

 四.谈谈自己对该操作系统进程模型的看法

真心感觉了解一下操作系统是一件挺有意义的事,毕竟,老实来说,随着美国芯片的禁止,国家估计在硬件与操作系统的重视度会大大加强。而且,如果想打好代码 ,了解一下操作系统也是非常有必要的。

五.参考资料

https://elixir.bootlin.com/linux/v2.6.39/source  

 

https://www.cnblogs.com/hanxiaoyu/p/5549212.html

 https://blog.csdn.net/mu0206mu/article/details/7348618  

https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E5%9D%97%E7%BB%84%E7%BB%87%E6%96%B9%E5%BC%8F

以上是关于第一次作业:深入源码分析进程模型的主要内容,如果未能解决你的问题,请参考以下文章

第一次作业:基于Linux系统深入源码分析进程模型

第一次作业:深入源码分析进程模型

第一次作业:基于Linux0.01深入源码分析进程模型

第一次作业:深入源码分析进程模型

第一次作业:深入源码分析进程模型(Linux kernel 2.6.32)

第一次作业:深入源码分析进程模型