




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
进程管理一、FORK()函数的两次返回的具体情况对于fork来说,父子进程共享同一段代码空间,所以给人的感觉好像是有两次返回,其实对于调用 fork的父进程来说,如果fork出来的子进程没有得到调度,那么父进程从fork系统调用返回,同时分析sys_fork知道,fork返回的是子进 程的id。再看fork出来的子进程,由copy_process函数可以看出,子进程的返回地址为ret_from_fork(和父进程在同一个代码点 上返回),返回值直接置为0。所以当子进程得到调度的时候,也从fork返回,返回值为0。 关键注意两点:1.fork返回后,父进程或子进程的执行位置。(首先会将当前进程eax的值做为返回值)2.两次返回的pid存放的位置。(eax中) 进程调用copy_process得到lastpid的值(放入eax中,fork正常返回后,父进程中返回的就是lastpid) 子进程任务状态段tss的eax被设置成0, fork.c 中 p-tss.eax=0;(如果子进程要执行就需要进程切换,当发生切换时,子进程tss中的eax值就调入eax寄存器,子进程执行时首先会将eax的内容做为返回值) 当子进程开始执行时,copy_process返回eax的值。 fork()后,就是两个任务同时进行,父进程用他的tss,子进程用自己的tss,在切换时,各用各的eax中的值. 所以,“一次调用两次返回”是2个不同的进程! 例子:int main() pid_t pid; pid=fork(); if ( pid 0 stopped */ /-1 不能运行 0 运行 0 停止unsigned long flags; /* per process flags, defined below */进程标志,在下面定义int sigpending; /进程上是否有待处理的信号mm_segment_t addr_limit; /* thread address space:进程地址空间0-0xBFFFFFFF for user-thead0-0xFFFFFFFF for kernel-thread*/volatile long need_resched; /调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度int lock_depth; /* Lock depth */锁深度/* * offset 32 begins here on 32-bit platforms. We keep* all fields in a single cacheline that are needed for* the goodness() loop in schedule().*/ long counter; /进程可运行的时间量long nice; /进程的基本时间片unsigned long policy; /进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR;分时进程:SCHED_OTHER;struct mm_struct *mm; /进程内存管理信息int processor;/* * cpus_runnable is 0 if the process is not running on any* CPU. Its (1 father can be replaced with * p-p_pptr-pid)*/指针指向(原始的)父进程,孩子进程,比自己年轻的兄弟进程,比自己年长的兄弟进程/(p-father能被p-p_pptr-pid代替)struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;struct list_head thread_group; /线程链表/* PID hash table linkage. */进程散列表指针struct task_struct *pidhash_next; /用于将进程链入HASH表pidhashstruct task_struct *pidhash_pprev;wait_queue_head_t wait_chldexit; /* for wait4() */wait4()使用struct completion *vfork_done; /* for vfork() */ vfork() 使用unsigned long rt_priority; /实时优先级,用它计算实时进程调度时的weight值/it_real_value,it_real_incr用于REAL定时器,单位为jiffies。系统根据it_real_value /设置定时器的第一个终止时间。在定时器到期时,向进程发送SIGALRM信号,同时根据it_real_incr重置终止时间/it_prof_value,it_prof_incr用于Profile定时器,单位为jiffies。当进程运行时,不管在何种状态下,每个tick都使/it_prof_value值减一,当减到0时,向进程发送信号SIGPROF,并根据it_prof_incr重置时间/it_virt_value,it_virt_value用于Virtual定时器,单位为jiffies。当进程运行时,不管在何种状态下,每个tick都使/it_virt_value值减一,当减到0时,向进程发送信号SIGVTALRM,根据it_virt_incr重置初值。/Real定时器根据系统时间实时更新,不管进程是否在运行/Virtual定时器只在进程运行时,根据进程在用户态消耗的时间更新/Profile定时器在进程运行时,根据进程消耗的时(不管在用户态还是内核态)更新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_utimeNR_CPUS, per_cpu_stimeNR_CPUS; /记录进程在每个CPU上所消耗的用户态时间和核心态时间/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */内存缺页和交换信息:/min_flt, maj_flt累计进程的次缺页数(Copy onWrite页和匿名页)和主缺页数(从映射文件或交换设备读入的页面数);/nswap记录进程累计换出的页面数,即写到交换设备上的页面数。/cmin_flt, cmaj_flt, cnswap记录本进程为祖先的所有子孙进程的累计次缺页数,主缺页数和换出页面数。在父进程/回收终止的子进程时,父进程会将子进程的这些信息累计到自己结构的这些域中unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;int swappable:1; /表示进程的虚拟地址空间是否允许换出 /* process credentials */进程认证信息/uid,gid为运行该进程的用户的用户标识符和组标识符,通常是进程创建者的uid,gid /euid,egid为有效uid,gid/fsuid,fsgid为文件系统uid,gid,这两个ID号通常与有效uid,gid相等,在检查对于文件系统的访问权限时使用他们。/suid,sgid为备份uid,giduid_t uid,euid,suid,fsuid;gid_t gid,egid,sgid,fsgid;int ngroups; /记录进程在多少个用户组中gid_t groupsNGROUPS; /记录进程所在的组kernel_cap_t cap_effective, cap_inheritable, cap_permitted;/进程的权能,分别是有效位集合,继承位集合,允许位集合int keep_capabilities:1;struct user_struct *user;/* limits */struct rlimit rlimRLIM_NLIMITS; /与进程相关的资源限制信息unsigned short used_math; /是否使用FPUchar comm16; /进程正在运行的可执行文件名 /* file system info */文件系统信息int link_count, total_link_count;struct tty_struct *tty; /* NULL if no tty 进程所在的控制终端,如果不需要控制终端,则该指针为空*/unsigned int locks; /* How many file locks are being held */* ipc stuff */进程间通信信息struct sem_undo *semundo; /进程在信号灯上的所有undo操作struct sem_queue *semsleeping; /当进程因为信号灯操作而挂起时,他在该队列中记录等待的操作/* CPU-specific state of this task */进程的CPU状态,切换时,要保存到停止进程的task_struct中struct thread_struct thread;/* filesystem information文件系统信息*/struct fs_struct *fs;/* open file information */打开文件信息struct files_struct *files;/* signal handlers */信号处理函数spinlock_t sigmask_lock; /* Protects signal and blocked */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;/* Thread group tracking */u32 parent_exec_id;u32 self_exec_id;/* Protection of (de-)allocation: mm, files, fs, tty */spinlock_t alloc_lock;/* journalling filesystem info */void *journal_info;pid,这个值会被保存到eax中。这时子进程就产生了,此时子进程与父进程拥有相同的代码空间,程 序指针寄存器eip指向相同的下一条指令地址,当fork正常返回调用其的父进程后,因为eax中的值是新创建的子进程号,所以,fork()返回子进程 号,执行else(pid0);当产生进程切换运行子进程时,首先会恢复子进程的运行环境即装入子进程的tss任务状态段,其中的eax值 (copy_process中置为0)也会被装入eax寄存器,所以,当子进程运行时,fork返回的是0执行if(pid=0)。 先显示child process应该和内核机制有关,当fork一个新的进程后都会进行进程的重新调度,此时总是子进程先运行(和进程优先级有关?) 二、进程描述符linux进程描述符task_struct结构 为了管理进程,操作系统必须对每个进程所做的事情进行清楚地描述,为此,操作系统使用数据结构来代表处理不同的实体,这个数据结构就是通常所说的进程描述符或进程控制块,在linux系统中,这就是task_struct结构,在includelinuxsched.h文件中定义。每个进程都会被分配一个task_struct结构,它包含了这个进程的所有信息,在任何时候操作系统都能跟踪这个结构的信息,这个结构是linux内核汇总最重要的数据结构,下面我们会详细的介绍。这个结构的源代码及其注释如下,之后对其进行了分类解释。/进程描述符task_structstruct task_struct /* * offsets of these are hardcoded elsewhere - touch with care*/ volatile long state; /* -1 unrunnable, 0 runnable, 0 stopped */ /-1 不能运行 0 运行 0 停止unsigned long flags; /* per process flags, defined below */进程标志,在下面定义int sigpending; /进程上是否有待处理的信号mm_segment_t addr_limit; /* thread address space:进程地址空间0-0xBFFFFFFF for user-thead0-0xFFFFFFFF for kernel-thread*/volatile long need_resched; /调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度int lock_depth; /* Lock depth */锁深度/* * offset 32 begins here on 32-bit platforms. We keep* all fields in a single cacheline that are needed for* the goodness() loop in schedule().*/ long counter; /进程可运行的时间量long nice; /进程的基本时间片unsigned long policy; /进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR;分时进程:SCHED_OTHER;struct mm_struct *mm; /进程内存管理信息int processor;/* * cpus_runnable is 0 if the process is not running on any* CPU. Its (1 father can be replaced with * p-p_pptr-pid)*/指针指向(原始的)父进程,孩子进程,比自己年轻的兄弟进程,比自己年长的兄弟进程/(p-father能被p-p_pptr-pid代替)struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;struct list_head thread_group; /线程链表/* PID hash table linkage. */进程散列表指针struct task_struct *pidhash_next; /用于将进程链入HASH表pidhashstruct task_struct *pidhash_pprev;wait_queue_head_t wait_chldexit; /* for wait4() */wait4()使用struct completion *vfork_done; /* for vfork() */ vfork() 使用unsigned long rt_priority; /实时优先级,用它计算实时进程调度时的weight值/it_real_value,it_real_incr用于REAL定时器,单位为jiffies。系统根据it_real_value /设置定时器的第一个终止时间。在定时器到期时,向进程发送SIGALRM信号,同时根据it_real_incr重置终止时间/it_prof_value,it_prof_incr用于Profile定时器,单位为jiffies。当进程运行时,不管在何种状态下,每个tick都使/it_prof_value值减一,当减到0时,向进程发送信号SIGPROF,并根据it_prof_incr重置时间/it_virt_value,it_virt_value用于Virtual定时器,单位为jiffies。当进程运行时,不管在何种状态下,每个tick都使/it_virt_value值减一,当减到0时,向进程发送信号SIGVTALRM,根据it_virt_incr重置初值。/Real定时器根据系统时间实时更新,不管进程是否在运行/Virtual定时器只在进程运行时,根据进程在用户态消耗的时间更新/Profile定时器在进程运行时,根据进程消耗的时(不管在用户态还是内核态)更新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_utimeNR_CPUS, per_cpu_stimeNR_CPUS; /记录进程在每个CPU上所消耗的用户态时间和核心态时间/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */内存缺页和交换信息:/min_flt, maj_flt累计进程的次缺页数(Copy onWrite页和匿名页)和主缺页数(从映射文件或交换设备读入的页面数);/nswap记录进程累计换出的页面数,即写到交换设备上的页面数。/cmin_flt, cmaj_flt, cnswap记录本进程为祖先的所有子孙进程的累计次缺页数,主缺页数和换出页面数。在父进程/回收终止的子进程时,父进程会将子进程的这些信息累计到自己结构的这些域中unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;int swappable:1; /表示进程的虚拟地址空间是否允许换出 /* process credentials */进程认证信息/uid,gid为运行该进程的用户的用户标识符和组标识符,通常是进程创建者的uid,gid /euid,egid为有效uid,gid/fsuid,fsgid为文件系统uid,gid,这两个ID号通常与有效uid,gid相等,在检查对于文件系统的访问权限时使用他们。/suid,sgid为备份uid,giduid_t uid,euid,suid,fsuid;gid_t gid,egid,sgid,fsgid;int ngroups; /记录进程在多少个用户组中gid_t groupsNGROUPS; /记录进程所在的组kernel_cap_t cap_effective, cap_inheritable, cap_permitted;/进程的权能,分别是有效位集合,继承位集合,允许位集合int keep_capabilities:1;struct user_struct *user;/* limits */struct rlimit rlimRLIM_NLIMITS; /与进程相关的资源限制信息unsigned short used_math; /是否使用FPUchar comm16; /进程正在运行的可执行文件名 /* file system info */文件系统信息int link_count, total_link_count;struct tty_struct *tty; /* NULL if no tty 进程所在的控制终端,如果不需要控制终端,则该指针为空*/unsigned int locks; /* How many file locks are being held */* ipc stuff */进程间通信信息struct sem_undo *semundo; /进程在信号灯上的所有undo操作struct sem_queue *semsleeping; /当进程因为信号灯操作而挂起时,他在该队列中记录等待的操作/* CPU-specific state of this task */进程的CPU状态,切换时,要保存到停止进程的task_struct中struct thread_struct thread;/* filesystem information文件系统信息*/struct fs_struct *fs;/* open file information */打开文件信息struct files_struct *files;/* signal handlers */信号处理函数spinlock_t sigmask_lock; /* Protects signal and blocked */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;/* Thread group tracking */u32 parent_exec_id;u32 self_exec_id;/* Protection of (de-)allocation: mm, files, fs, tty */spinlock_t alloc_lock;/* journalling filesystem info */void *journal_info;三、Linux内核2.6和2.4中内核堆栈的比较在内核2.4中堆栈是这么定义的:union task_union struct task_struct task;unsigned long stackINIT_TASK_SIZE/sizeof(long); ;而INIT_TASK_SIZE只能是8K。内核为每个进程分配一个task_struct结构时,实际上分配两个连续的物理页面(8192字节),如图所示。底部用作task_struct结构(大小约为1K字节),结构的上面用作内核堆栈(大小约为7K字节)。访问进程自身的task_struct结构,使用宏操作current, 在2.4中定义如下:#define current get_current()static inline struct task_struct * get_current(void) struct task_struct *current; _asm_(andl %esp,%0; :=r (current) : (8191UL); return current;8191UL表示最低13位为0, 其余位全为1。 %esp指向内核堆栈中,当屏蔽掉%esp的最低13后,就得到这个”两个连续的物理页面”的开头,而这个开头正好是task_struct的开始,从而得到了指向task_struct的指针。在内核2.6中堆栈这么定义:union thread_union struct thread_info thread_info; unsigned long stackTHREAD_SIZE/sizeof(long);根据内核的配置,THREAD_SIZE既可以是4K字节(1个页面)也可以是8K字节(2个页面)。thread_info是52个字节长。下图是当设为8KB时候的内核堆栈:Thread_info在这个内存区的开始处,内核堆栈从末端向下增长。进程描述符不是在这个内存区中,而分别通过task与thread_info指针使thread_info与进程描述符互联。所以获得当前进程描述符的current定义如下:#define current get_current()static inline struct task_struct * get_current(void) return current_thread_info()-task;static inline struct thread_info *current_thread_info(void) struct thread_info *ti; _asm_(andl %esp,%0; :=r (ti) : (THREAD_SIZE - 1); return ti; 根据THREAD_SIZE大小,分别屏蔽掉内核栈的12-bit LSB(4K)或13-bit LSB(8K),从而获得内核栈的起始位置。struct thread_info struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ unsigned long flags; /* low level flags */ unsigned long status; /* thread-synchronous flags */ . .四、进程内核栈每个进程都有自己的内核栈。当进程从用户态进入内核态时,CPU就自动地设置该进程的内核栈,也就是说,CPU从任务状态段TSS中装入内核栈指针esp(参见下一章的进程切换一节)。X86内核栈的分布如图4.2所示:0x018fbfff 堆栈 0x018fb000esptask_struct0x018fa000p 图4.2 内核栈的分布图 在Intel系统中,栈起始于末端,并朝这个内存区开始的方向增长。从用户态刚切换到内核态以后,进程的内核栈总是空的,因此,esp寄存器直接指向这个内存区的顶端。 在图4.2中,从用户态切换到内核态后,esp寄存器包含的地址为0x018fc00。进程描述符存放在从0x015fa00开始的地址。只要把数据写进栈中,esp的值就递减。在include/linux/sched.h中定义了如下一个联合结构: union task_union struct task_struct task; unsigned long stack2408; 从这个结构可以看出,内核栈占8kb的内存区。实际上,进程的task_struct结构所占的内存是由内核动态分配的,更确切地说,内核根本不给task_struct分配内存,而仅仅给内核栈分配8K的内存,并把其中的一部分给task_struct使用。 task_struct结构大约占1K字节左右,其具体数字与内核版本有关,因为不同的版本其域稍有不同。因此,内核栈的大小不能超过7K,否则,内核栈会覆盖task_struct结构,从而导致内核崩溃。不过,7K大小对内核栈已足够。把task_struct结构与内核栈放在一起具有以下好处: 内核可以方便而快速地找到这个结构,用伪代码描述如下:task_struct = (struct task_struct *) STACK_POINTER & 0xffffe000 避免在创建进程时动态分配额外的内存 task_struct结构的起始地址总是开始于页大小(PAGE_SIZE)的边界。五、linux进程管理之进程的退出在进程运行结束后,我们会显示的调用exit()或者return退出正在运行的进程,如果调用return的话,编译器会自己加上exit().此时,保存子进程的一部份信息是很有必要的,因为父进程可以读取这些消息而取得子进程的退出状态.如果子进程退出.但父进程没有用wait(),这就成为了我们常说的僵尸进程,exit()系统调用在内核中的相应接口为sys_exit(),我们来跟踪一下,看下内核是如何处理这个过程的,fastcall NORET_TYPE void do_exit(long code) struct task_struct *tsk = current; int group_dead; /选择编译函数 profile_task_exit(tsk); WARN_ON(atomic_rea
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 房屋 公租 合同范本
- 广场饭店合同范本
- 重庆江津购房合同范本
- 民房混凝土施工合同范本
- 地豇豆订购合同范本
- 电源供应合同范本
- 就业协议合同范本简约
- 天下租房合同范本
- 舞蹈电子培训合同范本
- 足浴店监工合同范本
- 植物生物技术概论
- 食品委托加工协议书范文6篇
- 充电桩检定培训课件
- 2025年黑龙江省哈尔滨市南岗区事业单位招聘考试卫生类医学检验专业知识试卷
- 人社法律法规知识竞赛考试题及答案
- 2025年青海省中考英语试卷真题(含答案及解析)
- NB/T 11636-2024煤矿用芳纶织物芯阻燃输送带
- 法官培训人民调解员讲稿
- 2025贵州航空产业城集团股份有限公司旗下子公司贵州安立航空材料有限公司面向社会招聘61人笔试历年参考题库附带答案详解
- 静脉留置针输液技术课件
- 2025至2030伸缩梯行业产业运行态势及投资规划深度研究报告
评论
0/150
提交评论