PCB

PCB(Process Control Block): 系统中存放进程的管理和控制信息的数据结构,PCB是进程存在的唯一标志。

task_struct

操作系统通过使用task_struct结构体描述进程,使用双向链表将这些结构组织进行管理。 在源码的/include/linux/sched.h文件中可以查看struct task_struct 结构体定义。

 struct task_struct {
     //  进程状态
    volatile long            state; 
     int                exit_state;
    int                exit_code;
    int                exit_signal; // 被设置为-1表示是某个线程组中的一员,只有当线程组的最后一个成员终止时,才会产生信号,以通知线程组的领头进程的父进程。

    // 进程标识
    pid_t                pid;
    pid_t                tgid;
    char                comm[TASK_COMM_LEN];


    // 进程内核栈
    void                *stack;

    // 进程标记
    unsigned int            flags;

    // 进程的父子、兄弟关系
    struct task_struct __rcu    *real_parent;
    struct task_struct __rcu    *parent;
    struct list_head        children;
    struct list_head        sibling;
    struct task_struct        *group_leader;

    // 进程调度信息
    // 时间\信号
    // // 控制终端信息
    // 当前工作目录
   // umask 掩码
    // 文件
    struct fs_struct        *fs;
   struct files_struct        *files;
   // 进程地址空间
   struct mm_struct        *mm;   // 进程内存描述符
   struct mm_struct        *active_mm;
  // 用户id和组id
 // 会话和进程组
 // 进程可以使用的资源上限 cgroup
 // 进程间通信
 ..... 
 }

说明:

  1. 进程状态

    volatile long state;
    int exit_state;

state的可能取值如下:

/* Used in tsk->state: */
#define TASK_RUNNING            0x0000     /*表示正在执行或者准备执行*/
#define TASK_INTERRUPTIBLE        0x0001     /*可中断阻塞状态*/
#define TASK_UNINTERRUPTIBLE        0x0002 /*不可中断阻塞状态*/
#define __TASK_STOPPED            0x0004 /*停止状态*/
#define __TASK_TRACED            0x0008  /*被debugger等进行监视*/
/* Used in tsk->exit_state: */
#define EXIT_DEAD            0x0010  /*最终状态, 进程死亡*/
#define EXIT_ZOMBIE            0x0020 /*僵尸进程, 表示进程被终止,但是父进程还没有获取它的终止信息,比如进程有没有执行完等信息*/
#define EXIT_TRACE            (EXIT_ZOMBIE | EXIT_DEAD)  /*跟踪状态*/
/* Used in tsk->state again: */
#define TASK_PARKED            0x0040     
#define TASK_DEAD            0x0080
#define TASK_WAKEKILL            0x0100    /*唤醒并杀死进程*/
#define TASK_WAKING            0x0200  /*唤醒进程*/
#define TASK_NOLOAD            0x0400
#define TASK_NEW            0x0800
#define TASK_STATE_MAX            0x1000
  1. 进程标识

    pid_t pid; 进程的唯一标识
    pid_t tgid; 进程组的领头线程的pid成员值

pid是进程的唯一表示,范围是0~32767,可以表示32768个进程。

Unix系统通过pid来标识进程,linux把不同的pid与系统中每个进程或轻量级线程关联,而unix程序员希望同一组线程具有共同的pid,遵照这个标准linux引入线程组的概念。一个线程组所有线程与领头线程具有相同的pid,存入tgid字段,getpid()返回当前进程的tgid值而不是pid的值。
在Linux系统中,一个线程组中的所有线程使用和该线程组的领头线程(该组中的第一个轻量级进程)相同的PID,并被存放在tgid成员中。只有线程组的领头线程的pid成员才会被设置为与tgid相同的值。注意,getpid()系统调用返回的是当前进程的tgid值而不是pid值。

可以通过 cat /proc/sys/kernel/pid_max 查看系统支持多少进程

[root@iz2zecj7a5r32f2axsctb9z ~]# sysctl -a | grep kernel.pid_max
kernel.pid_max = 32768
  1. 进程内核栈

    void *stack

对于每个进程,linux都把两个不同的数据结构紧凑的存放在一个单独为进程分配的内存区域中,一个是内核态的进程堆栈,另一个是线程描述符thread_info。这两个数据结构被定义在一个联合体中,由alloc_thread_info_node分配内存空间。

  1. 进程标记

    unsigned int flags;

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

flags 可能的取值:

/*
 * Per process flags
 */
