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 - 1));        //让SP堆栈指针与栈底对齐
}    

  可以看到,current 实际上是指向当前执行进程的 task_struct 指针的。

二、子进程的访问方法

  可以使用以下方法访问子进程:

struct task_struct *task;struct list_head *list;list_for_each(list,&current->children){task= list_entry(list,structtask_struct,sibling);
}

  可以看到,这里使用的是链表相关的操作来访问子进程。我们知道, task_struct 是存放在一个双向循环链表 task_list(任务队列)中的,而一个 task_struct 包含了一个具体进程的所有信息,因此,我们只需要找到子进程的 task_struct 即可以访问子进程了,上面代码就是这么做的。那么,具体是如何找到子进程的进程描述符 task_struct的呢?下面对上面的代码进行详细分析:

  list_head: 在 linux/types.h 中定义

structlist_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 *)0)->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 类型。

转载于:https://www.cnblogs.com/tongye/p/9517923.html

Linux内核学习笔记(2)-- 父进程和子进程及它们的访问方法相关推荐

  1. 操作系统进程学习(Linux 内核学习笔记)

    操作系统进程学习(Linux 内核学习笔记) 进程优先级 并非所有进程都具有相同的重要性.除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求.首先进程比较粗糙的划分,进程可 ...

  2. 我的Linux内核学习笔记

    在开始今天的内容之前,其实有一些题外话可以和大家分享一下.自从工作以来,我个人一直都有一个观点.那就是怎么样利用简单的代码来说明开发中的问题,或者是解释软件中的原理,这是一个很高的学问.有些道理看上去 ...

  3. linux内核进程状态,深入理解 Linux 内核学习笔记(一):进程

    进程 进程是任何多通道程序设计的操作系统中的基本概念,进程通常被定义为程序执行时的一个实例,在 Liunx 的源代码中,进程通常被称为 "任务". 进程描述符 进程描述符的作用是为 ...

  4. Linux内核学习之2号进程kthreadd

    Author       : Toney Email         : vip_13031075266@163.com Date          : 2020.12.04 Copyright : ...

  5. [Linux][内核学习笔记]--CFS调度器

    文章目录 1. 进程的状态转换 2. 内核调度器的发展 3. 调度策略 4. 与调度相关的系统调用 5. 优先级 6. CFS调度器的实现 6.1 相关结构体 6.1.1 sched_entity 结 ...

  6. Linux内核学习笔记

    1.vanbreaker的专栏 2.LinuxKernel Exploration 3.DroidPhone的专栏 4.Linux内核研究以及学习文档和ARM学习以及研究的开放文档   [力荐] 5. ...

  7. linux uid 内核,Linux内核学习笔记: uid之ruid,euid,suid

    s的本质是让某个用户在执行s权限的程序时,拥有该程序文件的属主或者属组一样的访问权限.属主或者属组取决于s的位置 一. Linux 文件权限的表示方法 文件权限用 12 个二进制位表示,如果该位的值是 ...

  8. 20135316王剑桥Linux内核学习笔记第三周

    20135316王剑桥 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC 1000029000 三个法宝:存储程序计算机.函数调 ...

  9. linux内核学习笔记【一】临时内核页表 Provisional kernel Page Tables

    最近开始学习linux内核,看了<深入理解linux内核>,开始写点学习收获.内核版本为2.6.11 临时全局目录(provisional page global directory)是在 ...

  10. Linux内核学习笔记——Linux中的用户组和权限管理(UID是什么?)

    目录 一.背景 进程权限 最小权限原则 二.linux系统安全模型 用户 用户组 用户和组的关系 安全上下文 进程的用户ID 函数setreuid和setregid 函数seteuid和setegid ...

最新文章

  1. 【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )
  2. C语言变长数组data[0]【总结】
  3. 1080 MOOC期终成绩 (25 分)
  4. qtdesigner 组件全吗_显示屏种类这么多,你知道怎么分类吗?
  5. fanuc 机床,加工中心通信总结,机床联网监控系统
  6. 如何嫁给改变世界的男人:程序员理想女友大调查
  7. yii2 Rbac使用yii命令一键建表
  8. CCF NOI1000 加密算法
  9. docker打包部署nginx,django应用
  10. (6)Redis的高可用方案
  11. 【系统分析师之路】系统分析师历年真题大汇总
  12. 太原理工软件学院c语言2020,庆祝软件学院成立十周年创意设计之logo投稿入围展示...
  13. 淘宝二面:说下二维码登录的原理?我懵了。。。
  14. oracle插入获取当前时间,Oracle中如何获取系统当前时间
  15. 抖音:技术优化打造最佳创作体验
  16. 打开游戏时提示计算机缺失文件,计算机提示缺少DLL文件
  17. 什么相片可以两张弄成一张_美图秀秀怎么把两张图片合成一张?美图秀秀两张图片融合方法汇总_图形图像_软件教程_脚本之家...
  18. Xcode No certificate for team ‘xxx‘ matching ‘iPhone Developer: xxx (xxx)‘
  19. 基于JAVA自行车在线租赁管理系统2021计算机毕业设计源码+系统+lw文档+部署
  20. 珍惜生命,战胜自己,活出精彩

热门文章

  1. Python基础语法,基本数据类型及相关操作
  2. Django 配置App特定类的富文本编辑器
  3. 广州有这么一个无聊的人
  4. CFS调度主要代码分析二
  5. Linux设备驱动之字符设备(一)
  6. 使用docker环境编译驱动
  7. (转)DPDK收发包处理流程01 -- 网卡初始化
  8. 如何利用systrace分析Android App的死锁问题
  9. pjsip代码分析(1)——modules框架
  10. linux 下 ffmpeg 库怎么才可以调试