linux源代码分析与研究.pdf
第 1 章 引言 Linux 是一种能运行于多种平台、源代码公开、免费、功能强大、遵守 POSIX标准、与 UNIX 兼容的操作系统。Linux 最初版本是由 Linus Benedict Torvalds 编写的,为了能够使 Linux 更加完善,Torvalds在网络上公开了Linux的源码,邀请全世界的志愿者来参与Linux的开发。在这些无私的人们的帮助下,Linux 得到不断的完善,并在短时期内迅速崛起。现在,Linux 内核已经发展到了 2.5.X 版,并还在以相当快的速度不断地发展着。据报道,它是一个很有发展前途的操作系统,也是为数不多可以与 Microsoft旗下操作系统相竞争的操作系统。我国的 IT 产业起步较晚,技术落后于西方经济发达国家。在我国,由于受知识产权的限制,无论是使用 PC 平台上的 Windows,还是使用应用于大中型机的UNIX,都无法窥视到其内部结构。这些系统很可能存在不为我们所知的漏洞,如果这些漏洞为别有用心者所利用,将会严重危及我国的经济安全和国家安全。操作系统不同于其它软件产品,它是其它应用程序得以运行的平台,应用软件的开发必须基于对相应平台(操作系统)的技术的理解和掌握。由于我们的软件企业无法获知这些系统的细节,根本无法与拥有这些关键技术的国外先进企业相抗衡,长此以往,将会对我国软件产业产生深远的负面影响。为了打破这种受制于人的局面,我国迫切的需要开发一个具有自主知识产权的操作系统。由于 Linux 性能优越,属于自由软件,公开源代码且完全免费,所以拿来作发展自主知识产权的操作系统的底版是非常合适的选择。只有完全了解当前Linux 的实现细节,才能在它的基础上作进一步的开发和完善。因此,分析 Linux源代码对于在Linux现有的基础上开发我们自己的Linux就具有非常现实和重要的意义。本论文主要在源码水平上讨论 Linux 内核进程调度与控制的实现,其目的是通过对源码的分析与研究,找出Linux在本论文研究方向上的优缺点,作为今后Linux系统开发的参考。1 第 2 章 Linux 内核的整体结构 Linux 内核由 5 个主要的子系统组成。这 5 个子系统分别是进程调度(SCHED)、内存管理(MM)、虚拟文件系统(Virtual File System,VFS)、网络接口(NET)和进程间通信(IPC)。进程调度控制着进程对 CPU 的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际是仅等待 CPU 资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux 使用了比较简单的基于优先级的进程调度算法选择新的进程。内存管理允许多个进程安全地共享主内存区域。Linux 的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只将当前使用的程序块保留在内存中,其余的程序块则保留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换程序块。内存管理从逻辑上可以分为硬件无关的部分和硬件相关的部分。硬件无关的部分提供了进程的映射和虚拟内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。虚拟文件系统隐藏了各种不同硬件的具体细节,为所有设备提供了统一的接口,虚拟文件系统还支持多达数十种不同的文件系统,这也是 Linux 较有特色的部分。虚拟文件系统可分为逻辑文件系统和设备驱动程序。逻辑文件系统指 Linux所支持的文件系统,如 ext2、fat 等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。网络接口提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序两部分。网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备进行通信,每一种可能的硬件设备都有相应的设备驱动程序。进程间通信支持进程间各种通信机制。下图显示了上述五个子系统之间的关系:2 虚拟文件系统虚拟文件系统逻辑文件系统硬件驱动程序内存管理内存管理硬件无关硬件相关网络网络网络协议硬件驱动程序进程调度进程调度进程间通信进程间通信 各个子系统之间的依赖关系如下:1 进程调度与内存管理之间的关系:这两个子系统互相依赖。在多道程序环境下,程序要运行必须为之创建进程,而创建进程的第一件事,就是要将程序和数据装入内存。2 进程间通信与内存管理之间的关系:进程间通信子系统要依赖内存管理支持共享内存通信机制,这种机制允许两个进程除了拥有自己的私有内存,还可存取共同的内存区域。3 虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络文件系统(NFS),也利用内存管理支持 RAMDISK 设备。4 内存管理与虚拟文件系统之间的关系:内存管理利用虚拟文件系统支持交换,交换进程定期地由调度程序调度,这也是内存管理依赖于进程调度的唯一原因。当一个进程存取的内存映射被换出时,内存管理向文件系统发出请求,同时,挂起当前当前正在运行的进程。在这些子系统中,进程调度子系统是其他子系统得以顺利工作的关键。无论是文件系统的系统进程还是网络子系统的服务进程都需要通过进程调度来获得相应的 CPU 时间以正常运行。3第 3 章 Linux 进程调度 3.1 相关概念简述 3.1.1Linux 进程的四个要素 一般来说 Linux 系统的进程都具备下列诸要素:(1)有一段程序供其执行。这段程序不一定是某个进程所专有,可以与其他进程共用。(2)有进程专用的内核空间堆栈。(3)在内核中有一个 task_struct 数据结构,即通常所说的“进程控制块”。有了这个数据结构,进程才能成为内核调度的一个基本单位接受内核的调度。同时,这个结构还记录着进程所占用的各项资源。(4)有独立的存储空间,这意味着拥有专有的用户空间;进一步,还意味着除前述的内核空间堆栈外还有其专用的用户空间堆栈。有一点必须指出,内核空间是不能独立的,任何进程都不可能直接(不通过系统调用)改变内核空间的内容(除其本身的内核空间堆栈以外)。这四条都是必要条件,缺了任何一条都不能成为“进程”。如果只具备了前三条而缺第四条,就称为“线程”。如果完全没有用户空间,就称为“内核线程”(kernel thread);而如果共享用户空间则称为“用户线程”。二者往往都简称“线程”。事实上,在 Linux 系统中,进程和线程的区分并不十分严格,许多进程在“诞生”之初都与其父进程共用同一个存储空间,所以严格说来还是线程;但是子进程可以建立其自己的存储空间,并与父进程分离,成为真正意义上的进程。3.1.2 task_struct 结构描述 task_struct结构是向系统表明进程存在的唯一凭证,它包含了进程的全部信息。同时,也是进程为实现操作而取得必要资源的唯一途径。下面列出了 task_struct结构的全部源码,在源码后面有对 task_struct 结构(参见 includelinuxsched.h)各数据项的分类解释:struct task_struct /*these are hardcoded-dont touch*/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-0 xBFFFFFFF for user-thead 0-0 xFFFFFFFF for kernel-thread */struct exec_domain*exec_domain;long need_resched;4/*various fields*/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 list_head run_list;/*task state*/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.*/struct task_struct*pidhash_next;struct task_struct*pidhash_pprev;wait_queue_head_t 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;5 struct timer_list real_timer;struct tms times;unsigned long start_time;long per_cpu_utimeNR_CPUS,per_cpu_stimeNR_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 groupsNGROUPS;kernel_cap_t cap_effective,cap_inheritable,cap_permitted;struct user_struct*user;/*limits*/struct rlimit rlimRLIM_NLIMITS;unsigned short used_math;char comm16;/*file system info*/int link_count;struct tty_struct*tty;/*NULL if no tty*/*ipc stuff*/struct sem_undo*semundo;struct sem_queue*semsleeping;/*CPU-specific state of this task*/struct thread_struct thread;/*filesystem information*/struct fs_struct*fs;/*open file information*/struct files_struct*files;/*memory management info*/struct mm_struct*mm,*active_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;1.调度数据成员 6(1)(1)volatile long states;volatile long states;表示进程的当前状态:TASK_RUNNING:正在运行或在就绪队列 run-queue 中准备运行的进程,实际参与进程调度。TASK_INTERRUPTIBLE:处于等待队列中的进程,待资源有效时唤醒,也可由其它进程通过信号(signal)或定时中断唤醒后进入就绪队列 run-queue。TASK_UNINTERRUPTIBLE:处于等待队列中的进程,待资源有效时唤醒,不可由其它进程通过信号(signal)或定时中断唤醒。TASK_ZOMBIE:表示进程结束但尚未消亡的一种状态(僵死状态)。此时,进程已经结束运行且释放大部分资源,但尚未释放进程控制块。TASK_STOPPED:进程被暂停,通过其它进程的信号才能唤醒。导致这种状态的原因有二,或者是对收到 SIGSTOP、SIGSTP、SIGTTIN 或 SIGTTOU信号的反应,或者是受其它进程的 ptrace 系统调用的控制而暂时将 CPU 交给控制进程。TASK_SWAPPING:进程页面被交换出内存的进程。(2)(2)unsigned long flags;unsigned long flags;进程标志:PF_ALIGNWARN 打印“对齐”警告信息。PF_PTRACED 被 ptrace 系统调用监控。PF_TRACESYS 正在跟踪。PF_FORKNOEXEC 进程刚创建,但还没执行。PF_SUPERPRIV 超级用户特权。PF_DUMPCORE dumped core。PF_SIGNALED 进程被信号(signal)杀出。PF_STARTING 进程正被创建。PF_EXITING 进程开始关闭。PF_USEDFPU 该进程使用 FPU(SMP only)。PF_DTRACE delayed trace(used on m68k)。(3)(3)long priority;long priority;进程优先级。Priority 的值给出进程每次获取 CPU 后可使用的时间(按jiffies 计)。优先级可通过系统调用 sys_setpriorty 改变(在 kernel/sys.c 中)。(4)(4)unsigned long rt_priority;unsigned long rt_priority;rt_priority给出实时进程的优先级,rt_priority+1000给出进程每次获取CPU后可使用的时间(同样按 jiffies 计)。实时进程的优先级可通过系统调用sys_sched_setscheduler()改变(见 kernel/sched.c)。(5)(5)long counter;long counter;在轮转法调度时表示进程当前还可运行多久。在进程开始运行是被赋为priority 的值,以后每隔一个 tick(时钟中断)递减 1,减到 0 时引起新一轮调度。重新调度将从 run_queue 队列选出 counter 值最大的就绪进程并给予 CPU 使用权,因此 counter 起到了进程的动态优先级的作用(priority 则是静态优先级)。(6)(6)unsigned long policy;unsigned long policy;该进程的进程调度策略,可以通过系统调用 sys_sched_setscheduler()更改(见 kernel/sched.c)。调度策略有:SCHED_OTHER 0 非实时进程,基于优先权的轮转法(round robin)。7SCHED_FIFO 1 实时进程,用先进先出算法。SCHED_RR 2 实时进程,用基于优先权的轮转法。2.信号处理(1)(1)unsigned long signal;unsigned long signal;进程接收到的信号。每位表示一种信号,共 32 种。置位有效。(2)(2)unsigned long blocked;unsigned long blocked;进程所能接受信号的位掩码。置位表示屏蔽,复位表示不屏蔽。(3)(3)struct signal_struct*sig;struct signal_struct*sig;因为 signal 和 blocked 都是 32 位的变量,Linux 最多只能接受 32 种信号。对每种信号,各进程可以由 PCB 的 sig 属性选择使用自定义的处理函数,或是系 统 的 缺 省 处 理 函 数。指 派 各 种 信 息 处 理 函 数 的 结 构 定 义 在include/linux/sched.h 中。对信号的检查安排在系统调用结束后,以及“慢速型”中断服务程序结束后(IRQ#_interrupt(),参见 9。5 节“启动内核”)。3.进程队列指针(1)(1)struct task_struct*next_task,*prev_task;struct task_struct*next_task,*prev_task;所有进程(以 PCB 的形式)组成一个双向链表。next_task 和就是链表的前后指针。链表的头和尾都是 init_task(即 0 号进程)。(2)(2)struct task_struct*next_run,*prev_run;struct task_struct*next_run,*prev_run;由正在运行或是可以运行的,其进程状态均为 TASK_RUNNING 的进程所组成的一个双向循环链表,即 run_queue 就绪队列。该链表的前后向指针用next_run 和 prev_run,链表的头和尾都是 init_task(即 0 号进程)。(3)(3)struct task_struct*p_opptr,*p_pptr;和 struct task_struct*p_cptr,*p_ysptr,*p_osptr;struct task_struct*p_opptr,*p_pptr;和 struct task_struct*p_cptr,*p_ysptr,*p_osptr;以上分别是指向原始父进程(original parent)、父进程(parent)、子进程(youngest child)及新老兄弟进程(younger sibling,older sibling)的指针。相关的操作宏参见 kenerl/linux/sched.h。它们之间的关系见下图:父子进程间的关系父子进程间的关系父进程父进程子进程子进程最老的子进程最老的子进程最新的子进程最新的子进程p_cptrp_pptrp_osptrp_ysptrp_osptrp_pptrp_ysptrp_pptr 4.进程标识(1)(1)unsigned short uid,gid;unsigned short uid,gid;uid 和 gid 是运行进程的用户标识和用户组标识。(2)(2)int groupsNGROUPS;int groupsNGROUPS;与多数现代 UNIX 操作系统一样,Linux 允许进程同时拥有一组用户组号。8在进程访问文件时,这些组号可用于合法性检查。(3)(3)unsigned short euid,egid;unsigned short euid,egid;euid 和 egid 又称为有效的 uid 和 gid。出于系统安全的权限的考虑,运行程序时要检查 euid 和 egid 的合法性。通常,uid 等于 euid,gid 等于 egid。有时候,系统会赋予一般用户暂时拥有 root 的 uid 和 gid(作为用户进程的 euid 和egid),以便于进行运作。(4)(4)unsigned short fsuid,fsgid;unsigned short fsuid,fsgid;fsuid 和 fsgid 称为文件系统的 uid 和 gid,用于文件系统操作时的合法性检查,是 Linux 独特的标识类型。它们一般分别和 euid 和 egid 一致,但在 NFS文件系统中 NFS 服务器需要作为一个特殊的进程访问文件,这时只修改客户进程的 fsuid 和 fsgid。(5)(5)unsigned short suid,sgid;unsigned short suid,sgid;suid 和 sgid 是根据 POSIX 标准引入的,在系统调用改变 uid 和 gid 时,用于保留真正的 uid 和 gid。(6)(6)int pid,pgrp,session;int pid,pgrp,session;进程标识号、进程的组织号及 session 标识号,相关系统调用(见程序kernel/sys.c)有 sys_setpgid、sys_getpgid、sys_setpgrp、sys_getpgrp、sys_getsid及 sys_setsid 几种。(7)(7)int leader;int leader;是否是 session 的主管,布尔量。5.时间数据成员(1)(1)unsigned long timeout;unsigned long timeout;用于软件定时,指出进程间隔多久被重新唤醒。采用 tick 为单位。(2)(2)unsigned long it_real_value,it_real_iner;unsigned long it_real_value,it_real_iner;用于 itimer(interval timer)软件定时。采用 jiffies 为单位,每个 tick 使it_real_value 减到 0 时向进程发信号 SIGALRM,并重新置初值。初值由it_real_incr 保存。具体代码见 kernel/itimer.c 中的函数 it_real_fn()。(3)(3)struct timer_list real_timer;struct timer_list real_timer;一种定时器结构(Linux 共有两种定时器结构,另一种称作 old_timer)。数据结构的定义在 include/linux/timer.h 中,相关操作函数见 kernel/sched.c 中add_timer()和 del_timer()等。(4)(4)unsigned long it_virt_value,it_virt_incr;unsigned long it_virt_value,it_virt_incr;关于进程用户态执行时间的 itimer 软件定时。采用 jiffies 为单位。进程在用户态运行时,每个 tick 使 it_virt_value 减 1,减到 0 时向进程发信号SIGVTALRM,并重新置初值。初值由 it_virt_incr 保存。具体代码见kernel/sched.c 中的函数 do_it_virt()。(5)(5)unsigned long it_prof_value,it_prof_incr;unsigned long it_prof_value,it_prof_incr;同样是 itimer 软件定时。采用 jiffies 为单位。不管进程在用户态或内核态运行,每个 tick 使 it_prof_value 减 1,减到 0 时向进程发信号 SIGPROF,并重新置初值。初值由 it_prof_incr 保存。具体代码见 kernel/sched.c 中的函数do_it_prof。(6)(6)long utime,stime,cutime,cstime,start_time;long utime,stime,cutime,cstime,start_time;以上分别为进程在用户态的运行时间、进程在内核态的运行时间、所有层次子进程在用户态的运行时间总和、所有层次子进程在核心态的运行时间总 9和,以及创建该进程的时间。6.信号量数据成员(1)(1)struct sem_undo*semundo;struct sem_undo*semundo;进程每操作一次信号量,都生成一个对此次操作的 undo 操作,它由sem_undo 结构描述。这些属于同一进程的 undo 操作组成的链表就由 semundo属性指示。当进程异常终止时,系统会调用 undo 操作。sem_undo 的成员 semadj指向一个数据数组,表示各次 undo 的量。结构定义在 include/linux/sem.h。(2)(2)struct sem_queue*semsleeping;struct sem_queue*semsleeping;每一信号量集合对应一个 sem_queue 等待队列(见 include/linux/sem.h)。进程因操作该信号量集合而阻塞时,它被挂到 semsleeping 指示的关于该信号量集合的 sem_queue 队列。反过来,semsleeping。sleeper 指向该进程的 PCB。7.进程上下文环境(1)(1)struct desc_struct*ldt;struct desc_struct*ldt;进程关于 CPU 段式存储管理的局部描述符表的指针,用于仿真 WINE Windows 的程序。其他情况下取值 NULL,进程的 ldt 就是 arch/i386/traps.c 定义的 default_ldt。(2)(2)struct thread_struct tss;struct thread_struct tss;任务状态段,其内容与 INTEL CPU 的 TSS 对应,如各种通用寄存器.CPU调度时,当前运行进程的 TSS 保存到 PCB 的 tss,新选中进程的 tss 内容复制到 CPU 的 TSS。结构定义在 include/linux/tasks.h 中。(3)(3)unsigned long saved_kernel_stack;unsigned long saved_kernel_stack;为 MS-DOS 的仿真程序(或叫系统调用 vm86)保存的堆栈指针。(4)(4)unsigned long kernel_stack_page;unsigned long kernel_stack_page;在内核态运行时,每个进程都有一个内核堆栈,其基地址就保存在kernel_stack_page 中。8.文件系统数据成员(1)(1)struct fs_struct*fs;struct fs_struct*fs;fs 保存了进程本身与 VFS 的关系消息,其中 root 指向根目录结点,pwd指向当前目录结点,umask 给出新建文件的访问模式(可由系统调用 umask 更改),count是Linux保留的属性,如下页图所示。结构定义在include/linux/sched.h中。(2)(2)struct files_struct*files;struct files_struct*files;files包含了进程当前所打开的文件(struct file*fdNR_OPEN)。在Linux中,一个进程最多只能同时打开 NR_OPEN 个文件。而且,前三项分别预先设置为标准输入、标准输出和出错消息输出文件。(3)(3)int link_count;int link_count;文件链(link)的数目。9.内存数据成员(1)(1)struct mm_struct*mm;struct mm_struct*mm;在 linux 中,采用按需分页的策略解决进程的内存需求。task_struct 的数据成员 mm 指向关于存储管理的 mm_struct 结构。其中包含了一个虚存队列mmap,指向由若干 vm_area_struct 描述的虚存块。同时,为了加快访问速度,mm 中的 mmap_avl 维护了一个 AVL 树。在树中,所有的 vm_area_struct 虚存块均由左指针指向相邻的低虚存块,右指针指向相邻的高虚存块,见下图。结 10构定义在 include/linux/sched.h 中。countcloso_on_cxccopen_fsfd0fd1countumask*root*pwdfd255f_ownerf_inodef_opf_versionf_modef_posf_flagsf_counttask_structfsfilcsfile oparationroutinasfs_structfiles_structor022inodcfilefileinode文件系统的数据成员文件系统的数据成员 10.页面管理(1)(1)int swappable:1;int swappable:1;进程占用的内存页面是否可换出。swappable 为 1 表示可换出。对该标志的复位和置位均在 do_fork()函数中执行(见 kerenl/fork.c)。(2)(2)unsigned long swap_address;unsigned long swap_address;虚存地址比 swap_address 低的进程页面,以前已经换出或已换出过,进程下一次可换出的页面自 swap_address 开始。参见 swap_out_process()和swap_out_pmd()(见 mm/vmscan.c)。(3)(3)unsigned long min_flt,maj_flt;unsigned long min_flt,maj_flt;该进程累计的 minor 缺页次数和 major 缺页次数。maj_flt 基本与 min_flt相同,但计数的范围比后者广(参见 fs/buffer.c 和 mm/page_alloc.c)。min_flt 只在 do_no_page()、do_wp_page()里(见 mm/memory.c)计数新增的可以写操作的页面。(4)(4)unsigned long nswap;unsigned long nswap;该进程累计换出的页面数。11task_structmmmmap_avlmmap_scmcountpgdmmapmm_structvm_opsvm_nextvm_chdvm_startvm_flagsvm_inodovm_area_structvm_opsvm_nextvm_chdvm_startvm_flagsvm_inodovm_area_structCodeDataProcesses Virtual Memory0 x859BBB0 x80480000 x0000000虚存数据成员虚存数据成员(5)(5)unsigned long cmin_flt,cmaj_flt,cnswap;unsigned long cmin_flt,cmaj_flt,cnswap;以本进程作为祖先的所有层次子进程的累计换入页面、换出页面计数。(6)(6)unsigned long old_maj_flt,dec_flt;unsigned long old_maj_flt,dec_flt;(7)(7)unsigned long swap_cnt;unsigned long swap_cnt;下一次信号最多可换出的页数。11.支持对称多处理器方式(SMP)时的数据成员(1)(1)int processor;int processor;进程正在使用的 CPU。(2)(2)int last_processor;int last_processor;进程最后一次使用的 CPU。(3)(3)int lock_depth;int lock_depth;上下文切换时系统内核锁的深度。12.其它数据成员(1)(1)unsigned short used_math;unsigned short used_math;是否使用 FPU。(2)(2)char comm16;char comm16;进程正在运行的可执行文件的文件名。(3)(3)struct rlimit rlimRLIM_NLIMITS;struct rlimit rlimRLIM_NLIMITS;结构 rlimit 用于资源管理,定义在 linux/include/linux/resource.h 中,成员共有两项:rlim_cur 是资源的当前最大数目;rlim_max 是资源可有的最大数目。在i386 环境中,受控资源共有 RLIM_NLIMITS 项,即 10 项,定义在linux/include/asm/resource.h 中,见下表:(4)(4)int errno;int errno;12最后一次出错的系统调用的错误号,0 表示无错误。系统调用返回时,全程量也拥有该错误号。(5)(5)long debugreg8;long debugreg8;保存 INTEL CPU 调试寄存器的值,在 ptrace 系统调用中使用。(6)(6)struct exec_domain*exec_domain;struct exec_domain*exec_domain;Linux 可以运行由 80386 平台其它 UNIX 操作系统生成的符合 iBCS2 标准的程序。关于此类程序与 Linux 程序差异的消息就由 exec_domain 结构保存。(7)(7)unsigned long personality;unsigned long personality;Linux 可以运行由 80386 平台其它 UNIX 操作系统生成的符合 iBCS2 标准的程序。Personality 进一步描述进程执行的程序属于何种 UNIX 平台的“个性”信息。通常有 PER_Linux、PER_Linux_32BIT、PER_Linux_EM86、PER_SVR3、PER_SCOSVR3、PER_WYSEV386、PER_ISCR4、PER_BSD、PER_XENIX 和PER_MASK 等,参见 include/linux/personality.h。(8)(8)struct linux_binfmt*binfmt;struct linux_binfmt*binfmt;指向进程所属的全局执行文件格式结构,共有 a。out、script、elf 和 java等四种。结构定义在 include/linux/binfmts.h 中(core_dump、load_shlib(fd)、load_binary、use_count)。(9)(9)int exit_code,exit_signal;int exit_code,exit_signal;引起进程退出的返回代码 exit_code,引起错误的信号名 exit_signal。(10)(10)int dumpable:1;int dumpable:1;布尔量,表示出错时是否可以进行 memory dump。(11)(11)int did_exec:1;int did_exec:1;按 POSIX