上回我们说到了常用的操作系统进程调度算法,学过操作系统的同学应该都知道操作系统的四大职能:进程管理、内存管理、设备管理以及文件系统的管理。
那么最重要的职能之一:进程管理,是如何进行的呢?首先在要管理一个进程的时候,我们需要知道某个进程的具体信息,比如进程的PID、优先级等等,所以我们就需要一个结构体来保存这些信息,在Linux中这个结构体就是task_struct,也就是我们平常所说的PCB(进程控制块)。当我们用fork创建一个子进程的时候,就会新产生一个task_struct结构体,新创建的进程会从父进程哪里继承一些信息,所有的这些信息就会被保存在task_struct里,因此了解task_struct的结构对于我们学习进程的的调度是非常关键的。
按照我们对进程的了解,可以推论出来一个task_struct中大概包括以下信息:
①标识符:表示一个进程的唯一标识符,来区别其他进程
②状态:任务状态,退出代码,退出信号等
③并行:推进代码,多个同时进行
④优先级:(与权限区别)
⑤硬件上下文:cpu在切换进程之前保存当前进程的信息,下次加载该进程的时候,又可以回到上次的状态,该信息保存在PCB里面,可因此PCB里面应该保存硬件上下文信息
⑥I/O状态:包括处理器时间的总和,使用时钟数总和等
⑦记账信息:
⑧程序计数器:程序中即将要执行的下一条指令的地址,实际是一个CPU 寄存器
⑨内存指针:程序代码和进程相关数据的信息指针,还有和其他进程共享的内存块的指针,找到目标程序的代码和数据。
打开/include/linux/sched.h 找到task_struct 的定义
struct task_struct
{ /* these are hardcoded - don't touch */ 这里是一些硬件设置对程序原来说是透明的.其中state说明了该进程是否可以执行,还是可中断等信息.Flage是进程号,在调用fork()时给出,addr_limit是区分内核进程与普通进程在内存存放的位置不同
volatile long state; /* -1 unrunnable,未运行状态, 0 runnable 运行状态, >0 stopped 停止运行状态 */
unsigned long flags; /* per process flags, defined below */ int sigpending;
mm_segment_t addr_limit; /* thread address space: 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */
struct exec_domain *exec_domain;
long need_resched;
/* various fields */ count是计数器,priorrity是优先级
long counter;
long priority;
cycles_t avg_slice;
/* SMP and runqueue state */ 为多处理机定义的变量.
int has_cpu;
int processor;
int last_processor;
int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */
为了在进程树中排序, 定义的父子,兄弟指针
struct task_struct *next_task, *prev_task;
struct task_struct *next_run, *prev_run;
/* task state */ 定义可 task 运行的状态, 以及信号
struct linux_binfmt *binfmt;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */ /* 定义可进程的用户号,用户组以及进程组*/
unsigned long personality;
int dumpable:1;
int did_exec:1;
pid_t pid;
pid_t pgrp;
pid_t tty_old_pgrp;
pid_t session;
/* boolean value for session group leader */
是不是进程组的头文件
int leader;
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with * p->p_pptr->pid)
*/
父子进程的一些指针
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
/* PID hash table linkage. */ 在调度中用的一些hash 表
struct task_struct *pidhash_next;
struct task_struct **pidhash_pprev;
/* Pointer to task[] array linkage. */
struct task_struct **tarray_ptr;
struct wait_queue *wait_chldexit; /* for wait4() 等待队列 */ struct semaphore *vfork_sem; /* for vfork() */
unsigned long policy, rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
进程的性质因为实时进程与普通进程的调度算法不一样所以应有变量区分
下面是进程的一些时间信息
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
struct tms times;
unsigned long start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];定义了时间片的大小
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
内存信息
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; int swappable:1;
/* process credentials */
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;
struct user_struct *user;
以下英文注释很清楚
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
char comm[16]; /* file system info */
int link_count;
struct tty_struct *tty; /* NULL if no tty */
/* ipc stuff */
struct sem_undo *semundo;
struct sem_queue *semsleeping;
/* tss for this task */
struct thread_struct tss;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* memory management info */
struct mm_struct *mm;
/* signal handlers */
spinlock_t sigmask_lock;
/* Protects signal and blocked */
struct signal_struct *sig; sigset_t signal, blocked;
struct signal_queue *sigqueue, **sigqueue_tail;
unsigned long sas_ss_sp;
size_t sas_ss_size;
};
以上就是task_struct的大概信息了,可能还有些地方我解释的不够详细,欢迎各位小伙伴来补充~