#define PF_VCPU            0x00000001    /* I'm a virtual CPU */
#define PF_IDLE            0x00000002    /* I am an IDLE thread */
#define PF_EXITING        0x00000004    /* Getting shut down */
#define PF_IO_WORKER        0x00000010    /* Task is an IO worker */
#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_KSWAPD        0x00020000    /* I am kswapd */
#define PF_MEMALLOC_NOFS    0x00040000    /* All allocation requests will inherit GFP_NOFS */
#define PF_MEMALLOC_NOIO    0x00080000    /* All allocation requests will inherit GFP_NOIO */
#define PF_LOCAL_THROTTLE    0x00100000    /* Throttle writes only against the bdi I write to,
                         * I am cleaning dirty pages from some other bdi. */
#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_mask */
#define PF_MCE_EARLY        0x08000000      /* Early kill for mce process policy */
#define PF_MEMALLOC_NOCMA    0x10000000    /* All allocation request will have _GFP_MOVABLE cleared */
#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 */
  1. 进程亲属关系

    struct task_struct _rcu *realparent;
    struct task_struct _rcu *parent;
    struct list
    head children;
    struct list_head sibling;
    struct task_struct *group_leader;

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

  1. 进程调度信息

    int prio;
    int static_prio;
    int normal_prio;
    unsigned int rt_priority;
    const struct sched_class *sched_class;
    struct sched_entity se;
    struct sched_rt_entity rt;
    struct sched_dl_entity dl;
    unsigned int policy;

prio : 动态优先级
static_prio: 静态优先级, 可以通过nice来进行修改
normal_prio: 取决于静态优先级和调度策略
rt_priority: 实时优先级
policy: 调度策略

  1. 时间数据成员

    u64 utime; // 进程在用户态经过的节拍数
    u64 stime; // 进程在内核态经过的节拍数
    u64 utimescaled; // 用户态运行时间
    u64 stimescaled; // 内核态运行时间
    u64 gtime; // 虚拟机运行时间
    struct prev_cputime prev_cputime; // 先前运行的时间
    struct vtime vtime;
    unsigned long nvcsw; // 自愿上下文切换次数
    unsigned long nivcsw; // 非自愿上下文切换次数
    u64 start_time; // 进程创建时间
    u64 start_boottime;
    unsigned long min_flt;
    unsigned long maj_flt;

  2. 信号处理

    int pdeath_signal;
    struct signal_struct *signal;
    struct sighand_struct _rcu *sighand;
    sigset
    t blocked;
    sigset_t real_blocked;
    sigset_t saved_sigmask;
    struct sigpending pending;
    unsigned long sas_ss_sp;
    size_t sas_ss_size;
    unsigned int sas_ss_flags;
    struct callback_head *task_works;

pdeath_signal : 用于判断父进程终止时发送的信号
signal: 指向进程的信号描述符
sighand: 指向进程的信号处理程序描述符
blocked: 表示阻塞信号的掩码
real_blocked: 表示临时掩码
pending: 存放私有挂起信号的数据结构
sas_ss_sp: 信号处理程序备用堆栈的地址
sas_ss_size 堆栈的大小

  1. 文件系统

    struct fs_struct *fs;
    struct files_struct *files;

fs 表示 进程与文件系统的联系, 包括当前目录和根目录
files 表示进程打开的文件

  1. 进程地址空间

    struct mm_struct *mm;
    struct mm_struct *active_mm;
    struct vmacache vmacache;
    struct task_rss_stat rss_stat;

mm 指向进程所拥有的内存描述符, active_mm指向进程运行时所使用的内存描述符。对于普通进程而言,这两个指针变量的值相同。但是,内核线程不拥有任何内存描述符,所以它们的mm成员总是为NULL。当内核线程得以运行时,它的active_mm成员被初始化为前一个运行进程的active_mm值

rss_stat: 记录缓冲信息

  1. 其他
  • 用于保护资源分配和释放的自旋锁

    spinlock_t alloc_lock;

  • 进程描述符使用计数,被置为2时,表示进程描述符正在被使用而且其相应的进程处于活动状态

    refcount_t usage;

  • 调度器统计进程的运行信息

    struct sched_info sched_info;

  • 构建进程列表

    struct list_head tasks;

  • PID 散列表

    /* PID/PID hash table linkage. */
    struct pid *thread_pid;
    struct hlist_node pid_links[PIDTYPE_MAX];
    struct list_head thread_group;
    struct list_head thread_node;

  • 缺页统计

    unsigned long min_flt; // 软缺页异常次数
    unsigned long maj_flt; //从硬盘拷数据而发生的缺页(主缺页)的次数

  • 程序名

    char comm[TASK_COMM_LEN];

  • 进程通信(sysvIPC)

    struct sysv_sem sysvsem;
    struct sysv_shm sysvshm;

  • 命名空间

    struct nsproxy *nsproxy;

  • 进程审计

    struct audit_context *audit_context;

  • 用户id和会话id

    kuid_t loginuid;
    unsigned int sessionid;

文档更新时间: 2021-03-14 19:23   作者:周国强