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

1.前言

本文主要基于Linux 2.6源代码分析进程模型。源代码下载地址:https://elixir.bootlin.com/linux/v2.6.39/source

2.进程

定义:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

3.Linux系统进程的组织

进程是由进程控制块(PCB)、程序段、数据段三部分组成。

3.1 进程控制块

进程控制块(Processing Control Block),是操作系统核心中一种数据结构,主要表示进程状态,是系统为了管理进程设置的一个专门的数据结构。在Linux中,这个结构叫做task_struct。task_struct被定义在/include/linux/sched.h中。

源代码地址

PCB包含信息:

  • 进程标识符:每个进程都必须有一个唯一的标识符

    pid_t pid; //进程的唯一标识
    pid_t tgid; //线程组的领头线程的pid成员的值
  • 进程状态

    volatile long state;
  • 进程优先级

    int prio, static_prio, normal_prio;
    unsigned int rt_priority;

    prio表示进程的动态优先级,static_prio表示进程的静态优先级,normal_prio表示基于进程的静态优先级和调度策略计算出的优先级,rt_priority表示实时进程的优先级。

  • CPU现场保护区
  • 进程相应的程序和数据地址
  • 进程资源清单
  • 信号处理信息
  • 文件系统的信息
  • 与进程有关的其他信息

3.2 程序段

程序段:被CPU执行的程序代码

3.3 数据段

数据段:进程对应的程序中原来的数据或程序执行后产生的结果。

4.Linux系统中进程的状态及转换

4.1 进程的状态

  • 进程的三种基本状态:

运行态(该时刻进程实际占用CPU)

就绪态(可运行,但因为其他进程正在运行而暂时停止)

阻塞态(除非某种外部事件发生,否则进程不能运行)

  • 在Linux系统中,进程的状态有以下几种,定义在/include/linux/sched.h中。

源代码地址:https://elixir.bootlin.com/linux/v2.6.37/source/include/linux/sched.h#L182

#define TASK_RUNNING        0      //可执行状态
#define TASK_INTERRUPTIBLE    1    //可中断的睡眠状态
#define TASK_UNINTERRUPTIBLE    2  //不可中断的睡眠状态
#define __TASK_STOPPED        4    //暂停状态
#define __TASK_TRACED        8     //跟踪状态
/* in tsk->exit_state */
//终止状态
#define EXIT_ZOMBIE        16
#define EXIT_DEAD        32
TASK_RUNNING是就绪态,进程当前只等待CPU资源。TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE都是阻塞态,进程当前正在等待除CPU外的其他系统资源;前者可以被信号唤醒,后者不可以。ZOMBIE是僵尸进程,进程已经结束运行,但是进程控制块尚未注销。TASK_STOPPED是挂起状态,主要用于调试目的。进程接收到SIGSTOP信号后会进入该状态,在接收到SIGCONT后又会恢复运行。

4.2 进程的创建

在Linux中主要提供了fork()、vfork()、clone()三个进程创建方法。

在Linux系统中可以使用fork()来创建一个进程,fork()函数用于从已存在的进程中创建一个新的进程。新进程为子进程,原进程为父进程。使用fork()函数得到的子进程时父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文,代码段,进程堆栈,内存信息,文件描述符,信号控制设定,进程优先级,进程组号,当前工作目录,根目录,资源限制和控制终端等,而子进程所独有的只有它的进程号,资源使用和计时器等子进程几乎是父进程的完全复制,所以父子进程会同时运行一个程序。vfork()函数则只复制task_struct和内核堆栈。

4.3 状态的转换

进程状态转换图如下图所示:

1.进程因为等待输入而被阻塞

2.调度程序选择另一个进程

3.调度程序选择这个进程

4.出现有效输入

5.进程结束

4.4进程的终止

  • 正常退出
  • 出错退出
  • 严重错误
  • 被其他进程杀死

5.进程的调度

