《深入Linux内核架构》第2章 进程管理和调度 (2)

目录

2.4 进程管理相关的系统调用

2.4.1 进程复制

2.4.2 内核线程

2.4.3 启动新程序

2.4.4 退出进程


本专栏文章将有70篇左右,欢迎+关注,订阅后续文章。

2.4 进程管理相关的系统调用

2.4.1 进程复制

1. _do_fork函数

        fork vfork clone都最终调用_do_fork

                clone:通过CLONE_XX标志精确控制父子进程共享哪些资源。

                vfork:由于fork使用了COW技术,vfork优势不再,使用少。

COW:copy-on-write,写时复制。

        

fork子进程时,使用COW机制,原理:

        1. 不复制父进程的地址空间。而是将父进程的地址空间标记为只读,并与子进程共享相同的物理内存页。

        2. 当父进程或子进程有写内存时,发生缺页异常。

       3. 缺页异常处理中检查该页是否可以写。

                若可以,写数据到内存页,再修改子进程页表项。

                若不可以,段错误。

COW页:减少不必要的拷贝,提高性能。

2. 执行系统调用

long do_fork(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr)stack_start:用户栈parent_tidptr,child_tidptr:用于返回线程ID给用户空间,因为pthread_create函数需要tid值

系统调用在用户空间和内核空间传递参数的方法因体系结构而异。

方法有:

        寄存器传递:速度快,但寄存器数量有限。

        栈传递:可传递内容多。

3. do_fork的实现

copy_process:见下节

wake_up_new_task:将该新进程加入调度器队列。

4. copy_process 复制进程

dup_task_struct函数:

        复制父进程的task_struct和thread_info结构体。

task_struct:存储体系架构无关的通用信息。

thread_info:存储线程的重要信息,不同体系架构定义不一样。从task_struct中独立出来。

        通常包含:内核栈栈顶,指向当前线程的task_struct等。

        task_struct:存储体系架构无关的通用信息。

创建新进程时分配了新的内核栈,即task_struct->stack

复制后,父子进程两个的task_struct结构体只有一个成员不同:

        新进程分配了一个自己的内核栈,即task_struct->stack

union thread_union {struct thread_info thread_info; 定义在不同体系中unsigned long stack[THREAD_SIZE/sizeof(long)];
};

每个进程有一个内核栈,大小为8K。如下:

THREAD_SIZE=8K,即上图内核栈最大为8K,恶意操作内核栈可能覆盖thread_info

struct thread_info {            //以arch/arm为例unsigned long            flags;            int                      preempt_count;    抢占计数,表示当前线程是否可被抢占。struct task_struct        *task;            代表当前线程__u32                     cpu;                当前线程所在CPU    struct cpu_context_save   cpu_context;    保存着CPU寄存器(如PC,SP等)
};其中thread_info中flag有:TIF_SIGPENDING 当前进程是否有待决信号TIF_NEED_RESCHED 当前进程想让出CPU,调度器选择其他进程执行。TIF = Thread Info Flag

如何访问指定线程的thread_info?

        (struct thread_info *) (task)->stack

如何根据当前线程thread_info找到当前线程的task_struct?

        task_struct *current = current_thread_info()->task

如何访问当前线程的thread_info?

struct thread_info *current_thread_info(void)        ARM为例
{register unsigned long sp asm ("sp");        //sp寄存器:保存了当前线程的内核栈顶部return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

  

如何根据thread_info找到对应task_struct?

        task_struct *current = current_thread_info()->task

task_struct->stack和CPU sp寄存器,如上图,两者不指向同一地址:

        task_struct->stack:

                指向创建该线程时分配8K内核栈的起始地址。也就是thread_info处

        CPU sp寄存器:

                当前CPU运行线程的内核栈栈顶。

当前进程正在运行时:

        通过ARM sp寄存器值,得到当前线程的thread_info,再得到current的task_struct。

进程切换到一个新进程时:

        通过task_strcut -> stack,得到该线程的thread_info,再通过thread_info得到cpu_context,即可得到该进程上次执行时的寄存器信息,如pc,sp,r0-r12等。

进程切换时,关于进程的task_struct的stack成员,sp寄存器,变化过程?

1. 保存当前进程的上下文:

        保存当前进程上下文到内核栈中:包括CPU的通用寄存器、程序计数器PC、栈指SP等。

2. 切换新进程的:

     切换到新进程的task_struct结构体,再通过task_struct->stack得到thread_info。

3. 恢复新进程上下文

