前言
当把一个程序加载到内存当中,此时,这个时候就有了进程,关于进程,有一个相关的叫做进程控制块(PCB),这个是系统为了方便进行管理进程所设置的一个数据结构,通过PCB,就可以记录进程的特征以及一些信息。
内核当中使用进程描述符task_struct。
这个task_struct就是一个定义的一个结构体,通过这个结构体,可以对进程的所有的相关的信息进行维护,对进程进行管理。
接下来我们需要对task_struct结构体当中的成员进行一些分析。
linux内核版本 |
---|
Linux version 2.6.32-431.el6.i686 |
1 task_struct
1.1 进程状态
volatile long state;
int exit_state;`
表示进程的状态,
在进程执行的时候,它会有一个状态,这个状态对于进程来说是很重要的一个属性。进程主要有以下几个状态。
state可能的取值
这些状态就不再一一说明了,后续进程篇会有专门的说明。
1.2 进程标识符(PID)
pid_t pid;
pid_t tgid;
每个进程都有进程标识符、用户标识符、组标识符,进程标识符对于每一个进程来说都是唯一的。内核通过进程标识符来对不同的进程进行识别,一般来说,行创建的进程都是在前一个进程的基础上PID加上1作为本进程的PID。为了linux平台兼容性,PID一般最大为32767。
1.3 进程内核栈
void *stack
stack用来维护分配给进程的内核栈,内核栈的意义在于,进程task_struct所占的内存是由内核动态分配的,确切的说就是内核根本不给task_struct分配内存,只给内核栈分配8KB内存,并且一部分会提供给task_struct使用。
task_struct结构体大约占用的大小为1K左右,根据内核版本的不同,大小也会有差异。
所以,也就可以知道内核栈最大也就是7KB,否则,内核栈会覆盖task_struct结构。
1.4 标记
unsigned int flags
用来反映一个进程的状态信息,但不是运行状态,用于内核识别进程当前的状态,flags的取值如下:
可使用的标记 | 功能 |
---|---|
PF_FORKNOEXEC | 进程刚创建,但还没执行。 |
PF_SUPERPRIV | 超级用户特权。 |
PF_DUMPCORE | 关于核心。 |
PF_SIGNALED | 进程被信号(signal)杀出。 |
PF_EXITING | 进程开始关闭。 |
1.5 表示进程亲属关系的成员
struct task_struct *real_parent;
struct task_struct *parent;
struct list_head children;
struct list_head sibling;
struct task_struct *group_leader;
linux系统当中,考虑到进程的派生,所以进程之间会存在父进程和子进程这样的关系,当然,对于同一个父进程派生出来的进程,他们的关系当然是兄弟进程了。
成员 | 功能 |
---|---|
real_parent | 指向父进程的指针,如果父进程不存在了,则指向PID为1的进程 |
parent | 指向父进程的,值与real——parent相同,需要向它的父进程发送信号 |
children | 表示链表的头部,链表中的所有元素都是它的子进程 |
sibling | 用于当前进程插入兄弟链表当中 |
group_leader | 指向进程组的领头进程 |
1.6 ptrace系统调用
unsigned int ptrace;
struct list_head ptraced;
struct list_head ptrace_entry;
首先我们要清楚ptrace是什么东西,ptrace是一种提供父进程控制子进程运行,并且可以检查和改变它的核心image。当trace设置为0时不需要被跟踪。
1.7 性能诊断工具——Performance Event
#ifdef CONFIG_PERF_EVENTS
#ifndef __GENKSYMS__
void * __reserved_perf__;
#else
struct perf_event_context *perf_event_ctxp;
#endif
struct mutex perf_event_mutex;
struct list_head perf_event_list;
#endif
Performance Event是性能诊断工具,这些成员用来帮助它进行分析进程性能问题。
1.8 进程调度
int prio, static_prio, normal_prio;
unsigned int rt_priority;
成员 | 功能 |
---|---|
static_prio | 保存静态优先级,可以通过nice系统进行修改 |
rt_priority | 保存实时优先级 |
normal_prio | 保存静态优先级和调度策略 |
prio | 保存动态优先级 |
调度进程利用这部分信息决定系统当中的那个进程最应该运行,并且结合进程的状态信息保证系统运作高效。
提到进程调度,当然还需要说明一下进程调度策略,我们来看下关于调度策略的成员:
unsigned int policy;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
成员 | 功能 |
---|---|
policy | 调度策略 |
sched_class | 调度类 |
se | 普通进程的一个调用的实体,每一个进程都有其中之一的实体 |
rt | 实时进程的调用实体,每个进程都有其中之一的实体 |
cpus_allowed | 用于控制进程可以在处理器的哪里运行 |
policy表示进程的调度策略,主要有以下五种:
种类 | 功能 |
---|---|
SCHED_NORMAL | 用于普通进程 |
SCHED_BATCH | 普通进程策略的分化版本,采用分时策略 |
SCHED_IDLE | 优先级最低,系统空闲时才跑这类进程 |
SCHED_FIFO | 先入先出的调度算法 |
SCHED_RR | 实时调度算法,采用时间片,相同优先级的任务当用完时间片就会放到队列的尾部,保证公平性,同时,高优先级的任务抢占低优先级的任务。 |
SCHED_DEADLINE | 新支持的实时调度策略,正对突发性计算 |
说完了调度策略,我们再来看一下调度类。
调度类 | 功能 |
---|---|
idle_sched_class | 每一个cpu的第一个pid=0的线程,是一个静态的线程 |
stop_sched_class | 优先级最高的线程,会中断所有其他的线程,而且不会被其他任务打断 |
rt_sched_slass | 作用在实时线程 |
fair_sched_class | 作用的一般线程 |
它们的优先级顺序为Stop>rt>fair>idle
1.9进程的地址空间
struct mm_struct *mm, *active_mm;
成员 | 功能 |
---|---|
mm | 进程所拥有的用户空间的内存描述符 |