Linux源码-进程描述符

news2024/12/29 10:32:22

Linux操作系统引入了PCB(Process Control Block,进程控制块)结构。PCB是Linux操作系统识别进程的通道。

创建进程时,首先会创建PCB,根据PCB中的信息对进程实施有效管理。当进程终止后,Linux操作系统会释放对应的PCB资源。

PCB的数据结构是struct task_struct。包含四个方面,描述信息、控制信息、CPU上下文和资源管理。

task_struct位于源码<include/linux/sched.h>

首行的代码注释如下,sched.h用于定义task_struct结构体并提供主要的调度API,比如schedule(), wakeup等

/*

 * Define 'struct task_struct' and provide the main scheduler

 * APIs (schedule(), wakeup variants, etc.)

 */

task_struct总计有约700行代码。

1 描述信息

1.1 进程描述符

每个进程都有唯一的进程标识符pid。是一个32位正整型数。即单个系统内pid的上限为2的31次方*(2147483648),约21亿个PID

struct task_struct{

    ...(796行)

    pid_t               pid;  //全局进程号

    pid_t               tgid; //全局线程组标识符

    ...

}

1.2 用户标识符

每个进程都属于系统中的某一个用户,因此在数据结构体中会包含用户uid信息,变量为kuid_t

struct task_struct{

    ...(940行)

    kuid_t              loginuid;

    unsigned int            sessionid;

    ...

}

kuid_t在<include/linux/uidgid.h>中有定义,为val变量,是一个无符号整数,代表用户标识号。

typedef struct {

    uid_t val;

} kuid_t;

1.3 家族关系

进程并不会独立存在,互相之间存在依赖性,会形成依赖关系,主要为父子关系。除了0号进程之外,其他进程都有父进程。

父进程的父进程叫做祖先进程(隔代),同一个父进程中的多个子进程之间构成兄弟关系(同代)。

Linux系统启动时,0号进程进行内核初始化工作,并创建出1号进程。

1号进程完成用户空间初始化后成为init进程,为后续该系统内创建进程的共同祖先进程。

如下代码中real_parent和parent在正常情况下都指向父进程pid,但是在特殊情况下,比如因为程序缺陷,父进程在子进程结束前自行退出了,子进程就变成了孤儿进程,也就是僵尸进程,此时,该子进程就会被挂到init 1号进程下。这是real_parent不会变化,但是parent变成了1。

sibling用于指向兄弟进程。

children用于指向子进程。

struct task_struct{

    ...(809行)

    /*

     * 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;  //通过进程描述符,指向线程组的组长

2控制信息

PCB中进程控制信息主要包括进程的状态信息、优先级信息和记账信息。

2.1 状态信息

进程的状态有就绪、运行、阻塞、终止等状态,其中在终止状态中又分为了僵尸和死亡两种状态。

内核代码中对进程状态有如下几种类型定义:

<include/linux/sched.h>

....(82行)

/* Used in tsk->state: */

#define TASK_RUNNING            0x0000 //运行状态,int 0

#define TASK_INTERRUPTIBLE      0x0001 //阻塞状态(可中断) int 1

#define TASK_UNINTERRUPTIBLE        0x0002 //阻塞状态(不可中断) int 2

#define __TASK_STOPPED          0x0004 //终止状态 int 4

#define __TASK_TRACED           0x0008 // 跟踪状态 int 8

/* Used in tsk->exit_state: */

#define EXIT_DEAD           0x0010 //终止状态中的死亡状态,属于exit_state

#define EXIT_ZOMBIE         0x0020//终止状态中的僵尸状态,属于exit_state

#define EXIT_TRACE          (EXIT_ZOMBIE | EXIT_DEAD)

在操作系统上可以看到的进程的状态描述:

static const char * const task_state_array[] = {

    /* states in TASK_REPORT: */

    "R (running)",      /* 0x00 */

    "S (sleeping)",     /* 0x01 */

    "D (disk sleep)",   /* 0x02 */

    "T (stopped)",      /* 0x04 */

    "t (tracing stop)", /* 0x08 */

    "X (dead)",     /* 0x10 */

    "Z (zombie)",       /* 0x20 */

    "P (parked)",       /* 0x40 */

    /* states beyond TASK_REPORT: */

    "I (idle)",     /* 0x80 */

};

定义一个宏TASK_REPORT, 将所有进程的状态进行合并。

/* get_task_state(): */

#define TASK_REPORT         (TASK_RUNNING | TASK_INTERRUPTIBLE | \

