Linux进程描述符:task_struct结构体

浅析task_struct结构体

1、简介

1.1进程

1.1.1进程的概念

我们知道操作系统最核心的概念就是进程。
其实进程简单来说就是在操作系统中运行的程序,它是操作系统资源管理的最小单位。
进程是一个动态的实体,它是程序的一次执行过程。
进程和程序的区别在于:进程是动态的,程序是静态的,进程是运行中的程序,而程序是一些保存在硬盘上的可执行代码。
在Linux下面,可以通过命令ps或pstree查看当前系统中的进程。

1.1.2进程的结构。

Linux进程结构:可由三部分组成:代码段、数据段、堆栈段。也就是程序、数据、进程控制块PCB(Process Control Block进程控制块)组成。进程控制块是进程存在的惟一标识,系统通过PCB的存在而感知进程的存在。

这个PCD数据结构是一种结构体,由操作系统创建和管理,下面我们来了解下tast_struct结构体是如何来通过进程控制块对进程进行控制和调控的。

2、task_struct源码成员解析

2.1、task_struct源码

Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。它定义在linux-2.6.38.8/include/linux/sched.h文件中。
http://lxr.free-electrons.com/source/include/linux/sched.h

2.2、task_struct源码成员分析

2.2.1进程状态:

volatile long state;/* -1 unrunnable, 0 runnable, >0 stopped */

这个是进程的运行时状态,-1代表不可运行,0代表可运行,>0代表已停止。
volatile关键字是降低编译器对代码的优化,是state变量一直从变量的内存中读取内容而不是寄存器;从而保证对操作系统状态实时访问的稳定性。

state成员的可能取值如下:

/*
  * Task state bitmask. NOTE! These bits are also
  * encoded in fs/proc/array.c: get_task_state().
  *
  * We have two separate sets of flags: task->state
  * is about runnability, while task->exit_state are
  * about the task exiting. Confusing, but this way
  * modifying one set can't modify the other one by
  * mistake.
  */
 #define TASK_RUNNING            0
 #define TASK_INTERRUPTIBLE      1
 #define TASK_UNINTERRUPTIBLE    2
 #define TASK_STOPPED            4
 #define TASK_TRACED             8

/* in tsk->exit_state */
 #define EXIT_DEAD               16
 #define EXIT_ZOMBIE             32
 #define EXIT_TRACE              (EXIT_ZOMBIE | EXIT_DEAD)

/* in tsk->state again */
 #define TASK_DEAD               64
 #define TASK_WAKEKILL           128    /** wake on signals that are deadly **/
 #define TASK_WAKING             256
 #define TASK_PARKED             512
 #define TASK_NOLOAD             1024
 #define TASK_STATE_MAX          2048

 /* Convenience macros for the sake of set_task_state */
#define TASK_KILLABLE           (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED            (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED             (TASK_WAKEKILL | __TASK_TRACED)

介绍几种常用的取值

状态 描述
TASK_RUNNING 表示进程要么正在执行,要么正要准备执行
TASK_INTERRUPTIBLE 进程因为等待某些条件处于阻塞(挂起的状态),一旦等待的条件成立,进程便会从该状态转化成就绪状态
TASK_UNINTERRUPTIBLE 与TASK_INTERRUPTIBLE类似,但是我们传递任意信号等不能唤醒他们,只有它所等待的资源可用的时候,他才会被唤醒。
TASK_STOPPED 进程被停止执行
TASK_TRACED 进程被debugger等进程所监视。
EXIT_DEAD 表示进程的最终状态。
EXIT_ZOMBIE 进程的执行被终止,但是其父进程还没有使用wait()等系统调用来获知它的终止信息,此时进程成为僵尸进程

2.2.2进程标识符(PID)

pid_t pid;     //进程的标识符
pid_t tgid;    //线程组标识符

Unix系统通过pid来标识进程,linux把不同的pid与系统中每个进程或轻量级线程关联,而unix程序员希望同一组线程具有共同的pid,遵照这个标准linux引入线程组的概念。一个线程组所有线程与领头线程具有相同的pid,存入tgid字段,getpid()返回当前进程的tgid值而不是pid的值。
它的引入是为了区别每个进程;tgid的引入是由于Unix程序员希望同一组线程具有相同的pid所以就引入了tgid。

2.2.3进程标记符

unsigned int flags; /* per process flags, defined below */ 

flags反应进程的状态信息(不是运行状态),用于内核识别当前进程的状态。

取值范围如下

 /*
* Per process flags
*/
#define PF_EXITING      0x00000004      /* getting shut down */
#define PF_EXITPIDONE   0x00000008      /* pi exit done on shut down */
#define PF_VCPU         0x00000010      /* I'm a virtual CPU */
#define PF_WQ_WORKER    0x00000020      /* I'm a workqueue worker */
#define PF_FORKNOEXEC   0x00000040      /* forked but didn't exec */
#define PF_MCE_PROCESS  0x00000080      /* process policy on mce errors */
#define PF_SUPERPRIV    0x00000100      /* used super-user privileges */
#define PF_DUMPCORE     0x00000200      /* dumped core */
#define PF_SIGNALED     0x00000400      /* killed by a signal */
#define PF_MEMALLOC     0x00000800      /* Allocating memory */
#define PF_NPROC_EXCEEDED 0x00001000    /* set_user noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH    0x00002000      /* if unset the fpu must be initialized before use */
#define PF_USED_ASYNC   0x00004000      /* used async_schedule*(), used by module init */
#define PF_NOFREEZE     0x00008000      /* this thread should not be frozen */
#define PF_FROZEN       0x00010000      /* frozen for system suspend */
#define PF_FSTRANS      0x00020000      /* inside a filesystem transaction */
#define PF_KSWAPD       0x00040000      /* I am kswapd */
#define PF_MEMALLOC_NOIO 0x00080000     /* Allocating memory without IO involved */
#define PF_LESS_THROTTLE 0x00100000     /* Throttle me less: I clean memory */
#define PF_KTHREAD      0x00200000      /* I am a kernel thread */
#define PF_RANDOMIZE    0x00400000      /* randomize virtual address space */
#define PF_SWAPWRITE    0x00800000      /* Allowed to write to swap */
#define PF_NO_SETAFFINITY 0x04000000    /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY    0x08000000      /* Early kill for mce process policy */
#define PF_MUTEX_TESTER 0x20000000      /* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP 0x40000000      /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK 0x80000000      /* this thread called freeze_processes and should not be frozen */

