openEuler 笔记:进程1:程序的加载运行、进程的描述(PCB、进程状态)

本系列学习笔记基本上是博主的《 openEuler 操作系统》读书笔记,中间插入一些自己查的资料以及翻到的感觉有用的源代码

默认架构为 ARM

程序及其加载执行

类 UNIX 的二进制程序一般为 ELF 格式,一个【逻辑意义上作为整体的程序】会被按照内容类型划分为数个 Segment 进行存储。主要的 Segment 有 :.text ,存机器指令序列;.data 存可变的全局变量及静态局部变量;.rodata 存只读数据、常量;.bss 存未初始化的全局变量。

加载,是操作系统将 ELF 读入内存的过程。首先检查 ELF 头,确定是否可以运行。然后读端头表,得到各个段的信息,为需要装入内存的段分配空间,然后把这些段加载到内存中。

执行。程序入口地址存在 ELF 头中,OS 读到该地址后到 .text 找到入口,将入口地址赋给 PC ,程序获得 CPU 控制权。

运行过程中,PC 保存即将执行的指令地址,LR(链接寄存器)保存函数调用返回后的下一条指令地址。

每个运行中的函数都拥有一个栈帧,其为函数的每次调用构建独立的上下文。当函数调用新的函数时,新的函数会被分配新的栈帧。函数运行结束后栈帧会被弹出,系统从下面的栈帧(即发起对刚刚结束的函数调用的函数的栈帧)中取出之前保存的 FP、LR 值,继续运行


进程的描述
操作系统使用 PCB (Process Control Block,进程控制块)对进程进行描述,操作系统通过 PCB 感知进程。
PCB
PCB 定义在 include/linux/sched.h 的 struct task_struct,是一个六百二十多行的结构体。
启动一个程序时,操作系统先创建 PCB ,然后根据其中的信息对进程进行管理和控制,程序运行后系统释放 PCB 。其中的主要信息包含描述信息、控制信息、 CPU 上下文、资源管理信息
描述信息

进程标识符,OS 用它来标记每个进程;

用户标识号,区分某个进程属于哪个用户

    kuid_t          loginuid;
    unsigned int        sessionid;

家族关系,表明该进程与其父进程、祖先进程、子进程、兄弟进程等的关系

    /*
     * Pointers to the (original) parent process, youngest child, younger sibling,
     * older sibling, respectively.  (p->father can be replaced with
     * p->real_parent->pid)
     */
  
    /* Real parent process: */
    struct task_struct __rcu    *real_parent;
  
    /* Recipient of SIGCHLD, wait4() reports: */
    struct task_struct __rcu    *parent;
  
    /*
     * Children/sibling form the list of natural children:
     */
    struct list_head        children;
    struct list_head        sibling;
    struct task_struct      *group_leader;

real_parent 是创建该进程的进程,而 parent 是响应信号相关的父进程——比如 SIGCHLD 就会被发送给 parent。这么设计是因为:有些情况下真父进程可能先终止,这样如 init 这样的其他进程就会成为新的父进程,但不会改变真父进程的值。

控制信息

进程状态(就绪、阻塞、运行、终止)

    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
  
    /* 相关宏定义如下 */
  
    /* Used in tsk->state: */
    #define TASK_RUNNING        0x0000
    #define TASK_INTERRUPTIBLE      0x0001
    #define TASK_UNINTERRUPTIBLE    0x0002
    #define __TASK_STOPPED      0x0004
    #define __TASK_TRACED       0x0008
    #define TASK_PARKED         0x0040
    #define TASK_DEAD           0x0080
    #define TASK_WAKEKILL       0x0100
    #define TASK_WAKING         0x0200
    #define TASK_NOLOAD         0x0400
    #define TASK_NEW            0x0800
    #define TASK_STATE_MAX      0x1000

进程优先级

    int             prio;
    int             static_prio;
    int             normal_prio;
    unsigned int        rt_priority;

静态优先级:进程启动时指定,值越小越高。一般不用,但可用系统调用 nice() 修改;
动态优先级:可以因调度策略的改变而临时变动;
实时:有限程度仅与实时优先级有关,值越小越高。实时进程调度总优于普通进程

记账信息:记录进程占有、利用资源的情况,调度以这些信息为依据进行(如剥夺等),如时间方面、上下文切换方面的:

        u64             utime;
        u64             stime;
    #ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
        u64             utimescaled;
        u64             stimescaled;
    #endif
        u64             gtime;
        struct prev_cputime     prev_cputime;
    #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
        struct vtime            vtime;
    #endif
  
    #ifdef CONFIG_NO_HZ_FULL
        atomic_t            tick_dep_mask;
    #endif
        /* Context switch counts: */
        unsigned long           nvcsw;
        unsigned long           nivcsw;
  
        /* Monotonic time in nsecs: */
        u64             start_time;
  
        /* Boot based time in nsecs: */
        u64             real_start_time;

