task_struct 结构描述

本文出自于博客 http://blog.csdn.net/npy_lp/article/details/7292563



进程是处于执行期的程序以及它所管理的资源(如打开的文件、挂起的信号、进程状态、地址空间等等)的总称。注意,程序并不是进程,实际上两个或多个进程不仅有可能执行同一程序,而且还有可能共享地址空间等资源。

1.进程状态(State)
volatile long state;  
int exit_state;
state成员的可能取值如下:
#define TASK_RUNNING        0  
#define TASK_INTERRUPTIBLE  1  
#define TASK_UNINTERRUPTIBLE    2  
#define __TASK_STOPPED      4  
#define __TASK_TRACED       8   
#define EXIT_ZOMBIE     16  
#define EXIT_DEAD       32   
#define TASK_DEAD       64  
#define TASK_WAKEKILL       128  
#define TASK_WAKING     256

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

(1)可运行状态
处于这种状态的进程,要么正在运行、要么正准备运行。正在运行的进程就是当前进程 (由 current 宏  所指向的进程),而准备运行的进程只要得到CPU 就可以立即投入运行,CPU 是 这些进程唯一等待的系统资源。系统中有一个运行队列(run_queue),用来容纳所有处于可 运行状态的进程,调度程序执行时,从中选择一个进程投入运行。 当前运行进程一直处于该队列中,也就是说,current 总是指向运行队列中的某个元素,只是具体指向谁由调度程序决定。

(2)等待状态
处于该状态的进程正在等待某个事件(Event)或某个资源,它肯定位于系统中的某个 等待队列(wait_queue)中。Linux 中处于等待状态的进程分为两种:可中断的等待状态和 不可中断的等待状态。处于可中断等待态的进程可以被信号唤醒,如果收到信号,该进程就 从等待状态进入可运行状态,并且加入到运行队列中,等待被调度;而处于不可中断等待态 的进程是因为硬件环境不能满足而等待,例如等待特定的系统资源,它任何情况下都不能被 打断,只能用特定的方式来唤醒它,例如唤醒函数wake_up()等。

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

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

 2.进程调度信息


调度程序利用这部分信息决定系统中哪个进程最应该运行,并结合进程的状态信息保证系统运转的公平和高效。这一部分信息通常包括进程的类别(普通进程还是实时进程)、进程的优先级等,如表4.2 所示。

当need_resched 被设置时,在“下一次的调度机会”就调用调度程序schedule();counter 代表进程剩余的时间片,是进程调度的主要依据,也可以说是进程的动态优先级,因为这个值在不断地减少;nice 是进程的静态优先级,同时也代表进程的时间片,用于对counter 赋值,可以用nice()系统调用改变这个值;policy是适用于该进程的调度策略,实时进程和普通进程的调度策略是不同的;rt_priority 只对实时进程有意义,它是实时进程调度的依据。

进程的调度策略有3 种,如表4.3 所示。

只有root 用户能通过sched_setscheduler()系统调用来改变调度策略。
3.标识符(Identifiers)

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


在Linux系统中,一个线程组中的所有线程使用和该线程组的领头线程(该组中的第一个轻量级进程)相同的PID,并被存放在tgid成员中。只有线程组的领头线程的pid成员才会被设置为与tgid相同的值。注意,getpid()系统调用返回的是当前进程的tgid值而不是pid值。


4、标记

 flags成员的可能取值如下: 

#define PF_KSOFTIRQD    0x00000001  /* I am ksoftirqd */  
#define PF_STARTING 0x00000002  /* being created */  
#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   0x00
#define PF_KSOFTIRQD    0x00000001  /* I am ksoftirqd */  
#define PF_STARTING 0x00000002  /* being created */  
#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_USED_MATH    0x00002000  /* if unset the fpu must be initialized before use */  
#define PF_FREEZING 0x00004000  /* freeze in progress. do not account to load */  
#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_OOM_ORIGIN   0x00080000  /* Allocating much memory to others */  
#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_SPREAD_PAGE  0x01000000  /* Spread page cache over cpuset */  
#define PF_SPREAD_SLAB  0x02000000  /* Spread some slab caches over cpuset */  
#define PF_THREAD_BOUND 0x04000000  /* Thread bound to specific cpu */  
#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_FREEZER_NOSIG 0x80000000 /* Freezer won't send signals to it */ 


5、表示进程亲属关系的成员

struct task_struct *real_parent; /* real parent process */  
struct task_struct *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 */ 
在Linux系统中,所有进程之间都有着直接或间接地联系,每个进程都有其父进程,也可能有零个或多个子进程。拥有同一父进程的所有进程具有兄弟关系。


    real_parent指向其父进程,如果创建它的父进程不再存在,则指向PID为1的init进程。


    parent指向其父进程,当它终止时,必须向它的父进程发送信号。它的值通常与real_parent相同。


    children表示链表的头部,链表中的所有元素都是它的子进程。


    sibling用于把当前进程插入到兄弟链表中。


    group_leader指向其所在进程组的领头进程。

6、ptrace系统调用

unsigned int ptrace;  
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  

 成员ptrace被设置为0时表示不需要被跟踪,它的可能取值如下: 

