Linux内核学习笔记(2)-- 父进程和子进程及它们的访问方法
Linux系统中,进程之间有一个明显的继承关系,所有进程都是 PID 为1的 init 进程的后代。内核在系统启动的最后阶段启动 init 进程。该进程读取系统的初始化脚本(initscript)并执行其他的相关程序,最终完成系统启动的整个过程。
系统中每个进程必有一个父进程,相应的,每个进程也可以由零个或者多个子进程。拥有同一个父进程的所有进程被称为兄弟。进程之间的关系存放在进程描述符 task_struct 中。每个 task_struct 都包含一个指向其父进程 task_struct 的指针 parent,还有一个被称为 children 的子进程链表。
一、父进程的访问方法
对于当前进程,可以使用下面代码访问其父进程,获得其进程描述符:
struct task_struct *my_parent = current -> parent;
其中,current 是一个宏,在 linux/asm-generic/current.h中有定义:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_GENERIC_CURRENT_H
#define __ASM_GENERIC_CURRENT_H #include <linux/thread_info.h> #define get_current() (current_thread_info()->task)
#define current get_current() #endif /* __ASM_GENERIC_CURRENT_H */
而 current_thread_info() 函数在 arch/arm/include/asm/thread_info.h 中有定义:
/*
* how to get the thread information struct from C
*/
static inline struct thread_info *current_thread_info(void) __attribute_const__; static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - )); // 让SP堆栈指针与栈底对齐
}
可以看到,current 实际上是指向当前执行进程的 task_struct 指针的。
二、子进程的访问方法
可以使用以下方法访问子进程:
struct task_struct *task;
struct list_head *list; list_for_each(list,¤t->children){
task = list_entry(list,struct task_struct,sibling);
}
可以看到,这里使用的是链表相关的操作来访问子进程。我们知道, task_struct 是存放在一个双向循环链表 task_list(任务队列)中的,而一个 task_struct 包含了一个具体进程的所有信息,因此,我们只需要找到子进程的 task_struct 即可以访问子进程了,上面代码就是这么做的。那么,具体是如何找到子进程的进程描述符 task_struct的呢?下面对上面的代码进行详细分析:
list_head: 在 linux/types.h 中定义
struct list_head{
struct list_head *next,*prev;
};
显然,list_head 其实就是一个双向链表,而且一般来说,都是双向循环链表。
list_for_each: 在linux/list.h 中定义
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
这是一个宏定义。其中,pos 是指向 list_head 的指针,而 head 是双链表 list_head 中的指针,定义了从哪里开始遍历这个链表。这个宏的作用就是对一个双向循环链表进行遍历。
list_entry: 在 linux/list.h 中定义,也是一个宏定义
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
list_entry 实际上就是 container_of。
container_of : 在 linux/kernel.h 中定义
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *))->member) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
container_of 实现了根据一个结构中的一个成员变量的指针来获取指向整个结构的指针的功能。其中,offsetof 也是一个宏,它的功能是获得成员变量基于其所在结构的地址的偏移量,定义如下:
#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0) -> MEMBER) // 获得成员变量member基于其所在结构的地址的偏移量,该宏在 linux/stddef.h 中有定义
分析一下 offsetof 宏:
1)、((TYPE *) 0) : 将 0 转换成 TYPE 类型的指针。这声明了一个指向 0 的指针,且这个指针是 TYPE 类型的;
2)、((TYPE *) 0) -> MEMBER: 访问结构中的成员MEMBER,一个指向 0 的 TYPE 类型的结构;显然,MEMBER 的地址就是偏移地址;
3)、&((TYPE *) 0) -> MEMBER :取数据成员MEMBER的地址(不是按位与,不要看错了);
4)、((size_t) &((TYPE *) 0) -> MEMBER): 强制类型转换成 size_t 类型。
Linux内核学习笔记(2)-- 父进程和子进程及它们的访问方法的更多相关文章
- Linux内核学习笔记-2.进程管理
原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记二——进程
Linux内核学习笔记二——进程 一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...
- Linux内核学习笔记-1.简介和入门
原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- 20135316王剑桥Linux内核学习笔记
王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...
- Linux内核学习笔记(1)-- 进程管理概述
一.进程与线程 进程是处于执行期的程序,但是并不仅仅局限于一段可执行程序代码.通常,进程还要包含其他资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个 ...
- Linux内核学习笔记(3)-- 进程的创建和终结
一. 进程创建: Unix 下的进程创建很特别,与许多其他操作系统不同,它分两步操作来创建和执行进程: fork() 和 exec() .首先,fork() 通过拷贝当前进程创建一个子进程:然后,ex ...
- Linux内核学习之2号进程kthreadd
Author : Toney Email : vip_13031075266@163.com Date : 2020.12.04 Copyright : ...
- 深入理解Linux内核 学习笔记(3)
第三章 进程 可以看到很多熟悉的结构体 进程状态: 可运行状态(TASK_ RUNNING) 进程要么在CPU上执行,要么准备执行. 可巾断的等待状态(TASK_ INTERRUPTIBLE) 进程被 ...
- 深入理解Linux内核 学习笔记(1)
1.用户和用户组 每个用户是一个或多个用户组的一名成员,组由唯一的用户组标识符(user group ID)标识.每个文件的相关权限也恰好与一个组相对应. root为超级用户, 2.模块 为了达到微内 ...
随机推荐
- 深入理解JVM与GC回收
JVM内存模型 java虚拟机在执行java程序的过程中会把它所管理的内存划分为不同的若干个不同的的数据区域,这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机的进程的启动而存在,有些区 ...
- ABP在领域事件中异步调用方法抛异常
在领域事件中调用UserRegistrationManager.RegisterAsync抛异常 Call UserRegistrationManager.RegisterAsync() throw ...
- --oracle删除数据库表(无主键)中重复的记录
--oracle删除数据库表(无主键)中重复的记录 1, CREATE TABLE newtable as SELECT distinct * FROM T_SYSTEM_MENU_PRIV; 2, ...
- MySQL索引优化经验总结
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引 ...
- Java监听器原理及实例
一.监听器原理 监听器是基于事件驱动的,用于对操作事件进行监听.处理,是观察者设计模式的应用 监听器三元素: 2.1 事件源:事件发生的源头 2.2 事件:对事件进行抽象.封装 2.3 监听器:用于监 ...
- 前端基础-jQuery的内容之选择器
阅读目录 ID选择器 类选择器 元素选择器 通配符选择器 层级选择器 基本筛选器 内容筛选器 可见性筛选器 属性筛选器 子元素筛选器 表单元素筛选器 表单对象筛选器 this和$(this) 一.jQ ...
- 利用node中的内置模块fs实现对简单文件的读取 拷贝 创建等功能
1.文件的读取 我们想要根据如下一种目录生成一种json数据 代码如下 //此函苏是对目录进行读取的 //我们想要生成的是一个根据目录所创建的json数据 const fs = require(&qu ...
- LIS(单调队列优化 C++ 版)(施工ing)
#include <iostream> using namespace std; #include <cstdio> ; ,x,stack[MaxN]; int main(){ ...
- 自己用原生JS写的轮播图,支持移动端触摸滑动,分页器圆点可以支持mouseover鼠标移入和click点击,高手看了勿喷哈
自己用原生JavaScript写的轮播图,分页器圆点按钮可支持click点击,也可支持mouseover鼠标悬浮触发,同时支持移动端触摸滑动,有兴趣的友友可以试试哈,菜鸟一枚,高手看了勿喷,请多多指正 ...
- 20155239 《Java程序设计》实验三(敏捷开发与XP实践)实验报告
实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 学会使用git 学会代码的重构 实现团队合作 团队分工 20155239:按照老师的实验三教程,逐步实验,编写代码,并用git上传,下载团 ...