介绍几种常用取值

状态 取值
PF_FORKNOEXEC 表示进程刚被创建,但还没有执行
PF_SUPERPRIV 表示进程拥有超级用户特权
PF_SIGNALED 表示进程被信号杀出
PF_EXITING 表示进程开始关闭

2.2.4进程标记符

unsigned int flags; /* per process flags, defined below */  

反应进程状态的信息,但不是运行状态,用于内核识别进程当前的状态,以备下一步操作

2.2.5表示进程亲属关系的成员

/*
 * pointers to (original) parent process, youngest child, younger sibling,
 * older sibling, respectively.  (p->father can be replaced with
 * p->real_parent->pid)
 */
struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
/*
 * children/sibling forms the list of my natural children
 */
struct list_head children;      /* list of my children */
struct list_head sibling;       /* linkage in my parent's children list */
struct task_struct *group_leader;       /* threadgroup leader */

在Linux系统中,所有进程之间都有着直接或间接地联系,每个进程都有其父进程,也可能有零个或多个子进程。拥有同一父进程的所有进程具有兄弟关系。


成员 描述
real_parent 指向其父进程,如果创建它的父进程不再存在,则指向PID为1的init进程
Pparent 指向当前进程的父进程,当它终止时,必须向它的父进程发送信号。它的值通常与real_parent相同
children 链表的头部,链表中的所有元素都是它的子进程
sibling 把当前进程插入到兄弟链表中
group_leader 指向其进程组的领头进程

2.2.6ptrace系统调用

Ptrace提供了一种父进程,它可以被用来控制子进程的运行,常被用来进行断点调试,当它被设置为0时表示不需要追踪。

/*
 * Ptrace flags
 *
 * The owner ship rules for task->ptrace which holds the ptrace
 * flags is simple.  When a task is running it owns it's task->ptrace
 * flags.  When the a task is stopped the ptracer owns task->ptrace.
 */

#define PT_SEIZED       0x00010000      /* SEIZE used, enable new behavior */
#define PT_PTRACED      0x00000001
#define PT_DTRACE       0x00000002      /* delayed trace (used on m68k, i386) */
#define PT_PTRACE_CAP   0x00000004      /* ptracer can follow suid-exec */

#define PT_OPT_FLAG_SHIFT       3
/* PT_TRACE_* event enable flags */
#define PT_EVENT_FLAG(event)    (1 << (PT_OPT_FLAG_SHIFT + (event)))
#define PT_TRACESYSGOOD         PT_EVENT_FLAG(0)
#define PT_TRACE_FORK           PT_EVENT_FLAG(PTRACE_EVENT_FORK)
#define PT_TRACE_VFORK          PT_EVENT_FLAG(PTRACE_EVENT_VFORK)
#define PT_TRACE_CLONE          PT_EVENT_FLAG(PTRACE_EVENT_CLONE)
#define PT_TRACE_EXEC           PT_EVENT_FLAG(PTRACE_EVENT_EXEC)
#define PT_TRACE_VFORK_DONE     PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE)
#define PT_TRACE_EXIT           PT_EVENT_FLAG(PTRACE_EVENT_EXIT)
#define PT_TRACE_SECCOMP        PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP)

#define PT_EXITKILL             (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT)
#define PT_SUSPEND_SECCOMP      (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT)

/* single stepping state bits (used on ARM and PA-RISC) */
#define PT_SINGLESTEP_BIT       31
#define PT_SINGLESTEP           (1<
#define PT_BLOCKSTEP_BIT        30
#define PT_BLOCKSTEP            (1<

2.2.7优先级

int prio, static_prio, normal_prio;
unsigned int rt_priority;

成员 描述
static_prio 用来保存静态优先级,可以调用nice系统直接来修改取值范围为100~139
rt_priority 用来保存实时优先级,取值范围为0~99
prio 用来保存动态优先级
normal_prio 它的值取决于静态优先级和调度策略

2.2.8进程地址空间

进程都拥有自己的资源,这些资源指的就是进程的地址空间,每个进程都有着自己的地址空间,在task_struct中,有关进程地址空间的定义如下:

struct mm_struct *mm, *active_mm;
/* per-thread vma caching */
u32 vmacache_seqnum;
struct vm_area_struct *vmacache[VMACACHE_SIZE];
#if defined(SPLIT_RSS_COUNTING)
struct task_rss_stat    rss_stat;
#endif

/*  http://lxr.free-electrons.com/source/include/linux/sched.h?V=4.5#L1484  */
#ifdef CONFIG_COMPAT_BRK
unsigned brk_randomized:1;
#endif

成员 描述
mm 进程所拥有的内存空间描述符,对于内核线程的mm为NULL
active_mm 指进程运行时所使用的进程描述符
rss_stat 被用来记录缓冲信息

总结:到这里,我们已经看到了很多的字段,但这些字段只是task_struct的冰山一角,如果还有兴趣可以通过阅读源码分析。

你可能感兴趣的:(Linux)