当计算机系统是多道程序设计系统时,通常就会有多个进程通时竞争CPU。只要有两个或更多的进程处于就绪状态,这种情形就会发生。如果只有一个CPU可用,那么就必须选择下一个要运行的进程。完成选择工作的部分称为调度,使用的算法称为调度算法。

5.1 何时调度

有关调度的一个关键问题是何时进行调度决策。

  • 在创建一个新进程之后,需要决定是运行父进程还是运行子进程。这两种进程都处于就绪状态,可以任意决定。
  • 在一个进程退出时必须做出调度决策。从就绪进程中选择某个进程,如果没有就绪的进程,通常会运行一个系统提供的空闲进程。
  • 当一个进程阻塞在I/O和信号量上或由于其他原因阻塞时,必须选择另一个进程运行。
  • 在一个I/O中断发生时,必须做出调度决策。

5.2 如何调度

schedule():进程调度函数,由它来完成进程的调度。该函数的主要流程如下:先关闭内核抢占,找到当前CPU上的就绪队列,检查prev的状态,如果是非运行状态的,且在内核中没有被抢占,从队列rq中删除。但如果prev有挂起信号,设置其状态为TASK_RUNNING状态,保留在队列rq中。然后挑选优先级高的下一个进程,并且通知调度器即将进行切换,更新队列中保存的进程信息,最后通知调度类,完成进程切换。

