被问到两个问题, 后来想了下如果要讲明白还不太容易,需要对进程的概念,进程管理有清晰的认识:

1. 父进程打开了一个文件,然后通过fork创建一个子进程, 子进程是否共享父进程的文件描述符?

2. 在shell中执行脚本、程序的机制或者流程是什么?

下面就对这两个问题涉及到的Linux进程的基本概念,进程的创建、 线程的实现, 进程的终结等做一下总结:

1. Linux进程基本概念和数据结构

进程-处于执行期的程序和它相关资源的总称。
理解: 进程是程序执行的实时结果, 这个实时结果包括很多资源和状态,比如:
可执行程序代码,数据段,打开的文件,挂起的信号, 内核的内部数据,处理器状态,线程,地址空间等。
Linux操作系统为了便于管理所有这些细节,会在内核中使用task_struct结构体来记录一个进程的各种信息,这个结构体的实例就是进程描述符。

(1)进程地址空间:
为什么会有地址空间这个概念, 因为现在os都采用了虚拟内存技术,在c编程中取得的内存地址都是虚拟地址,真实的物理地址是内核来完成映射的,
这样避免了程序直接操作物理地址引起的混乱。 每个进程都有自己独立的虚拟地址空间, 让进程在分配和管理内存的时候觉得自己是拥有整个内存资源。

进程地址空间分为内核空间和用户空间, 32位CPU的linux上其大小分别是1G和3G。
内核地址空间固定且连续映射, 所有进程共享此区域, 用户无法直接访问内核空间。
用户地址空间如上图所示,分为堆栈区,bss段, 数据段, 代码段(Text segment)用来存放不同的资源

(2)进程描述符 (process descriptor)
进程描述符是task_struct结构体类型, 用来记录进程的所有信息。
每个进程在内核中都有一个进程描述符对应, 内核把进程的列表存放在叫task list的双向循环链表中。

struct task_struct {
volatile long state; /* -1 不可运行, 0 可运行, >0 已停止 */
void *stack; /* 内核栈 */
atomic_t usage;
unsigned int flags; /* 一组标志 */
unsigned int ptrace;
/* ... */ int prio, static_prio, normal_prio; /* 优先级 */
/* ... */ struct list_head tasks; /* 执行的线程(可以有很多) */
struct plist_node pushable_tasks; struct mm_struct *mm, *active_mm; /* 内存页(进程地址空间) */ /* 进行状态 */
int exit_state;
int exit_code, exit_signal;
int pdeath_signal; /* 当父进程死亡时要发送的信号 */
/* ... */
pid_t pid; /* 进程号 */
pid_t tgid; /* ... */
struct task_struct *real_parent; /* 实际父进程real parent process */
struct task_struct *parent; /* SIGCHLD的接受者,由wait4()报告 */
struct list_head children; /* 子进程列表 */
struct list_head sibling; /* 兄弟进程列表 */
struct task_struct *group_leader; /* 线程组的leader */
/* ... */ char comm[TASK_COMM_LEN]; /* 可执行程序的名称(不包含路径) */
/* 文件系统信息 */
int link_count, total_link_count;
/* ... */ /* 特定CPU架构的状态 */
struct thread_struct thread;
/* 进程当前所在的目录描述 */
struct fs_struct *fs;
/* 打开的文件描述信息 */
struct files_struct *files;
/* ... */
};

(3)thread_info结构和内核栈:
每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。
在kernel-2.4内核里面,内核栈的实现是:
 Union task_union {
                   Struct task_struct task;
                   Unsigned long stack[INIT_STACK_SIZE/sizeof(long)];
 };
其中,INIT_STACK_SIZE的大小只能是8K。
内核为每个进程分配task_struct结构体的时候,实际上分配两个连续的物理页面,底部用作task_struct结构体,结构上面的用作堆栈。使用current()宏能够访问当前正在运行的进程描述符。
注意:这个时候task_struct结构是在内核栈里面的,内核栈的实际能用大小大概有7K。
 
内核栈在kernel-2.6里面的实现是:
 Union thread_union {
                   Struct thread_info thread_info;
                   Unsigned long stack[THREAD_SIZE/sizeof(long)];
 };
 其中THREAD_SIZE的大小可以是4K,也可以是8K,thread_info占52bytes。
如下图所示,当内核栈为8K时,Thread_info在这块内存的起始地址,内核栈从堆栈末端向下增长。
所以此时,kernel-2.6中的current宏是需要更改的。要通过thread_info结构体中的task_struct域来获得于thread_info相关联的task。
 struct thread_info {
                   struct task_struct *task;
                   struct exec_domain *exec_domain;
                   __u32 flags;
__u32 status;
                   __u32 cpu;
                   …  ..
 };
 注意:此时的task_struct结构体已经不在内核栈空间里面了。


总结一下,

