浅谈task_struct各个字段内容

什么是进程?什么是task_struct?

  首先站在用户的角度来看:进程就是运行中的程序,这是一个比较抽象化的概念。

  站在操作系统的角度来看:进程就是操作系统对进程的描述,这个描述信息就是对进程的具象化描述- - -这个描述信息就是进程,这个描述信息就是pcb(process control block)- - -进程控制块或者进程描述符。在linux下就是task_struct这个结构体。

  在创建新进程时,Linux就从系统内存中分配一个task_struct结构,并把它的首地址加入 task 数组中,这个 task 数组是系统中的一个向量数组,该数组的长度默认是 512B,该数组的元素是指向task_struct的。

《操作系统精髓与设计原理》这本书中对进程作了如下定义:

  • 一个正在执行中的程序
  • 一个正在计算机上执行的程序实例
  • 能分配给处理器并由处理器处理的实体
  • 一个具有以下特征的活动单元:1、一组指令序列的执行。2、一个当前状态和相关的系统资源集合
  那么 task_struct 中都有什么内容呢?
  • 标识符:描述本进程的唯一标识符,用于区别其他进程
  • 状态:任务状态,退出信号,退出代码等
  • 优先级:相对于其他进程的优先级
  • 程序计数器:程序中即将被执行的下一条指令的地址
  • 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • 上下文数据:进程执行时处理器的寄存器中的数据
  • IO状态信息:包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。
  • 记账信息(审计信息):可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
  • 那么还有其他的信息如下介绍:

调度数据成员

//进程的状态,能否执行(-1, 0, >1)
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */

volatile这个关键字是保持内存可见性,防止代码过度优化,就是state变量从内存当中读取数据,而不是将从寄存器中读取,这也是为了保证对操作系统状态实时访问的稳定性。

/*	状态取值
 192  * Task state bitmask. NOTE! These bits are also
 193  * encoded in fs/proc/array.c: get_task_state().
 194  *
 195  * We have two separate sets of flags: task->state
 196  * is about runnability, while task->exit_state are
 197  * about the task exiting. Confusing, but this way
 198  * modifying one set can't modify the other one by
 199  * mistake.
 200  */
#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_ZOMBIE             16
#define EXIT_DEAD               32
/* in tsk->state again */
#define TASK_DEAD               64
#define TASK_WAKEKILL           128
#define TASK_WAKING             256
#define TASK_PARKED             512
#define TASK_STATE_MAX          1024
/* 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)
/* Convenience macros for the sake of wake_up */
#define TASK_NORMAL             (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
#define TASK_ALL                (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED)

//用于自定义调度程序行为
unsigned int flags; /* per process flags, defined below */

/*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_MEMPOLICY    0x10000000      /* Non-default NUMA mempolicy */
#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 */

unsigned int policy; //该进程的调度策略

调度策略有:
SCHED_OTHER 0 非实时进程,基于优先权的轮转法(round robin)。
SCHED_FIFO 1 实时进程,用先进先出算法。
SCHED_RR 2 实时进程,用基于优先权的轮转法。

进程标识符

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

tgid是用于表示线程组的标识符,它等于主线程的id,主线程的id也就是这个进程的id。

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

struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
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 */

real_parent 指向其父进程,如果父进程不存在,则指向1号 init 进程;
parent 是父进程,是接受SIGCHLD信号的,也就是回收子进程资源的进程;
children 链表中都是它的子进程;
sibling 把当前链表插入兄弟链表中
group_leader 指向线程组的首位。

进程地址空间

struct mm_struct *mm, *active_mm;

struct mm_struct *mm, *active_mm;
#ifdef CONFIG_COMPAT_BRK
        unsigned brk_randomized:1;
#endif
#if defined(SPLIT_RSS_COUNTING)
        struct task_rss_stat    rss_stat;

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

信号处理

/* signal handlers */
         struct signal_struct *signal;
         struct sighand_struct *sighand;
 
         sigset_t blocked, real_blocked;
         sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
         struct sigpending pending;
 
         unsigned long sas_ss_sp;
         size_t sas_ss_size;
         int (*notifier)(void *priv);
         void *notifier_data;
         sigset_t *notifier_mask;

signal 指向信号描述符
sighand 指向信号处理程序描述符
blocked 表示被阻塞信号的掩码
real_blocked 表示临时掩码
pending 中存放未决信号(未被处理的信号)
sas_ss_sp 是信号处理程序备用堆栈的地址
sas_ss_size 表示堆栈的大小
设备驱动程序常用notifier指向的函数来阻塞进程的某些信号。(notifier_data是可能用到的数据,notifier_mask是信号的位掩码)

ptrace系统调用

gdb调试中底层就是使用 ptrace 来完成的。

unsigned int ptrace; //追踪

/*
* ptraced is the list of tasks this task is using ptrace on.
* This includes both natural children and PTRACE_ATTACH targets.
* p->ptrace_entry is p's link on the p->parent->ptraced list.
*/
struct list_head ptraced;
struct list_head ptrace_entry;
unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use.  */
#ifdef CONFIG_HAVE_HW_BREAKPOINT
        atomic_t ptrace_bp_refcnt;
#endif

其他数据成员

fpu_counter包含使用FPU的连续上下文切换的数量。

(1) unsigned char fpu_counter;

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

(2) atomic_t usage;

用于表示获取大内核锁的次数,如果进程未获得过锁,则置为-1。

(3) int lock_depth; /* BKL lock depth */

用于管理资源分配以及释放的自旋锁。

(4) /* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
mempolicy */
spinlock_t alloc_lock;

用于调度器统计进程的运行信息。

(5)
#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
struct sched_info sched_info;
#endif

命名空间

(6)/* namespaces */
struct nsproxy *nsproxy;

死锁检测

(7)#ifdef CONFIG_DEBUG_MUTEXES
/* mutex deadlock detection */
struct mutex_waiter *blocked_on;
#endif

内存回收

(8)struct reclaim_state *reclaim_state;

I/O调度器所使用的信息

(9)struct io_context *io_context;

存放块设备I/O数据流量信息

(10)struct backing_dev_info *backing_dev_info;


PS:本文是基于CentOS Linux release 7.3.1611版本。task_struct中还有很多其他信息,本文没有讲到,可以自行查看。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值