源代码地址:https://elixir.bootlin.com/linux/v2.6.39/source/kernel/sched.c

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

    schedule_debug(prev);

    if (sched_feat(HRTICK))
        hrtick_clear(rq);

    raw_spin_lock_irq(&rq->lock);

    switch_count = &prev->nivcsw;   //切换次数记录
    if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { //当前进程非运行状态,并且非内核抢占

        if (unlikely(signal_pending_state(prev->state, prev))) { //若不是非挂起信号,设置进程为就绪状态
            prev->state = TASK_RUNNING;
        } else { //若为非挂起信号,则将其从队列中移出
            /*
             * If a worker is going to sleep, notify and
             * ask workqueue whether it wants to wake up a
             * task to maintain concurrency.  If so, wake
             * up the task.
             */
            if (prev->flags & PF_WQ_WORKER) {
                struct task_struct *to_wakeup;

                to_wakeup = wq_worker_sleeping(prev, cpu);
                if (to_wakeup)
                    try_to_wake_up_local(to_wakeup);
            }
            deactivate_task(rq, prev, DEQUEUE_SLEEP);

            /*
             * If we are going to sleep and we have plugged IO queued, make
             * sure to submit it to avoid deadlocks.
             */
            if (blk_needs_flush_plug(prev)) {
                raw_spin_unlock(&rq->lock);
                blk_schedule_flush_plug(prev);
                raw_spin_lock(&rq->lock);
            }
        }
        switch_count = &prev->nvcsw;
    }

    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 */ //进程上下文切换
        /*
         * 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);

    post_schedule(rq); //通知调度类,完成进程切换

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

6.对操作系统模型的看法

操作系统是实现资源管理,程序控制和人机交互的计算机程序。系统的设备资源和信息资源是操作系统根据用户需求按一定的策略来进行分配和调度的 ;一个用户程序的执行自始至终是在操作系统控制下进行的;操作系统的人机交互功能可以使计算机系统更“友善”。

7.参考资料

https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B/382503?fr=aladdin

https://blog.csdn.net/u013592097/article/details/52530129

https://blog.csdn.net/hzk8656511/article/details/52204016

http://blog.sina.com.cn/s/blog_9ca3f6e70102wkwq.html

原文地址:https://www.cnblogs.com/cclxq/p/8975423.html

时间: 2024-10-10 20:02:59

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

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

一.前言 本文主要基于Linux0.01源代码分析进程模型.Linux 0.01虽然是Linux的第一个发行版本,但是却基本具备了操作系统中最重要的组成部分,同时Linux 0.01只有8500行左右的代码,对于初学者而言学习起来比较简单一点. Linux 0.01源代码下载地址: https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/ 二.进程的定义 进程是程序执行的基本单位.(其中,进程和程序的区别:程序指的是由若干函数组成的可执

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

1.前言 本文基于Linux 2.6.32分析其进程模型,包括进程的概念.组织.转换.调度等内容,帮助对操作系统课程及Linux相关知识的理解和学习. 附Linux Kernel 2.6.32源码下载地址: https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.gz 2.进程的概念 2.1什么是进程? 在正式开始结合源代码分析进程模型之前,我们首先需要搞清楚进程的究竟是什么. 维基百科上对于进程的定义如下:

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

一.什么是进程 计算机上有许多可以运行的软件,其中也包括操作系统,这些软件运行时,就产生了一个或多个进程. 二.Linux系统中进程的组织与转换 1>Linux中进程的描述符(即用来描述一个进程的结构体) struct task_struct { ...... volatile long state; // 描述进程的运行状态 void *stack; // 指向内核栈 struct list_head tasks; // 用于加入进程链表 ...... struct mm_struct *mm

第一次作业:Linux2.6源码分析进程模型

1.进程的定义 从系统允许多个程序同时进入CPU那一天开始,我们才有了进程,进程的出现,解决了程序并发执行时对系统资源共享的描述问题,同时顺路解决了程序执行时动态特征的描述问题. 进程:一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位 进程四要素: 1.有一段程序供其执行,该程序不一定是一个进程独享,也可以和其他进程共享. 2.有进程专用的内核空间堆栈. 3.在内核中有一个名为"进程控制块"的task_struct,内核通过结构对进程进行

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

前言:          这是一篇关于linux操作系统的简单介绍.linux本身不能算是操作系统,只是一个内核,基于linux内核的操作系统有很多,比如流行的android,ubuntu,红旗linux等等.Linux以它的高效性和灵活性著称.它能够在PC计算机上实现全部的Unix特性,具有多任务.多用户的能力.Linux是在GNU公共许可权限下免费获得的,是一个符合POSIX标准的操作系统.Linux操作系统软件包不仅包括完整的Linux操作系统,而且还包括了文本编辑器.高级语言编译器等应用

深入源码分析进程模型

1.操作系统是怎么组织进程的 struct task_struct { ...... /* 进程状态 */ volatile long state; /* 指向内核栈 */ void *stack; /* 用于加入进程链表 */ struct list_head tasks; ...... /* 指向该进程的内存区描述符 */ struct mm_struct *mm, *active_mm; ........ /* 进程ID,每个进程(线程)的PID都不同 */ pid_t pid; /* 线

在 Linux 系统上源码安装 GTK+ 2.0

在 Linux 系统上源码安装 GTK+ 2.0==================================================Keywords: GTK+, Install, Linux, SourceAuthor:       whyglinux (whyglinux AT hotmail DOT com)Date:          2007-01-07==================================================目录0. 前言1.

linux系统下源码安装PHP5.6

linux系统下源码安装PHP5.6 从php5.4开始,需要自己下载安装libXpm-dev了,但是由于包的依赖性原因,我就选择了yum方式来进行安装,通过网络yum源直接下载并进行安装了 下载php以及相关的库文件(百度网盘:http::/pan.baidu.com/s/1bnL31c7) gd库以及php功能特性扩展库文件 libgd-2.1.1.tar.gz        gd库文件(使php支持以下功能)     jpegsrc.v7.tar.gz         jpeg库文件(使p

linux调度器源码分析 - 运行(四)

本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 之前的文章已经将调度器的数据结构.初始化.加入进程都进行了分析,这篇文章将主要说明调度器是如何在程序稳定运行的情况下进行进程调度的. 系统定时器 因为我们主要讲解的是调度器,而会涉及到一些系统定时器的知识,这里我们简单讲解一下内核中定时器是如何组织,又是如何通过通过定时器实现了调度器的间隔调度.首先我们先看一下内核定时器的框架 在内核中,会使用strut clock_event_device结构描述硬件