        从thread_info中cpu_context得到该进程上次执行时的上下文信息。如pc,sp,r0-r12等。从而恢复新进程上下文值。此时可正确得到新进程的内核栈栈顶sp。

struct pt_regs 和 thread_info中struct cpu_context_save 是用于保存 CPU 寄存器状态

区别:

        struct pt_regs:用于处理异常或系统调用返回时将其恢复到原始状态,还可传参。

        struct cpu_context_save:用于进程切换时主动保存CPU上下文。

kstack_end(void *addr)函数:

        返回当前线程的内核栈的结束地址。

                这样就可判断某个地址是否在内核栈区间。

继续回到copy_process

sched_fork函数:

        1. 初始化子进程调度参数:优先级和调度策略等。

        2. 复制父进程的调度器相关数据(调度器类别,时间片)。

        3. 将子进程加入调度队列。

copy_process会检测如下标志:

        CLONE_FS 共享父进程的文件系统

        CLONE_NEWXX 不共享的资源

        CLONE_FILES 共享父进程的文件描述符

        CLONE_SIGHAND 共享父进程的信号处理函数

        CLONE_MM COW,只复制页表

struct pt_regs { 如上图,存储在当前线程的内核栈最底部中。

        long uregs[18];

};

struct pt_regs作用:

        从用户态陷入内核态时候,用户态的上下文信息保存在pt_regs数据结构中。还可传递系统调用参数和返回值。

存储的寄存器信息有:

        #define ARM_cpsr uregs[16] 程序状态寄存器

        #define ARM_pc uregs[15]

        #define ARM_lr uregs[14]

        #define ARM_sp uregs[13] 当前线程内核栈的栈顶

        #define ARM_ip uregs[12]

        #define ARM_fp uregs[11]

        #define ARM_r10 uregs[10] //通用寄存器 r0-r10

struct pt_regs这18个寄存器,保存在当前线程的内核栈的底部,如上图。

        即 :struct pt_regs *regs = task_struct->stack + THREAD_START_SP - 1

copy_process还调用copy_thread。

        copy_thread重要内容:

                填充thread_info和pt_regs。

父子进程可共享信号处理函数,但不共享挂起待处理信号。

unsigned long put_user(void __user *dst, const void *src, unsigned long size);

        向用户空间传递单个数据。如char,short,int大小的数据,比copy_to_user快。

copy_to_user优点:可复制任意类型和长度数据。

每个体系的虚拟地址0到4KB的区域,没有任何意义。可重用该地址范围来编码错误码。

如果返回值指向0-4KB地址范围内部,表示该调用失败,其原因由指针值判断。

宏ERR_PTR:将数值常数编码为指针。

使用方法:return ERR_PTR(-EINVAL);

2.4.2 内核线程

内核线程父进程是:init进程

内核线程的任务通常是周期任务,如:

        pdflush:刷新脏页到磁盘。

        kswapd:回写内存页到交换区。

        ksoftirqd:处理软中断。

创建内核线程:

        pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)

        最终也调用_do_fork(CLONE_VM)

创建的内核线程在指定CPU上运行:

        kthread_create_on_cpu()

                -> p->sched_class->set_cpus_allowed(p, new_mask);

kthread_run() = kthread_create() + wake_up_process()

内核线程不需要用户空间,所以内核线程task_struct的mm_struct=NULL。

当内核线程运行,可不置换掉之前进程的用户空间地址,因为内核线程不使用用户空间。所以用active_mm保存用户空间mm_struct,因为内核线程运行后调度的进程通常还是之前那个用户进程,通过active_mm直接恢复,不用修改映射表,TLB中缓存的映射表仍然有效。这叫惰性TLB。

惰性TLB:一种优化策略,延迟或避免不必要TLB的更新,提高性能。

TASK_SIZE:即用户态虚拟地址大小(32位,0-3G)。

        内核线程地址空间大于TASK_SIZE。

2.4.3 启动新程序

execve系统调用

int do_execve(struct filename *filename, const char __user *const __user *__argv, const char __user *const __user *__envp)

会__user定义的指针进行参数检查。

linux_binfmt存储了所有注册的可执行程序的加载函数和执行函数。

struct linux_binprm:保存可执行文件的信息,包括可执行程序的路径,参数和环境变量的信息,vma

struct linux_binfmt {struct list_head lh;         连接所有二进制的执行函数int (*load_binary)(struct linux_binprm *); 加载二进制文件int (*load_shlib)(struct file *); 加载动态库int (*core_dump)(struct coredump_params *cprm); 用于crash时核心转储文件}