                     TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \

                     __TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \

                     TASK_PARKED)

task_state_index为内联函数,用于计算给定任务结构体task_struct的状态索引,明确一个进程的具体状态。

根据给定任务的运行状态 (tsk->state) 和退出状态 (tsk->exit_state),计算出一个状态索引。通过按位操作和掩码 (TASK_REPORT),函数能够准确地表示任务的当前状态,并返回一个索引值,用于进一步的处理或决策。

static inline unsigned int task_state_index(struct task_struct *tsk)

{

    unsigned int tsk_state = READ_ONCE(tsk->state);

    unsigned int state = (tsk_state | tsk->exit_state) & TASK_REPORT;

    BUILD_BUG_ON_NOT_POWER_OF_2(TASK_REPORT_MAX);

    if (tsk_state == TASK_IDLE)

        state = TASK_REPORT_IDLE;

    return fls(state);

}

2.2 进程优先级信息

进程优先级用于确定进程被调度到CPU上执行的优先程度如内核代码定义分为动态优先级、静态优先级、普通优先级和试试优先级

  struct task_struct {

......(732行)

    int             prio;         //动态优先级

    int             static_prio;  //静态优先级

    int             normal_prio;  //普通优先级,取决于静态优先级和调度策略

    unsigned int            rt_priority; //realtime,实时优先级

静态优先级:数值越小,优先级越高,可用nice调整

动态优先级和普通优先级默认等于静态优先级,但动态优先级会被临时修改。同样是数值越小,优先级越高。

进程可分为实时进程和普通进程,实时优先级作用于实时进程,数值越大,优先级越高。

实时进程的调度优先于普通进程。

3 CPU上下文

CPU上下文是指进程执行到某时刻时CPU各寄存器中的数值,这些数值就代表着当前进程活动的状态信息。

什么是上下文切换?

在单CPU多进程并发的场景下,单位时间内一个CPU同一时刻只会执行一个进程的代码,比如在1秒中内,CPU的时间周期被切割成100个分片,同时有10个进程需要执行,且每个进程之间的优先级都是相同的情况下,每个进程被分配到的时间就在10个时间分片,同时这10个时间分片不一定是连续的。因此在CPU进行两个进程处理切换期间,需要保留上一个进程在CPU内寄存器的数值,同时要加载下一个进程在上一个时间片内执行的寄存器数值。这个过程叫做上下文切换。

进程切换时,CPU上下文保存调用为task_struct --> thread_struct --> cpu_context

结构体 thread_struct,用于存储特定于进程的状态信息,特别是在处理器上下文、浮点寄存器状态和调试信息方面的详细数据。以下是结构体的主要成员及其作用的解释:

<arch/arm64/include/asm/processor.h>

...

struct thread_struct {

    struct cpu_context  cpu_context;    /* cpu context */

...

    unsigned long       fault_address;  /* fault info */

    unsigned long       fault_code; /* 寄存器ESR_EL1 value */

    struct debug_info   debug;      /* debugging */

    ...

    }

对应引用cpu_context结构体,主要代码如下,包含了通用寄存器x19--x28, 栈帧寄存器FP,堆栈指针寄存器SP和程序计数器PC

<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;

};

4 资源管理信息

PCB中包含资源管理信息,包含存储器、文件系统等等,多个代码调用关系如下

在sched.h中定义了对应的内存、文件、打开文件的结构体。

    <include/linux/sched.h>

    ...

    void *stack; //指向进程的内核栈

    ...

    struct mm_struct        *mm;

    struct mm_struct        *active_mm; //进程的用户控件描述符

    struct fs_struct        *fs;  //进程相关联的文件系统信息

    struct files_struct     *files;  //指向打开的文件列表

4.1 mm_types.h

mm_struct结构体记录了进程的内存布局

<include/linux/mm_types.h>

struct mm_struct {  //内存描述符

    struct {

        struct vm_area_struct *mmap;        /* list of VMAs */

        struct rb_root mm_rb;

        ...

        spinlock_t arg_lock; //自旋锁,保护如下字段

        //内存空间中各段起始、结束地址

         //包括堆、栈 、映射段、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;

        ...

4.2 fs_struct.h

fs_struct结构体记录与进程相关联的文件系统信息,包括当前目录和根目录。

<include/linux/fs_struct.h>

struct fs_struct {

