Linux进程通过一个task_struct结构体描述,在linux/sched.h中定义,通过理解该结构,可更清楚的理解linux进程模型。       包含进程所有信息的task_struct数据结构是比较庞大的,但是该数据结构本身并不复杂,我们将它的所有域按其功能可做如下划分:

  • 进程状态(State)
  • 进程调度信息(Scheduling Information)
  • 各种标识符(Identifiers)
  • 进程通信有关信息(IPC:Inter_Process Communication)
  • 时间和定时器信息(Times and Timers)
  • 进程链接信息(Links)
  • 文件系统信息(File System)
  • 虚拟内存信息(Virtual Memory)
  • 页面管理信息(page)
  • 对称多处理器(SMP)信息
  • 和处理器相关的环境(上下文)信息(Processor Specific Context)
  • 其它信息

1. 进程状态(State)

进程执行时,它会根据具体情况改变状态。进程状态是调度和对换的依据。Linux中的进程主要有如下状态,如表1所示。

表3.1  Linux进程的状态

内核表示

含义

TASK_RUNNING

可运行

TASK_INTERRUPTIBLE

可中断的等待状态

TASK_UNINTERRUPTIBLE

不可中断的等待状态

TASK_ZOMBIE

僵死

TASK_STOPPED

暂停

TASK_SWAPPING

换入/换出

1).可运行状态:处于这种状态的进程,要么正在运行、要么正准备运行。正在运行的进程就是当前进程(由current所指向的进程),而准备运行的进程只要得到CPU就可以立即投入运行,CPU是这些进程唯一等待的系统资源。

2).等待状态:处于该状态的进程正在等待某个事件(event)或某个资源,它肯定位于系统中的某个等待队列(wait_queue)中。

3).暂停状态:此时的进程暂时停止运行来接受某种特殊处理。通常当进程接收到SIGSTOP、SIGTSTP、SIGTTIN或 SIGTTOU信号后就处于这种状态。例如,正接受调试的进程就处于这种状态。

4).僵死状态:进程虽然已经终止,但由于某种原因,父进程还没有执行wait()系统调用,终止进程的信息也还没有回收。顾名思义,处于该状态的进程就是死进程,这种进程实际上是系统中的垃圾,必须进行相应处理以释放其占用的资源。

进程状态转换如下图:

2.进程调度信息

调度程序利用这部分信息决定系统中哪个进程最应该运行,并结合进程的状态信息保证系统运转的公平和高效。这一部分信息通常包括进程的类别(普通进程还是实时进程)、进程的优先级等。表2描述了跟进程调度有关的字段,表3.3说明了几种常用的进程调度算法及这些算法的使用范围,如先来先服务主要用于实时进程的调度。

表2 进程调度信息

域名

含义

need_resched

调度标志

Nice

静态优先级

Counter

动态优先级

Policy

调度策略

rt_priority

实时优先级

表3  进程调度的策略

名称

解释

适用范围

SCHED_OTHER

其他调度

普通进程

SCHED_FIFO

先来先服务调度

实时进程

SCHED_RR

时间片轮转调度

只有root用户能通过sched_setscheduler()系统调用来改变调度策略。

3.标识符(Identifiers)

每个进程有进程标识符、用户标识符、组标识符,如表4所示。

不管对内核还是普通用户来说,怎么用一种简单的方式识别不同的进程呢?这就引入了进程标识符(PID:process identifier),每个进程都有一个唯一的标识符,内核通过这个标识符来识别不同的进程,同时,进程标识符PID也是内核提供给用户程序的接口,用户程序通过PID对进程发号施令。PID是32位的无符号整数,它被顺序编号:新创建进程的PID通常是前一个进程的PID加1。然而,为了与16位硬件平台的传统Linux系统保持兼容,在Linux上允许的最大PID号是32767,当内核在系统中创建第32768个进程时,就必须重新开始使用已闲置的PID号。

表4 各种标识符

域名

含义