Linux文件特殊权限SUID、SGID、Sticky总结:

SUID文件所属主:Set User ID

        当一个可执行文件具有SUID权限时,它执行时临时具有文件所有者的权限,而不是执行者的权限。

        作用:暂时提升用户权限。允许普通用户执行root用户的程序。

        缺点:潜在安全性威胁。谨慎使用。

        使用举例:

                /usr/bin/passwd:允许用户更改自己的密码而无需root权限。

        设置方法:

                增加suid权限:chmod u+s ,或chmod 4755

                移除suid权限:chmod u-s ,或chmod 0755。

SGID文件属组: Set Group ID

        当一个文件或目录设置SGID权限后,任何用户执行该文件或访问该目录时,都以该文件或目录所属的组身份执行,而不是该用户的组权限。

        使用场景:当不同组的用户在一个共享目录下创建新文件,新文件是该目录所属组的权限,而不是创建文件的用户的组权限。可确保所有用户以相同的组权限执行该目录下新文件。

        设置方法:

                增加suid权限:chmod g+s ,或chmod 2755。

                移除sgid权限:chmod g-s ,或chmod 0755。

Sticky权限:

        作用:一般用于目录,只允该目录下的文件的创建者删除自己的创建的文件,不允许其他人删除文件。

二进制文件起始处的magic值可标识该文件类型。

        如:ELF可执行文件:Magic number: 0x7F ELF

                JPEG图像文件:Magic number:0xFFD8FF

search_binary_hander:

        根据文件起始处的magic值来查找对应二进制文件的加载,执行函数。

二进制加载函数: 将文件段映射到虚拟地址空间。

        最终给变量start_code,end_code,start_data,end_data,start_brk brk,start_stack,arg_start,arg_end赋值。

每种二进制格式通过register_binfmt注册:

        如script_format,elf_format,aout_format等

2.4.4 退出进程

exit

各种引用计数减1。减1后若等于0,释放资源。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络 Telnet远程访问交换机和Console终端连接交换机

一、实验要求和内容 1、配置交换机进入特权模式密文密码为“abcd两位班内学号”,远程登陆密码为“123456” 2、验证PC0通过远程登陆到交换机上,看是否可以进去特权模式 二、实验步骤 1、将一台还没配置的新交换机,利用console线连接设备的…

数学建模-最优包衣厚度终点判别法-二(K-Means聚类)

💞💞 前言 hello hello~ ,这里是viperrrrrrr~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#xff…

OpenAI曾转录100万小时视频数据,训练GPT-4

4月7日,纽约时报在官网发布了一篇名为《科技巨头如何挖空心思,为AI收集数据》的技术文章。 纽约时报表示,OpenAI曾在2021年几乎消耗尽了互联网有用的文本数据源。为了缓解训练数据短缺的难题,便开发了知名开源语音识别模型Whispe…

Leetcode 394. 字符串解码

心路历程: 这道题看到括号直接想到栈,五分钟新题直接秒了,一开始以为需要两个栈分别存储数字和非数字,后来发现一个栈就够了,思路如图: 这道题考察的应该是队栈这两种数据结构的转换,因为每次…

C语言比较两个字符串是否相等是很容易的

一、概要 两个字符串char str1[n]和char str2[n] while循环,开始前i置为0,如果两个字符串都没有到末尾,且str1[i]str2[i],则i,循环继续 循环结束之后,如果两个字符串都到了末尾(str1[i]\0 &&…

Java零基础入门-Java反射机制

一、概述 我们都听说过java有个反射机制,通过反射机制我们可以更深入的控制程序的运行过程。例如,在程序进入到运行期间,由用户输入一个类名,然后我们可以动态获取到该类拥有的所有类结构、属性名和方法,甚至还可以任意…

Vue3---基础1(认识,创建)

变化 相对于Vue2,Vue3的变化: 性能的提升 打包大小减少 41% 初次渲染快 55%,更新渲染快133% 内存减少54% 源码的升级 使用 proxy 代替 defineProperty 实现响应式 重写虚拟 DOM 的实现和 Tree-shaking TypeScript Vue3就可以更好的支持TypeSc…

PHP 伪协议:使用 php://input 访问原始 POST 数据

文章目录 参考环境PHP 伪协议概念为什么需要 PHP 伪协议? php://input为什么需要 php://input?更灵活的数据处理减小性能压力 发送 POST 数据HackBarHackBar 插件的获取 $_POST打开 HackBar 插件通过 HackBar 插件发起 POST 请求 基操 enable_post_data_…

Linux——fork复制进程

1)shell: 在计算机科学中,Shell俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(command interpreter,命令解析器)。它类似于DOS下的COMMAND.COM和后来的cmd.exe。它接收用户命令&…