    int users;

    spinlock_t lock;  //自旋锁

    seqcount_spinlock_t seq;

    int umask;

    int in_exec;

    //根目录与当前目录

    struct path root, pwd;

} __randomize_layout;

通过t内联函数get_fs_roo获取根目录信息

通过内联函数get_fs_pwd获取当前目录信息

//通过get_fs_root内联函数获取根目录信息

static inline void get_fs_root(struct fs_struct *fs, struct path *root)

{

    spin_lock(&fs->lock);

    *root = fs->root;

    path_get(root);

    spin_unlock(&fs->lock);

}

//通过内联函数get_fs_pwd获取当前目录信息

static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd)

{

    spin_lock(&fs->lock);

    *pwd = fs->pwd;

    path_get(pwd);

    spin_unlock(&fs->lock);

}

4.3 fdtable.h

files_struct结构是进程正打开的所有文件的列表(包含输入/输出设备也是以文件形式存在的)

<include/linux/fdtable.h>

struct files_struct {

    atomic_t count;   //引用计数器

    bool resize_in_progress;

    wait_queue_head_t resize_wait;

    struct fdtable __rcu *fdt; //默认指向fdtab,用于动态申请内存

    struct fdtable fdtab;  //为fdt提供初始值

    spinlock_t file_lock ____cacheline_aligned_in_smp;

    unsigned int next_fd;

    unsigned long close_on_exec_init[1];

    unsigned long open_fds_init[1];

    unsigned long full_fds_bits_init[1];

    struct file __rcu * fd_array[NR_OPEN_DEFAULT];