Pid

进程标识符

Uid、gid

用户标识符、组标识符

Euid、egid

有效用户标识符、有效组标识符

Suid、sgid

备份用户标识符、备份组标识符

Fsuid、fsgid

文件系统用户标识符、文件系统组标识符

4.进程通信有关信息(IPC:Inter_Process Communication)

为了使进程能在同一项任务上协调工作,进程之间必须能进行通信即交流数据。

Linux支持多种不同形式的通信机制。它支持典型的Unix 通信机制(IPC Mechanisms):信号(Signals)、管道(Pipes),也支持System V 通信机制:共享内存(Shared Memory)、信号量和消息队列(Message Queues),如表5

表5 进程通信有关信息

域名

含义

Spinlock_t sigmask_lock

信号掩码的自旋锁

Long blocked

信号掩码

Struct signal  *sig

信号处理函数

Struct sem_undo *semundo

为避免死锁而在信号量上设置的取消操作

Struct sem_queue *semsleeping

与信号量操作相关的等待队列

5.进程链接信息(Links)

程序创建的进程具有父/子关系。因为一个进程能创建几个子进程,而子进程之间有兄弟关系,在task_struct结构中有几个域来表示这种关系。

在Linux系统中,除了初始化进程init,其他进程都有一个父进程(parent process)或称为双亲进程。可以通过fork()或clone()系统调用来创建子进程,除了进程标识符(PID)等必要的信息外,子进程的task_struct结构中的绝大部分的信息都是从父进程中拷贝,或说“克隆”过来的。系统有必要记录这种“亲属”关系,使进程之间的协作更加方便,例如父进程给子进程发送杀死(kill)信号、父子进程通信等,就可以用这种关系很方便地实现。

每个进程的task_struct结构有许多指针,通过这些指针,系统中所有进程的task_struct结构就构成了一棵进程树,这棵进程树的根就是初始化进程init的task_struct结构(init进程是Linux内核建立起来后人为创建的一个进程,是所有进程的祖先进程)。表6是进程所有的链接信息。

表6 进程链接信息

名称

解释 [指向哪个进程]

p_opptr

祖先

p_pptr

父进程

p_cptr

子进程

p_ysptr

弟进程

p_osptr

兄进程

Pidhash_next、

Pidhash_pprev

进程在哈希表中的链接

Next_task、

prev_task

进程在双向循环链表中的链接

Run_list

运行队列的链表

6.时间和定时器信息(Times and Timers)

一个进程从创建到终止叫做该进程的生存期(lifetime)。进程在其生存期内使用CPU的时间,内核都要进行记录,以便进行统计、计费等有关操作。进程耗费CPU的时间由两部分组成:一是在用户模式(或称为用户态)下耗费的时间、一是在系统模式(或称为系统态)下耗费的时间。每个时钟滴答,也就是每个时钟中断,内核都要更新当前进程耗费CPU的时间信息。

表7是和时间有关的域,上面所说的counter是指进程剩余的CPU时间片,也和时间有关,所以这里我们再次提及它。表8是进程的所有定时器。

表7与时间有关的域

域名

含义

Start_time

进程创建时间

Per_cpu_utime

进程在某个CPU上运行时在用户态下耗费的时间

Per_cpu_stime

进程在某个CPU上运行时在系统态下耗费的时间

Counter

进程剩余的时间片

表8  进程的所有定时器

定时器类型

解释

什么时候更新

用来表示此种定时器的域

ITIMER_REAL

实时定时器

实时更新,即不论该进程是否运行

it_real_value

it_real_incr

real_timer

ITIMER_VIRTUAL

虚拟定时器

只在进程运行于用户态时更新

it_virt_value

it_virt_incr

ITIMER_PROF

概况定时器

进程运行于用户态和系统态时更新

it_prof_value

it_prof_incr

7.文件系统信息(File System)