SpringBoot中的Redis的简单使用

在Spring Boot项目中使用Redis作为缓存、会话存储或分布式锁等组件,可以简化开发流程并充分利用Redis的高性能特性。以下是使用Spring Boot整合Redis的详细步骤: 1. 环境准备 确保开发环境中已安装: Java:用于编写和运行Spring…

微服务-6 Gateway网关

一、网关搭建 此时浏览器访问 localhost:10010/user/list 后正常返回数据,说明网关已生效,其原理流程图如下: 二、网关过滤器 作用:处理一切进入网关的请求和微服务响应。 1. 网关过滤器的分类: a. 某个路由的过滤器 …

LeetCode Meditations:合并 K 排序列表

描述 合并K分类列表 状态: 您有一系列 k 链接-列表 lists ,每个链接-列表按升序排序。 合并所有链接-列表为一个排序的链接-列出并返回。 例如: Input: lists [[1, 4, 5], [1, 3, 4], [2, 6]] Output: [1, 1, 2, 3, 4, 4, 5, 6] Explanatio…

地理信息系统(ArcGIS)在水文水资源、水环境中的应用

刘老师(副教授):来自北京重点高校资深专家,长期从事水资源与水环境、流域污染控制与管理、非点源模拟与控制、环境信息系统开发、环境遥感与GIS应用等领域的研究,发表多篇Sci论文、具有资深的技术底蕴和专业背景。 1、…

MapTracker:Tracking with Strided Memory Fusion for Consistent Vector HD Mapping

参考代码:MapTracker 动机与出发点 为了提升帧间检测的稳定性通常会添加时许信息,这个可以BEV特征处做时序融合,也可以是用当前帧query去cross-attn历史帧信息,则更多的时候是将之前帧信息与当前做融合或者cross-attn实现信息传…

SQL注入sqli_labs靶场第三题

?id1and 11 and 11和?id1and 11 and 11进行测试如果11页面显示正常和原页面一样,并且12页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。 根据报错信息判断为单引号带括号注入 联合查询: 猜解列名 ?id1) order by 3-…

SIC知识--(1):来龙去脉

一、碳化硅的起源 1891年,当时爱德华古德里奇艾奇逊在尝试制造人造金刚石的过程中意外发现了这一材料。艾奇逊将黏土(铝硅酸盐)与粉状焦炭(碳)混合后在电炉中加热,预期得到金刚石,却意外获得了一…

代码随想录35期Day08-字符串

344.反转字符串 位运算 func reverseString(s []byte) {l : 0r : len(s) - 1for l < r {s[l] ^ s[r]s[r] ^ s[l]s[l] ^ s[r]lr--} }541. 反转字符串II 没技巧 func reverseStringRange(s []byte, l int, r int) {if r > len(s) {r len(s) - 1}for l < r {s[l] ^…

Mac安装配置ElasticSearch和Kibana 8.13.2

系统环境&#xff1a;Mac M1 (MacOS Sonoma 14.3.1) 一、准备 从Elasticsearch&#xff1a;官方分布式搜索和分析引擎 | Elastic上下载ElasticSearch和Kibana 笔者下载的是 elasticsearch-8.13.2-darwin-aarch64.tar.gz kibana-8.13.2-darwin-aarch64.tar.gz 并放置到个人…

关于ASP.NET Core WebSocket实现集群的思考

前言 提到WebSocket相信大家都听说过&#xff0c;它的初衷是为了解决客户端浏览器与服务端进行双向通信&#xff0c;是在单个TCP连接上进行全双工通讯的协议。在没有WebSocket之前只能通过浏览器到服务端的请求应答模式比如轮询&#xff0c;来实现服务端的变更响应到客户端&…

潍微科技-水务信息管理平台 ChangePwd SQL注入漏洞复现

0x01 产品简介 水务信息管理平台主要帮助水务企业实现水质状态监测、管网运行监控、水厂安全保障、用水实时监控以及排放有效监管,确保居民安全稳定用水、环境有效保护,全面提升水务管理效率。由山东潍微科技股份有限公司研发,近年来,公司全力拓展提升水务、水利信息化业务…