CPU 上下文
CPU 上下文指某时刻 CPU 各寄存器中的值,用于进程切换时保存状态。其保存于 task_struct->thread_struct->cpu_context
从下面的代码中可以看到,cpu_context 就是各个寄存器中的值的集合

/* arch/arm64/include/asm/processor.h */
struct cpu_context {
    unsigned long x19;
    unsigned long x20;
    unsigned long x21;
    unsigned long x22;
    unsigned long x23;
    unsigned long x24;
    unsigned long x25;
    unsigned long x26;
    unsigned long x27;
    unsigned long x28;
    unsigned long fp;
    unsigned long sp;
    unsigned long pc;
};

struct thread_struct {
    struct cpu_context  cpu_context;    /* cpu context */
    /* 省略其他变量,thread_struct 结构体中包含所有与 CPU 相关的状态信息 */
};

资源管理信息
这部分信息在 PCB 中占比最大,包含存储器、文件系统、使用 IO 设备的信息等,主要与内存和文件相关。

    void *stack;    // 指向进程内核栈,内核栈是进程在内核态用的栈,在内核空间

    // 进程的用户空间描述符
    struct mm_struct        *mm;
    struct mm_struct        *active_mm;

    /* Filesystem information: */
    struct fs_struct        *fs;    // 与进程相关的文件系统

    /* Open file information: */
    struct files_struct     *files; // 进程正打开的文件列表

    // 内存描述符,定义在 include/linux/mm_types.h
    struct mm_struct {
        spinlock_t arg_lock; /* protect the below fields,自旋锁 */
        // 描述内存中各个段的起始位置,包括栈、映射段、堆、BSS段、数据段、代码段
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long start_brk, brk, start_stack;
        unsigned long arg_start, arg_end, env_start, env_end;
        //......
    };

    // 进程关联的文件系统信息,include/linux/fs_struct.h
    struct fs_struct {
        int users;              // 该结构的引用用户数
        spinlock_t lock;
        seqcount_t seq;
        int umask;
        int in_exec;
        struct path root, pwd;  // 根与当前目录
    } __randomize_layout;

    /* include/linux/fdtable.h
     * Open file table structure
     */
    struct files_struct {
      /*
       * read mostly part
       */
        atomic_t count;             // 引用计数
        struct fdtable __rcu *fdt;  // 默认指向 fdt,可用于动态申请内存
        struct fdtable fdtab;       // 为 fdt 提供初始值
        // fdt、fdtable 是管理文件描述符用的
        // ...
    };

    // path. include/linux/path
    struct path {
        struct vfsmount *mnt;
        struct dentry *dentry;
    } __randomize_layout;

    struct fdtable {
        unsigned int max_fds;
        struct file __rcu **fd;      /* current fd array */
        unsigned long *close_on_exec;
        unsigned long *open_fds;
        unsigned long *full_fds_bits;
        struct rcu_head rcu;
    };

进程的状态
进程当前状态由 PCB 中的状态值描述。这里的状态就是运行、就绪、阻塞、终止(僵尸、死亡)

    /* Used in tsk->state: */
    #define TASK_RUNNING        0x0000
    #define TASK_INTERRUPTIBLE      0x0001
    #define TASK_UNINTERRUPTIBLE    0x0002
    #define __TASK_STOPPED      0x0004
    #define __TASK_TRACED       0x0008
    /* Used in tsk->exit_state: */
    #define EXIT_DEAD           0x0010
    #define EXIT_ZOMBIE         0x0020
    #define EXIT_TRACE          (EXIT_ZOMBIE | EXIT_DEAD)
    /* Used in tsk->state again: */
    #define TASK_PARKED         0x0040
    #define TASK_DEAD           0x0080
    #define TASK_WAKEKILL       0x0100
    #define TASK_WAKING         0x0200
    #define TASK_NOLOAD         0x0400
    #define TASK_NEW            0x0800
    #define TASK_STATE_MAX      0x1000

就绪:进程位于运行队列中,已获得 CPU 外的所有资源,等待 OS 选中占用 CPU
运行:当前进程主动放弃或被抢占,则转为就绪;当前进程等待资源或事件时,转为阻塞;运行结束,进入终止状态(僵尸/等待)
阻塞:通常是等待外部事件(如 I/O ),需要等来了才就绪。但可被系统调用、信号等唤醒(阻塞分轻度中度深度,不同的程度需要的条件不同)
终止:

僵尸:父进程未回收进程及其占用的资源(包括 PCB )。若父进程先结束,init 会成为子进程的 parent ,待结束后回收资源
死亡:结束后由父进程回收资源

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容