本文内容概述:
1.进程的概念
2.进程控制块
3.剖析
Linux下的PCB—task_struct
说到task_struct,或许你是非常陌生的。如果我说他其实就是Linux下的对进程控制块PCB定义的一个结构体,你或许就会懂那么一点。下边开始今天分享的主题:
1.进程的概念:
说到进程控制块PCB,不得不说一下进程。在之前的
操作系统的课程学习中,给出的定义:进程是程序的一次动态的执行过程。(这样,你真的是能想明白吗?概念确实是比较抽象的,反正之前学习的时候我不是很清楚的)。进程=程序段+数据段+进程控制块。当我再次学习操作系统学习进程的时候,却有了更深层次的认识:
从操作系统的层次:进程是程序的一个执行实例;进程是正在执行的程序;进程是能分配处理机并且由处理机执行的实体。这么一说,没有正在执行的程序就一定不是进程吗?不是。假如在单处理机的系统中,一次只能执行一个进程(也就是说,一次只能有一个进程处于运行状态),那么其他的被加载到内存的程序(已经获得了除处理机之外的所需的全部资源),也是进程。
从内核的层次:担当分配系统资源(包括内存等)的实体。
进程的两个基本元素是程序代码(有可能被其他进程所共享)和与代码相关联的数据集。其实这里,与“进程=程序段+数据段+进程控制块 ”是一样的。数据集就是指的是数据段和进程控制块。
2.进程控制块:
为了描述进程的信息,我们引入了进程控制块这个
数据结构。那么,为什么需要进程控制块呢?它起着什么作用?
在单处理机系统,我们每次只能执行一个进程,我们如何知道是哪个进程在执行?执行完这个进程之后,又需要去执行哪些进程?假如一个进程由于种种原因,需要被中断(不是被杀死),那么之后再来执行此进程的时候,我们怎么会知道之前执行到哪(不可能从头开始执行),等等情形,所以就需要进程控制块。
通过分析以上的种种情况,我们得出:进程控制块至少应该包含进程标识(是进程的唯一标识,PID),还有进程的优先级,记录进程的上下文信息,记录进程下一次下一条指令的地址,进程中的程序的地址,等等(下文将会给出task_struct结构体的成员)。
当操作系统要调度某进程去执行时,要从该进程的PCB中查询进程的优先级和现行状态;
当系统调度到某个进程时,要根据PCB中保存的现行信息先去回复现场,然后再去修改进程的状态,根据程序的地址,找到程序的位置,并开始执行;
当进程由于某个原因需要暂停时,就必须将现行状态保存在PCB中,并记录下一条指令的地址。
可见,在进程的整个执行过程中,进程控制块都起着非常重要的作用。下边我们就来剖析Linux下的PCB—task_struct结构体。
3.剖析Linux下的PCB—task_struct
关于task_struct的定义, 位于/usr/include/linux/sched.h文件(centos6.5下)中。
下边我就结构体中的数据成员进行分类:
(1)进程的状态:
一个进程是执行状态还是睡眠状态还是阻塞状态,将在下边的成员中进行描述。
volatile long 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 //唤醒进程
(2)进程的唯一标识
pid_t pid;
pid_t tgid;
pid是进程的唯一表示,范围是0~32767,可以表示32768个进程。
在Linux系统中,一个线程组的所有线程使用和该线程组的领头线程相同的PID,并被存放在tgid成员中。(线程是程序运行的最小单位,进程是程序运行的基本单位。)
(3)进程的内核栈
void *stack;
Linux内核是通过以下的结构体来表示进程的内核栈:
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};
注明:关于内核栈,之后再来补充。
(4)进程的标记:
unsigned int flags;
#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */
#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_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_FLUSHER 0x00001000 /* responsible for disk writeback */
#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 freezeable */
#define PF_FREEZER_NOSIG 0x80000000 /* Freezer won't send signals to it */
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
(5)进程之间的亲属关系:
struct task_struct *real_parent;
struct task_struct *parent;
struct list_head children;
struct list_head sibling;
struct task_struct *group_leader;
real_parent指向其父进程,如果创建它的父进程不再存在,则指向PID为1的init进程。
parent指向其父进程,当它终止时,必须向它的父进程发送信号。它的值通常与 real_parent相同。
children表示链表的头部,链表中的所有元素都是它的子进程(进程的子进程链表)。
sibling用于把当前进程插入到兄弟链表中(进程的兄弟链表)。
group_leader指向其所在进程组的领头进程。
(6)进程调度信息:
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
unsigned int policy;
static_prio用于保存静态优先级,可以通过nice系统调用来进行修改。
rt_priority用于保存实时优先级。
normal_prio的值取决于静态优先级和调度策略。
prio用于保存动态优先级。
policy表示进程的调度策略,目前主要有以下五种:
#define SCHED_NORMAL 0//按照优先级进行调度(有些地方也说是CFS调度器)
#define SCHED_FIFO 1//先进先出的调度算法
#define SCHED_RR 2//时间片轮转的调度算法
#define SCHED_BATCH 3//用于非交互的处理机消耗型的进程
#define SCHED_IDLE 5//系统负载很低时的调度算法
#define SCHED_RESET_ON_FORK 0x40000000
(7) 时间数据成员:
cputime_t utime, stime, utimescaled, stimescaled;
cputime_t gtime;
cputime_t prev_utime, prev_stime;
unsigned long nvcsw, nivcsw;
struct timespec start_time;
struct timespec real_start_time;
unsigned long min_flt, maj_flt;
struct task_cputime cputime_expires;
struct list_head cpu_timers[3];
struct list_head run_list;
unsigned long timeout;
unsigned int time_slice;
int nr_cpus_allowed;
注明:关于进程的开始执行时间和真正开始执行时间,我认为:进程获得了除了处理机之外的所需的所有资源,它就进入了就绪状态,该时间就是进程的开始执行时间,也就是进入内存的时间。而真正开始时间是或得处理机开始执行的时间。这是本人的认识。
(8)信号处理信息
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
sigset_t saved_sigmask;
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
(9)文件系统信息
struct fs_struct *fs;
struct files_struct *files;
以下是对task_struct的定义及注释:
struct task_struct {
volatile long state;
unsigned long flags;
int sigpending;
mm_segment_t addr_limit;
volatile long need_resched;
int lock_depth;
long nice;
unsigned long policy;
struct mm_struct *mm;
int processor;
unsigned long cpus_runnable, cpus_allowed;
struct list_head run_list;
unsigned long sleep_time;
struct task_struct *next_task, *prev_task;
struct mm_struct *active_mm;
struct list_head local_pages;
unsigned int allocation_order, nr_local_pages;
struct linux_binfmt *binfmt;
int exit_code, exit_signal;
int pdeath_signal;
unsigned long personality;
int did_exec:1;
pid_t pid;
pid_t pgrp;
pid_t tty_old_pgrp;
pid_t session;
pid_t tgid;
int leader;
struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;
struct list_head thread_group;
struct task_struct *pidhash_next;
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit;
struct completion *vfork_done;
unsigned long rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_value;
struct timer_list real_timer;
struct tms times;
unsigned long start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1;
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups;
gid_t groups[NGROUPS];
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[16];
int link_count, total_link_count;
struct tty_struct *tty;
unsigned int locks;
struct sem_undo *semundo;
struct sem_queue *semsleeping;
struct thread_struct thread;
struct fs_struct *fs;
struct files_struct *files;
spinlock_t sigmask_lock;
struct signal_struct *sig;
sigset_t blocked;
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
u32 parent_exec_id;
u32 self_exec_id;
spinlock_t alloc_lock;
void *journal_info;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
注明:进程的调度策略有:先来先服务,短作业优先、时间片轮转、高响应比优先等等的调度
算法。