/* linux-2.6.38.8/include/linux/ptrace.h */  
#define PT_PTRACED  0x00000001  
#define PT_DTRACE   0x00000002  /* delayed trace (used on m68k, i386) */  
#define PT_TRACESYSGOOD 0x00000004  
#define PT_PTRACE_CAP   0x00000008  /* ptracer can follow suid-exec */  
#define PT_TRACE_FORK   0x00000010  
#define PT_TRACE_VFORK  0x00000020  
#define PT_TRACE_CLONE  0x00000040  
#define PT_TRACE_


7、Performance Event:

#ifdef CONFIG_PERF_EVENTS  
    struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];  
    struct mutex perf_event_mutex;  
    struct list_head perf_event_list;  
#endif

Performance Event是一款随 Linux 内核代码一同发布和维护的性能诊断工具。这些成员用于帮助PerformanceEvent分析进程的性能问题。


8、进程地址空间 

   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;  
#endif

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


    brk_randomized的用法在http://lkml.indiana.edu/hypermail/Linux/kernel/1104.1/00196.html上有介绍,用来确定对随机堆内存的探测。


    rss_stat用来记录缓冲信息。 


    9、判断标志

int exit_code, exit_signal;  
int pdeath_signal;  /*  The signal sent when the parent dies  */  
/* ??? */  
unsigned int personality;  
unsigned did_exec:1;  
unsigned in_execve:1;   /* Tell the LSMs that the process is doing an 
             * execve */  
unsigned in_iowait:1;  
  
  
/* Revert to default priority/policy when forking */  
unsigned sched_reset_on_fork:1;


exit_code用于设置进程的终止代号,这个值要么是_exit()或exit_group()系统调用参数(正常终止),要么是由内核提供的一个错误代号(异常终止)。


    exit_signal被置为-1时表示是某个线程组中的一员。只有当线程组的最后一个成员终止时,才会产生一个信号,以通知线程组的领头进程的父进程。


    pdeath_signal用于判断父进程终止时发送信号。


    personality用于处理不同的ABI,它的可能取值如下:

[cpp] view plain copy
enum {  
    PER_LINUX =     0x0000,  
    PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,  
    PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,  
    PER_SVR4 =      0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,  
    PER_SVR3 =      0x0002 | STICKY_TIMEOUTS | SHORT_INODE,  
    PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS |  
                     WHOLE_SECONDS | SHORT_INODE,  
    PER_OSR5 =      0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,  
    PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,  
    PER_ISCR4 =     0x0005 | STICKY_TIMEOUTS,  
    PER_BSD =       0x0006,  
    PER_SUNOS =     0x0006 | STICKY_TIMEOUTS,  
    PER_XENIX =     0x0007 | STICKY_TIMEOUTS | SHORT_INODE,  
    PER_LINUX32 =       0x0008,  
    PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,  
    PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */  
    PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */  
    PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */  
    PER_RISCOS =        0x000c,  
    PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,  
    PER_UW7 =       0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,  
    PER_OSF4 =      0x000f,          /* OSF/1 v4 */  
    PER_HPUX =      0x0010,  
    PER_MASK =      0x00ff,  
};  



did_exec用于记录进程代码是否被execve()函数所执行。    in_execve用于通知LSM是否被do_execve()函数所调用。详见补丁说明:http://lkml.indiana.edu/hypermail/linux/kernel/0901.1/00014.html。    in_iowait用于判断是否进行iowait计数。    sched_reset_on_fork用于判断是否恢复默认的优先级或调度策略。

10、时间

cputime_t utime, stime, utimescaled, stimescaled;  
    cputime_t gtime;  
#ifndef CONFIG_VIRT_CPU_ACCOUNTING  
    cputime_t prev_utime, prev_stime;  
#endif  
    unsigned long nvcsw, nivcsw; /* context switch counts */  
    struct timespec start_time;         /* monotonic time */  
    struct timespec real_start_time;    /* boot based time */  
    struct task_cputime cputime_expires; 

utime/stime用于记录进程在用户态/内核态下所经过的节拍数(定时器)。prev_utime/prev_stime是先前的运行时间,请参考补丁说明http://lkml.indiana.edu/hypermail/linux/kernel/1003.3/02431.html。


    utimescaled/stimescaled也是用于记录进程在用户态/内核态的运行时间,但它们以处理器的频率为刻度。


    gtime是以节拍计数的虚拟机运行时间(guest time)。


    nvcsw/nivcsw是自愿(voluntary)/非自愿(involuntary)上下文切换计数。last_switch_count是nvcsw和nivcsw的总和。


   start_time和real_start_time都是进程创建时间,real_start_time还包含了进程睡眠时间,常用于/proc/pid/stat,补丁说明请参考http://lkml.indiana.edu/hypermail/linux/kernel/0705.0/2094.html。


    cputime_expires用来统计进程或进程组被跟踪的处理器时间,其中的三个成员对应着cpu_timers[3]的三个链表。

11、信号处理

/* 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_mask是这些信号的位掩码),notifier_data指的是notifier所指向的函数可能使用的数据。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值