进程可以打开或关闭文件,文件属于系统资源,Linux内核要对进程使用文件的情况进行记录。task_struct结构中有两个数据结构用于描述进程与文件相关的信息。其中,fs_struct中描述了两个VFS索引节点(VFS inode),这两个索引节点叫做root和pwd,分别指向进程的可执行映象所对应的根目录(home directory)和当前目录或工作目录。file_struct结构用来记录了进程打开的文件的描述符(descriptor)。如表9所示。

表9  与文件系统相关的域

定义形式

解释

Sruct fs_struct *fs

进程的可执行映象所在的文件系统

Struct files_struct *files

进程打开的文件

在文件系统中,每个VFS索引节点唯一描述一个文件或目录,同时该节点也是向更低层的文件系统提供的统一的接口。

8.虚拟内存信息(Virtual Memory)

除了内核线程(kernel thread),每个进程都拥有自己的地址空间(也叫虚拟空间),用mm_struct来描述。另外Linux2.4还引入了另外一个域active_mm,这是为内核线程而引入。因为内核线程没有自己的地址空间,为了让内核线程与普通进程具有统一的上下文切换方式,当内核线程进行上下文切换时,让切换进来的线程的active_mm指向刚被调度出去的进程的active_mm(如果进程的mm域不为空,则其active_mm域与mm域相同)。内存信息如表10所示

表10   虚拟内存描述信息

定义形式

解释

Struct mm_struct *mm

描述进程的地址空间

Struct mm_struct *active_mm

内核线程所借用的地址空间

9.页面管理信息

当物理内存不足时,Linux内存管理子系统需要把内存中的部分页面交换到外存,其交换是以页为单位的。有关页面的描述信息如表11。

表11 页面管理信息

定义形式

解释

Int swappable

进程占用的内存页面是否可换出

Unsigned long min_flat,

maj_flt,nswap

进程累计的次(minor)缺页次数、

主(major)次数及累计换出、换入页面数

Unsigned long cmin_flat,

cmaj_flt,cnswap

本进程作为祖先进程,其所有层次子进程的累计的次(minor)缺页次数、主(major)次数及累计换出、换入页面数

10.进程内核栈及current宏

在Linux-2.6内核中堆栈这么定义:

union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};

根据内核的配置,THREAD_SIZE既可以是4K字节(1个页面)也可以是8K字节(2个页面)。thread_info是52个字节长。下图是当设为8KB时候的内核堆栈:Thread_info在这个内存区的开始处,内核堆栈从末端向下增长。进程描述符不是在这个内存区中,而分别通过task与thread_info指针使thread_info与进程描述符互联。所以获得当前进程描述符的current定义如下:

#define current get_current()
static inline struct task_struct * get_current(void)
{
return current_thread_info()->task;
}
static inline struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
__asm__("andl %%esp,%0; ":"=r" (ti) : "" (~(THREAD_SIZE - 1)));
return ti;
}

根据THREAD_SIZE大小,分别屏蔽掉内核栈的12-bit LSB(4K)或13-bit LSB(8K),从而获得内核栈的起始位置,及当前进程描述符的指针。