1. 为什么把内核栈和thread_info放在一起:
内核2.6版本之后,task_struct不再存放于内核栈中,而是通过slab分配器动态分配和复用。
所以为了获取当前运行进程信息, 新引入一个thread_info的结构体, 里面保存task_struct的指针, 放在内核栈底。
这样当进程从用户态陷入内核态后, esp寄存器会记录内核栈的地址, 通过计算就可以知道thread_info的地址, 进而获得task_struct的指针,也就获取了当前正在运行进程的所有信息。

2. 进程从整体上来看有两部分构成:

(1) 进程地址空间 (2)存在内核中的信息: 内核栈, thread_info, task_struct

(4)进程状态

2. 进程创建

3. 线程在Linux中的实现

4. 进程终结

5. 两个问题的解释

Reference:

Linux kernal 2.6.24

Linux内核设计与实现

fork: http://blog.csdn.net/cywosp/article/details/27316803

Linux进程管理: http://blog.csdn.net/xinyuan510214/article/details/50516279

Linux进程-基本概念: http://blog.sina.com.cn/s/blog_53ce9f9301018l1m.html

应用程序执行机制: http://www.cnblogs.com/li-hao/archive/2011/09/24/2189504.html

Linux进程管理(一、 基本概念和数据结构)的更多相关文章

  1. Linux进程管理子系统分析【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51298732 Linux进程管理: 进程与程序: 程序:存放在磁盘上的一系列代码 ...

  2. Linux进程管理 (2)CFS调度器

    关键词: 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 Linux进程管理 ( ...

  3. Linux进程管理知识整理

    Linux进程管理知识整理 1.进程有哪些状态?什么是进程的可中断等待状态?进程退出后为什么要等待调度器删除其task_struct结构?进程的退出状态有哪些? TASK_RUNNING(可运行状态) ...

  4. Linux性能及调优指南(翻译)之Linux进程管理

    本文为IBM RedBook的Linux Performanceand Tuning Guidelines的1.1节的翻译原文地址:http://www.redbooks.ibm.com/redpap ...

  5. Linux进程管理 (1)进程的诞生

    专题:Linux进程管理专题 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 L ...

  6. 《Linux 性能及调优指南》1.1 Linux进程管理

    https://blog.csdn.net/ljianhui/article/details/46718835 本文为IBM RedBook的Linux Performanceand Tuning G ...

  7. Linux进程管理与调度-之-目录导航【转】

    转自:http://blog.csdn.net/gatieme/article/details/51456569 版权声明:本文为博主原创文章 && 转载请著名出处 @ http:// ...

  8. 《Linux性能及调优指南》----1.1 Linux进程管理

    翻译:飞哥 ( http://hi.baidu.com/imlidapeng ) 版权所有,尊重他人劳动成果,转载时请注明作者和原始出处及本声明. 原文名称:<Linux Performance ...

  9. 《Linux性能及调优指南》 Linux进程管理

    版权所有: 原文名称:<Linux Performance and Tuning Guidelines> 原文地址:http://www.redbooks.ibm.com/abstract ...

随机推荐

  1. Java 容易疑惑的一些杂记录

    1 final.finally和finalize final 是一个关键字 ,final 修饰 对象不能被修改,final 修饰的方法不能被重写,final 修饰的 类 不能被继承. finally ...

  2. CSS样式汇总(转载)

    1.字体属性:(font) 大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位:PX.PD 样式 {font-style: o ...

  3. Activiti实战01_认识Activiti

    什么是Activiti Activiti是为解决工作流而创建的一套流程引擎.举个最简单的例子,请假流程就是一个工作流,从开始到审批到结束,像流一样的贯穿整个流程.在工作中最常见的就是OA了.工作流总是 ...

  4. JavaScript对象继承方式

    一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Parent 构造函数 成为 Children 的方法, ...

  5. tensorflow高效地推导pb模型,完整代码

    from matplotlib import pyplot as plt import numpy as np import os import six.moves.urllib as urllib ...

  6. UVA11722 Jonining with Friend

    Joining with Friend You are going from Dhaka to Chittagong by train and you came to know one of your ...

  7. phonegap geolocation android 问题

    很纠结的 phonegap 使用定位的时候 android 获取地址异常的慢,为什么呢? 经过分析 如果android 只开启gprs 上网功能 可以立即获取到经纬度 如果只开启wifi 根本就获取不 ...

  8. SSM4-Linux上jdk、tomcat、zookeeper------tar zxvf的安装

    1.zookeeper .Zookeeper介绍 官方推荐使用zookeeper注册中心. 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发 ...

  9. [转]IE userData

    IE浏览器实现了它专属的客户端存储机制——“userData”.userData可以实现一定量的字符串数据存储,可以将其用做是Web存储的替代方案.本文将详细介绍IE userData 概述 在IE5 ...

  10. 20190722-Moni和Boly的故事

    Moni(模拟)可以得到60分 Boly(暴力)可以得到40分 还好说,这次有点可行. 过程是: 先看了T3,可以模拟,然后做T1T2 T1 好说,$exgcd$,不会. 暴力,暴力!骗了40. T2 ...