Linux2.6.32 PCB内tast_struct的简述

linux下的PCB定义 (centos)

本分类下文章大多整理自《深入分析linux内核源代码》一书。如果想深入了解请下载该书,深入理解。在看此片博文前,如若对操作系统不甚了解的同学,须提前了解相关知识。首先,我们来了解一下什么叫task_struct;Linux中的每个进程由一个task_struct数

一 task_struct 结构描述

1.进程调度信息

调度程序利用这部分信息决定系统中哪个进程最应该运行,并结合进程的状态信息保证系统运转的公平和高效。这一部分信息通常包括进程的类别(普通进程还是实时进程)、进程的优先级等
进程状态:
R running 可运行状态
S sleeping 可中断睡眠状态
D disk sleep 不可中断的休眠状态 常规的方法不能终止(关机重启) 通常会等待I/O的结束
T stoppod
t tracing stop 可追踪状态
X dead
Z zombie 僵尸状态(占资源,代码执行完毕,维护状态等待检查 需要被回收)

(1)可运行状态

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

(2)等待状态

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

(3)暂停状态

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

(4)僵死状态

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

2.进程调度信息

调度程序利用这部分信息决定系统中哪个进程最应该运行,并结合进程的状态信息保证系统运转的公平和高效。这一部分信息通常包括进程的类别(普通进程还是实时进程)、进程的优先级等
当need_resched 被设置时,在“下一次的调度机会”就调用调度程序schedule();
Counter 代表进程剩余的时间片,是进程调度的主要依据,也可以说是进程的动态优先级,因为这个值在不断地减少;
Nice 是进程的静态优先级,同时也代表进程的时间片,用于对Counter 赋值,可以用nice()系统调用改变这个值;
Policy是适用于该进程的调度策略,实时进程和普通进程的调度策略是不同的;
rt_priority 只对实时进程有意义,它是实时进程调度的依据。

3.标识符(Identifiers)

4.进程通信有关信息(IPC,Inter_Process Communication)

为了使进程能在同一项任务上协调工作,进程之间必须能进行通信即交流数据。Linux 支持多种不同形式的通信机制。它支持典型的UNIX 通信机制(IPC Mechanisms):信号(Signals)、管道(Pipes),也支持System V / Posix 通信机制:共享内存(Shared Memory)、信号量和消息队列(Message Queues)

5.虚拟内存信息(Virtual Memory)

除了内核线程(Kernel Thread),每个进程都拥有自己的地址空间(也叫虚拟空间),用mm_struct 来描述。另外Linux 2.4 还引入了另外一个域active_mm,这是为内核线程而引入的。因为内核线程没有自己的地址空间,为了让内核线程与普通进程具有统一的上下文切换方式,当内核线程进行上下文切换时,让切换进来的线程的active_mm 指向刚被调度出去的进程的mm_struct。

6.内核线程

内核线程(kernel thread)
这类线程周期性被内核唤醒和调度,主要用于实现系统后台操作,如页面对换,刷新磁盘缓存,网络连接等系统工作。
• 内核线程执行的是内核中的函数,而普通进程只有通过系统调用才能执行内核中的函数。
• 内核线程只运行在内核态,而普通进程既可以运行在用户态,也可以运行在内核态。
• 因为内核线程指只运行在内核态,因此,它只能使用大于PAGE_OFFSET(3G)的地址空间。另一方面,不管在用户态还是内核态,普通进程可以使用4GB 的地址空间

7.等待队列

进程必须经常等待某些事件的发生,例如,等待一个磁盘操作的终止,等待释放系统资源或等待时间走过固定的间隔。等待队列实现在
事件上的条件等待,也就是说,希望等待特定事件的进程把自己放进合适的等待队列,并放弃控制权。因此,等待队列表示一组睡眠的进程,当某一条件变为真时,由内核唤醒它们。等待队列由循环链表实现。

8.运行队列

当内核要寻找一个新的进程在CPU 上运行时,必须只考虑处于可运行状态的进程(即在TASK_RUNNING 状态的进程),因为扫描整个进程链表是相当低效的,所以引入了可运行状态进程的双向循环链表,也叫运行队列(run queue)。
该队列通过task_struct 结构中的两个指针run_list 链表来维持。队列的标志有两个:一个是“空进程”idle_task;一个是队列的长度,,也就是系统中处于可运行状态(TASK_RUNNING)的进程数目,用全局整型变量nr_running 表示。

代码块

    struct task_struct {  
    volatile long state;   
     /* -1 unrunnable, 0 runnable, >0 stopped */  
    void *stack;    
    //stack should points to a threadinfo struct  
    atomic_t usage; 
    //有几个进程正在使用该结构  
    unsigned int flags; 
    /* per process flags, defined below */
    //反应进程状态的信息,但不是运行状态  
    unsigned int ptrace;  

#ifdef CONFIG_SMP  
    struct task_struct *wake_entry;  
    int on_cpu;   //在哪个CPU上运行  
#endif  
    int on_rq;  //on_rq denotes whether the entity is currently scheduled on a run queue or not.  


    int prio, static_prio, normal_prio;  //静态优先级,动态优先级  
/* 
the task structure employs three elements to denote the priority of a process: prio 
and normal_prio indicate the dynamic priorities, static_prio the static priority of a process. 
The static priority is the priority assigned to the process when it was started. It can be modified 
with the nice and sched_setscheduler system calls, but remains otherwise constant during the 
process’ run time. 
normal_priority denotes a priority that is computed based on the static priority and the 
scheduling policy of the process. Identical static priorities will therefore result in different 
normal priorities depending on whether a process is a regular or a real-time process. When a 
process forks, the child process will inherit the normal priority. 
However, the priority considered by the scheduler is kept in prio. A third element is required 
because situations can arise in which the kernel needs to temporarily boost the priority of a pro- 
cess. Since these changes are not permanent, the static and normal priorities are unaffected by 
this. 
*/  
    unsigned int rt_priority;  //实时任务的优先级  
    const struct sched_class *sched_class;  //与调度相关的函数  
    struct sched_entity se; //调度实体  
    struct sched_rt_entity rt; //实时任务调度实体  

#ifdef CONFIG_PREEMPT_NOTIFIERS  
    /* list of struct preempt_notifier: */  
    struct hlist_head preempt_notifiers; //与抢占有关的  
#endif  

    /* 
     * fpu_counter contains the number of consecutive context switches 
     * that the FPU is used. If this is over a threshold, the lazy fpu 
     * saving becomes unlazy to save the trap. This is an unsigned char 
     * so that after 256 times the counter wraps and the behavior turns 
     * lazy again; this to deal

你可能感兴趣的:(Linux系统编程,linux,PCB)