linux进程模型总结的更多相关文章

  1. Linux进程模型

    ----原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/08/01/2617884.html------ Linux进程通过一个task_st ...

  2. Linux进程/内核模型

    内核必须实现一组服务和相应的接口,应用程序则可以使用这些接口,而不是直接与硬件打交道. Linux内核主要由以下5个子系统组成:进程调度.内存管理.虚拟文件系统.进程间通信以及设备驱动. 在这个组成中 ...

  3. linux C++ 通讯架构(一)nginx安装、目录、进程模型

    nginx是C语言开发的,号称并发处理百万级别的TCP连接,稳定,热部署(运行时升级),高度模块化设计,可以用C++开发. 一.安装和目录 1.1 前提 epoll,linux内核版本为2.6或以上 ...

  4. 第一次作业:基于Linux 4.5的进程模型与调度器分析

    1.操作系统是怎么组织进程的? 1.1什么是线程,什么是进程: 刚接触时可能经常会将这两个东西搞混.简单一点的说,进程是一个大工程,线程则是这个大工程中每个小地方需要做的东西(在linux下看作&qu ...

  5. Linux IO模型和网络编程模型

    术语概念描述: IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者. 阻塞和非阻塞,是函数/方法的实现方式,即在数据就绪之前是立刻返回还是等待. 以文件IO为例,一个IO读过程是文件 ...

  6. Linux 进程

    Linux 进程 在用户空间,进程是由进程标识符(PID)表示的.从用户的角度来看,一个 PID 是一个数字值,可惟一标识一个进程.一个 PID 在进程的整个生命期间不会更改,但 PID 可以在进程销 ...

  7. Server Develop (五) Linux并发模型

    Linux并发模型 目前可以实现并发程序的方法有Apache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型,以及select模 ...

  8. Linux设备模型(总线、设备、驱动程序和类)

    Linux设备驱动程序学习(13) -Linux设备模型(总线.设备.驱动程序和类)[转] 文章的例子和实验使用<LDD3>所配的lddbus模块(稍作修改). 提示:在学习这部分内容是一 ...

  9. 探索 Linux 内存模型--转

    引用:http://www.ibm.com/developerworks/cn/linux/l-memmod/index.html 理解 Linux 使用的内存模型是从更大程度上掌握 Linux 设计 ...

随机推荐

  1. java web中cookie的永久创建与撤销

    一.首先是创建cookie 当在数据库中查找知道所输入的用户名和密码正确之后,就开始创建: String cb=request.getParameter("cb");//cb就是登 ...

  2. Windows服务器nginx+tomcat服务负载均衡

    一.安装两个tomcat服务自启动 1. 解压两个tomcat,名称为分别1,2 2. 配置环境变量 3. 修改文件server.xml中的三个端口号,使得两个tomcat不冲突 (1)<Ser ...

  3. 我们一起学Windows Phone 8-01-开发环境搭建

    我们仅讨论Windows Phone 8的开发,不考虑兼容向下兼容.也不会提供任何盗版软件的下载.破解. 需要准备 知识:.NET相关开发经验,C#语言开发经验.如果有WPF或Silverlight开 ...

  4. Linux的网卡由eth0变成了eth1,如何修复 (转载)

    Linux的网卡由eth0变成了eth1,如何修复   使用wmware安装了linux,安装成功后,使用的网卡是eth0,没有eth1.但是用过一段时间后,不知道为什么eth0无法使用,系统却自动生 ...

  5. ASP.net中导出Excel的简单方法介绍

    下面介绍一种ASP.net中导出Excel的简单方法 先上代码:前台代码如下(这是自己项目里面写的一点代码先贴出来吧) <div id="export" runat=&quo ...

  6. [DevExpress]ChartControl之基准线示例

    关键代码: /// <summary> /// 创建基准线ConstantLine /// </summary> /// <param name="chart& ...

  7. python(三)一个文件读写操作的小程序

    我们要实现一个文件读写操作的小程序 首先我们有一个文件 我们要以"============"为界限,每一个角色分割成一个独立的txt文件,按照分割线走的话是分成 xiaoNa_1. ...

  8. php提取淘宝URL中ID的代码

    一段可以提取淘宝URL中ID的PHP代码. 例如: <?php $taobao = 'taobao.com'; $tmall = 'tmall.com'; $guojitmall = 'tmal ...

  9. Django配置静态文件(CSS\js)及Django调用JS、CSS、图片等静态文件

    1 新建一项目: root@python:django-admin.py startproject csstest root@python:cd csstest root@python:ls csst ...

  10. 帝国cms中 内容分页的SEO优化

    关于内容页如果存在分页的话,我们想区分第一页和后面数页,当前的通用做法是在标题上加入分页码,帝国cms中如何做到呢.我们可以修改在e/class/functions.php中的源码.找到找到GetHt ...