    struct files_cgroup *files_cgroup;

};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1877522.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IP定位技术中的网络拓扑分析

IP地址物理位置的高精度定位对于众多应用至关重要&#xff0c;从网络安全监控到个性化内容推荐&#xff0c;从地理定位服务、流量优化策略以及广告分布推广等。IP定位技术作为实现这一目标的关键手段&#xff0c;不断演进和创新&#xff0c;今天就IP定位技术中的网络拓扑分析来…

【面试系列】数据科学家 高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

HTML5+JavaScript单词游戏

HTML5 JavaScript单词游戏 数据字典格式&#xff1a;每行一个 单词 &#xff0c;单词和解释用空格分隔&#xff0c;如 a art.一(个)&#xff1b;每一(个) ability n.能力&#xff1b;能耐&#xff0c;本领 able a.有能力的&#xff1b;出色的 baby n.婴儿&#xff1b;孩子…

深入浅出:npm 常用命令详解与实践

在现代的前端开发流程中&#xff0c;npm&#xff08;Node Package Manager&#xff09;已经成为了不可或缺的一部分。它不仅帮助我们有效地管理项目中的依赖包&#xff0c;还提供了一系列强大的命令来优化开发体验。在这篇博客中&#xff0c;我们将深入探讨 npm 的常用命令&…

Navicat上新啦

前言 Navicat&#xff0c;在数据库界&#xff0c;几乎是一个神奇的存在&#xff0c;似乎统治了数据库开发工具的“一片天”。且看下图&#xff1a; 红的蓝的绿的橙的…&#xff0c;可以说&#xff0c;留给它的color不多了。 那么商业BI到服务监控、从云托管到云协作&#xff…

Qt事件传递顺序是怎样的?

1、事件传递顺序规则 在Qt中&#xff0c;事件传递的顺序事件首先传递到目标对象的事件过滤器&#xff0c;然后传递到事件处理函数&#xff0c;最后传递到父对象的事件过滤器和事件处理函数。 为了更好地理解这一过程&#xff0c;下面将通过一个示例来展示事件在父窗口和子窗口…

盘点全球Top10大云计算平台最热门技能证书

小李哥花了一年半时间终于考下全球10大云的77张认证&#xff0c;今天盘点下各个云的热门证书&#xff0c;希望能帮到非CS专业转IT和刚刚入行云计算的小伙伴。 排名取自23年Yahoo云计算市场份额排名报告&#xff0c;我会从云平台、证书价格、证书热门程度做推荐。 1️⃣亚马逊云…

微机原理 复习

第一章导论 1.3 冯诺依曼体系结构 &#xff08;1&#xff09;以二进制形式表示指令和数据 &#xff08;2&#xff09;程序和数据事先放在存储器中&#xff08;预存储&#xff09; &#xff08;3&#xff09;由运算器、控制器、输入设备和输出设备五大部件组成 字长、主频…

《昇思25天学习打卡营第6天|onereal》

Vision Transformer&#xff08;ViT&#xff09;简介 近些年&#xff0c;随着基于自注意&#xff08;Self-Attention&#xff09;结构的模型的发展&#xff0c;特别是Transformer模型的提出&#xff0c;极大地促进了自然语言处理模型的发展。由于Transformers的计算效率和可扩…

深度解析:机器学习如何助力GPT-5实现语言理解的飞跃

文章目录 文章前言机器学习在GPT-5中的具体应用模型训练与优化机器翻译与跨语言交流&#xff1a;情感分析与问答系统&#xff1a;集成机器学习功能&#xff1a;文本生成语言理解任务适应 机器学习对GPT-5性能的影响存在的挑战及解决方案技术细节与示例 文章前言 GPT-5是OpenAI公…

昇思25天学习打卡营第11天|SSD目标检测

1. 学习内容复盘 模型简介 SSD&#xff0c;全称Single Shot MultiBox Detector&#xff0c;是Wei Liu在ECCV 2016上提出的一种目标检测算法。使用Nvidia Titan X在VOC 2007测试集上&#xff0c;SSD对于输入尺寸300x300的网络&#xff0c;达到74.3%mAP(mean Average Precision)…

任意密码重置漏洞

文章目录 1. 任意密码重置漏洞原理2. 任意密码重置漏洞产生原因3. 任意密码重置漏洞场景3.1 验证码爆破3.2 验证凭证回传3.3 验证凭证未绑是用户3.4 跳过验证步骤3.5 凭证可预测3.6 同时向多个账户发送凭证 4. 任意密码重置经典案例4.1 中国人寿某重要系统任意账户密码重置4.2 …

Go Error 处理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

ModuleNotFoundError: No module named ‘_sysconfigdata_x86_64_conda_linux_gnu‘

ModuleNotFoundError: No module named _sysconfigdata_x86_64_conda_linux_gnu 1.软件环境⚙️2.问题描述&#x1f50d;3.解决方法&#x1f421;4.结果预览&#x1f914; 1.软件环境⚙️ Ubuntu 20.04 Python 3.7.0 2.问题描述&#x1f50d; 今天发现更新conda之后&#xff0…

【数据库】Oracle安装报错(win10安装oracle提示环境不满足最低要求)

目录 一、问题场景&#xff1a; 二、问题描述 三、原因分析&#xff1a; 四、解决方案&#xff1a; 一、问题场景&#xff1a; 安装Oracle数据库 二、问题描述 安装之前提示&#xff08; [INS-13001]环境不满足最低要求。 是否确实要继续? &#xff09; 如图所示&…

1-爬虫基础知识(6节课学会爬虫)

1-爬虫基础知识&#xff08;6节课学会爬虫&#xff09; 1.什么是爬虫2.爬取的数据去哪了3.需要的软件和环境4.浏览器的请求&#xff08;1&#xff09;Url&#xff08;2&#xff09;浏览器请求url地址&#xff08;3&#xff09;url地址对应的响应 5.认识HTTP/HTTPS5.1 http协议之…

43.三倍游戏

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/390 题目描述 三倍游戏是一种单人游戏。玩…

2.优化算法之滑动窗口1

1.长度最小的子数组 . - 力扣&#xff08;LeetCode&#xff09; &#xff08;1&#xff09;题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;…

全网唯一免费无水印AI视频工具!

最近Morph Studio开始免费公测&#xff01;支持高清画质&#xff0c;可以上传语音&#xff0c;同步口型&#xff0c;最重要的是生成的视频没有水印&#xff01; Morph Studio国内就可以访问&#xff0c;可以使用国内邮箱注册&#xff08;我用的163邮箱&#xff09;&#xff0c;…

Java代码高风险弱点与修复之——弱密码哈希漏洞-Very weak password hashing (WEAK_PASSWORD_HASH)

弱密码哈希漏洞 弱密码哈希漏洞指的是在密码存储和验证过程中,由于使用了不安全的哈希算法或哈希函数的错误使用,导致攻击者能够更容易地破解或绕过密码验证机制。这种漏洞使得存储在系统或应用中的用户密码容易受到威胁,增加了账户被非法访问和数据泄露的风险。 常见的弱…