作者: sunmoon 在linux 中每一个进程都由task_struct 数据结构来定义 task_struct就是我们通常所说的PCB 她是对进程控制的唯一手段也是最有效的手段 当我们调用fork() 时 系统会为我们产生一个task_struct结构然后从父进程那里继承一些数据 并把新的进程插入到进程树中 以待进行进程管理因此了解task_struct的结构对于我们理解任务 调度(在linux 中任务和进程是同一概念)的关键在进行剖析task_struct的定义之前 我们先按照 我们的理论推一下它的结构 进程状态 将纪录进程在等待运行或死锁 调度信息 由哪个调度函数调度怎样调度等 进程的通讯状况 因为要插入进程树必须有联系父子兄弟的指针 当然是task_struct型 时间信息 比如计算好执行的时间 以便cpu 分配 标号 决定改进程归属 可以读写打开的一些文件信息 进程上下文和内核上下文 处理器上下文 内存信息 因为每一个PCB都是这样的 只有这些结构 才能满足一个进程的所有要求 打开/include/linux/schedh 找到task_struct 的定义 struct task_struct { /* these are hardcoded dont touch */ 这里是一些硬件设置对程序原来说是透明的 其中state 说明了该进程是否可以执行 还是可中断等信息 Flage 是进程号 在调用 fork() 时给出addr_limit 是区分内核进程 与普通进程在内存存放的位置不同 volatile long state; /* unrunnable runnable > stopped */ unsigned long flags; /* per process flags defined below */ int sigpending; mm_segment_t addr_limit; /* thread address space: xBFFFFFFF for userthead xFFFFFFFF for kernelthread */ 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:; int did_exec:; 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 wait() 等待队列 */ 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 mmspecific or threadspecific */ 内存信息 unsigned long min_flt maj_flt nswap cmin_flt cmaj_flt cnswap; int swappable:; /* process credentials */ uid_t uideuidsuidfsuid; gid_t gidegidsgidfsgid; 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[]; /* 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 中用的常量在那里定义呢 如最大进程个数 最多支持的cpu 个数等等 在调用fork() 时 系统是分配一块内存 会是这样么 malloc(sizeof(struct task_struck)) 拷贝一些变量还是和服进程公用一部分内存malloc 函数怎么实现(在内存管理那一部分但此处 我认为不能不想) 对于线程来说 又如何实现呢? 调度策略函数 schedul() 有几种形势 时间片轮转 抢占式优先级抢占式 多级反馈制除了时间片轮转外都要对进程树 进行遍历(对于实时进程 的fifo机制不用)linux 是怎样保证了高效呢?如果把最大线成数修改 效率会不会降低 进程通讯用到的管道信号结构如何 待续 |