进程调度与系统调用.ppt_第1页
进程调度与系统调用.ppt_第2页
进程调度与系统调用.ppt_第3页
进程调度与系统调用.ppt_第4页
进程调度与系统调用.ppt_第5页
已阅读5页,还剩122页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Linux操作系统内核分析,湘潭大学信息工程学院,讲课内容,中断管理 进程管理 信号处理,中断的概念,改变处理器正常执行顺序的事件 中断来源: 硬件:时钟、键盘、硬盘等,异步发生 异常:CPU检测到的错误 软件 系统调用:进程向OS发出的请求,中断向量,保护模式支持256个中断,每个中断用一个0到255的整数来标识,把这个整数称为中断向量 0到31对应异常(P76表5-2) 32到47对应硬件中断(P9图2-5) 48到255预留,linux使用了0 x80作为系统调用,中断,保护模式下中断处理,idtr,0号中断描述符,1号中断描述符,2号中断描述符,3号中断描述符,中断描述符表,中断描述符

2、,段选择子,段内偏移(0-15),段内偏移(16-31),2位,4位,Head中对中断描述符表的处理,在程序232行(P58),定义了有256个中断描述符的中断描述符表,并在程序开始处把该描述符表的基地址输出(可以被C程序使用) 在程序78行(P54),把这256个中断描述符中的处理程序设置为ignore_int 在程序105行(P55)把中断描述符表的基地址装入到idtr寄存器中,gcc嵌入汇编,_asm_ _volatile_( 汇编语句 : 输出寄存器 : 输入寄存器 : 会被修改的寄存器); 输出寄存器:“=代表寄存器的字母” (变量名) 寄存器的值会被写入变量中 输入寄存器:“代表寄

3、存器的字母” (变量名) 用变量的值初始化寄存器,P81,常用寄存器加载代码,P83表5-3,嵌入汇编示例,#define _save_flags(x) _ asm_ _volatile_( “pushfl;” “popl %0” : “=a” (x) );,a代表寄存器eax。把eax和变量x绑定,往eax中写入值等于给变量x赋值,数字代表寄存器的序号。把输出寄存器和输入寄存器按照顺序进行编号,从0开始。%n代表第n个寄存器。,序号0,嵌入汇编示例,#define get_seg_byte(seg,addr)( register char _res; _ _asm_ _(“ push %fs

4、; mov %ax, %fs; movb %fs:%2,%al; pop %fs” :“=a”(_res) :“0”(seg), “m”(*(addr); _res; ),序号0,序号1,序号2,宏的返回值,eax用seg的值进行了初始化,_set_gate宏,_set_gate宏(定义在system.h,P390的22行),用来设置中断描述符 gate_addr:描述符的地址 type:描述符的类型 dpl: 使用描述符的最低权限 addr:中断处理函数的地址,_set_gate宏,#define _set_gate(gate_addr,type,dpl,addr) _asm_ (movw

5、%dx,%axnt movw %0,%dxnt movl %eax,%1nt movl %edx,%2 : : i (short) (0 x8000+(dpl13)+(type8), o (*(char *) (gate_addr), o (*(4+(char *) (gate_addr), d (char *) (addr),a (0 x00080000),0,1,2,3,4,_set_gate宏,0号立即数,1号内存地址指向描述符的基地址(前4个字节),2号内存地址指向描述符的基地址+4(后4个字节),处理程序高16位,处理程序低16位,edx,0 x0008,0 x0000,eax,处理

6、程序低16位,0 x8000+(dpl13)+(type8),0 x8000+(dpl13)+(type8),段选择子,段内偏移(0-15),段内偏移(16-31),Type,0,DPL,1,00000000,设置中断描述符,#define set_trap_gate(n,addr) _set_gate( _ _asm_ _ volatile(“int $0 x80 : “=a”(_res) : “0”(_NR_#name); if(_res =0) return (type)_res; errno = - _res; return -1; ,系统调用的返回放在eax中,系统调用的功能号放在e

7、ax中(P381),使用系统调用,P63第23行 static inline _syscall0(int,fork) int fork(void) long _res; _ _asm_ _ volatile(“int $0 x80 : “=a”(_res) : “0”(_NR_fork); if(_res =0) return (type)_res; errno = - _res; return -1; ,使用系统调用,系统调用的输入 把子功能号放入eax中 如果还有其它参数(最多3个),则第1、第2和第3个参数分别放入寄存器ebx,ecx和edx中 系统调用的返回值保存在eax中,数据结构及

8、算法,函数指针数组 sys_call_talbe (P409) system_call(P86第80行)处理流程 保存现场 以子功能号作为索引查找sys_call_table,找到处理该功能的C语言函数,然后调用该函数。 恢复现场,系统调用的处理,cmpl $nr_system_calls-1,%eax ja bad_sys_call push %ds push %es push %fs pushl %edx pushl %ecx pushl %ebx movl %0 x10, %edx mov %dx,%ds mov %dx,%es movl %0 x17, %edx mov %dx,%fs

9、 call _sys_call_table(,%eax,4) pushl %eax,EFLAGS,EIP,用户态ESP,用户态SS,EDX,ECX,EBX,系统调用参数,_sys_call_table+4*eax _sys_call_table在P409定义,EAX,保存系统 调用返回值,系统调用的处理,3:popl %eax popl %ebx popl %ecx popl %edx pop %fs pop %es pop %ds iret,EFLAGS,EIP,用户态ESP,用户态SS,EDX,ECX,EBX,EAX,讲课内容,中断管理 进程管理 信号处理,进程的概念,进程是程序的一次执行

10、,是由代码段、数据段和堆栈段组成动态的实体,在Linux中,把进程又称为任务(task) 进程是系统资源分配的基本单位,也是使用CPU运行的基本调度单位,进程描述符,为了管理进程,操作系统需要清楚地知道每个进程的属性,Linux用一个称为进程描述符(task_struct)的数据结构来描述 task_struct定义在sched.h中,参见P404第78行,进程描述符状态,P12图2-6,没有实现,进程描述符线性地址分布,代码,数据,bss,用户态堆栈,环境参数,nr*64M,(nr+1)*64M,start_code,end_code,end_data,brk,start_stack,进程描

11、述符任务状态段,任务状态段(TSS)是保存任务的所有信息的内存段,共104B 寄存器保存区域 内层堆栈指针区域 地址映射寄存器区域 其它字段 P116图5-8,进程描述符任务状态段,在任务切换过程中 首先,CPU中各寄存器的当前值被自动保存到TR所指定的TSS中(当前任务的TSS中) 然后,下一任务的TSS的选择子被装入TR 最后,从TR所指定的TSS中取出各寄存器的值送到处理器的各寄存器中 由此可见,通过在TSS中保存任务现场各寄存器状态的完整映象,实现任务的切换,进程描述符任务状态段,TSS的段描述符在GDT中,当前进程的TSS的段选择子被保存在TR寄存器中,TSS段描述符,GDT,TSS

12、段,当前进程的 TSS段选择子,TR,TSS段描述符,TSS段,进程描述符局部描述符表,局部描述符表(LDT)包含任务私有内存段的描述符(也是一个内存段) LDT的段描述符在GDT中,当前进程的LDT段选择子在ldtr中,进程描述符局部描述符表,Linux中LDT包含3个描述符,其中: 第0个没用 第1个描述的是代码段,该段的段选择子是0 xf(1111) 第2个描述的是数据段,该段的段选择子是0 x17(10111),进程描述符局部描述符表,LDT段描述符,私有段段描述符,私有段段描述符,私有段段描述符,GDT,LDT,当前进程的 LDT段选择子,ldtr,LDT段描述符,私有段段描述符,私

13、有段段描述符,私有段段描述符,TSS段描述符,TSS段描述符,进程1,进程2,Linux内核堆栈,Intel平台上进程在不同的特权级别下使用不同的堆栈 在Linux中为进程在内核态建立的堆栈与进程描述符公用一块4K的内存块 参见shed.c(P95第53行),task_union,union task_union struct task_struct task; char stackPAGE_SIZE;/宏定义在mm.h(P401第4行) ;,内核堆栈栈顶,任务描述符基地址,4K,任务数组,Linux把所有任务的进程描述符的指针用一个指针数组管理起来,定义在sched.c中(P95第65行)

14、struct task_struct *taskNR_TASKS; /NR_TASK=64,定义在sched.h中(P402第4行) FIRST_TASK LAST_TASK,taskn,task数组,tss,进程数据段描述符,其它属性,进程描述符,没用,内核代码段描述符,内核数据段描述符,没用,TSS0,LDT0,TSS1,LDT1,TSSn,LDTn,TSS(n+1),LDT(n+1),GDT,.,进程代码段描述符,没用,进程n,n*64,内核态堆栈,求进程n的TSS段的段选择子,#define FIRST_TSS_ENTRY 4 #define _TSS(n) (unsigned lon

15、g) n)4)+(FIRST_TSS_ENTRY3) 定义在sched.h(P405第153和155行),4*8,16B,16B,GDT,Index,0,00,RPL,TI,(4+n*2)*8,进程管理,进程0的创建 创建子进程 调度进程 进程睡眠 终止进程,进程0,进程0是一个特殊的进程 它是所有其他进程的祖先进程; 所有其他的进程都是通过fork系统调用,复制进程0或者其后代进程产生的;只有进程0是静态产生的。,进程0,创建进程0的步骤 申请一个进程描述符与进程内核堆栈的公用体 把进程描述符的地址放在task数组的第0项 在GDT中设置进程0的tss段描述符和ldt段描述符(sched_i

16、nit函数, P102第392,393行) 把进程0tss段描述符的选择子和ldt段描述符的选择子装载到tr寄存器和ldtr寄存器(404,405行),申请进程描述符与内核堆栈的公用体,static union task_union init_task = INIT_TASK,; /定义在sched.c中(P95第58行) /INIT_TASK定义在sched.h中(P405第113行) /进程0的代码段和数据段与内核代码段和数据段重合 struct task_struct *taskNR_TASKS = /定义在sched.c中(P95第65行),task数组,tss,进程数据段描述符,其它

17、属性,进程描述符,没用,内核代码段描述符,内核数据段描述符,没用,TSS0,LDT0,GDT,进程代码段描述符,没用,进程0,64M,0M,esp0,内核态堆栈,tr,ldt,1,2,2,3,4,加载进程0的tss和ldt的段选择子,ltr(0); lldt(0); #define ltr(n) _asm_(ltr %ax:a (_TSS(n) #define lldt(n) _asm_(lldt %ax:a (_LDT(n) /定义在sched.h中(P405第157行),把进程0移到用户态,sched_init函数运行完之后,进程0还是运行在内核态 利用模拟中断返回的方法把进程0从内核态切

18、换到用户态 move_to_user_mode定义在system.h中(P389第1行),Iret指令,EIP,CS,FLAG,SS,ESP,esp,内核态堆栈,0 xf,0 x17,move_to_user_mode,#define move_to_user_mode() _asm_ ( “movl %esp,%eaxnt pushl $0 x17nt pushl %eaxnt pushflnt pushl $0 x0fnt pushl $1fnt iretn 1:tmovl $0 x17,%eaxnt movw %ax,%dsnt movw %ax,%esnt movw %ax,%fsnt

19、 movw %ax,%gs :ax),进程0用户态数据段选择子(0 x17),进程0用户态堆栈指针( user_stack ),EFLAGS,进程0代码段段选择子(0 x0f),EIP(iret返回后执行的代码),进程管理,进程0的创建 创建子进程 调度进程 进程睡眠 终止进程,fork系统调用,系统调用处理函数_sys_fork定义在system_call.s中(P89第208行),在task数组中 寻找一个空位,有空位,拷贝当前进程,有,无,在task数组中寻找空位,int find_empty_process(void) 定义在fork.c(P115第135行) 作用:寻找task数组中

20、的空位 返回:如果找到则返回空位索引 否则返回错误,find_empty_process,int i; repeat: if (+last_pid)pid = last_pid) goto repeat; for(i=1 ; iNR_TASKS ; i+) if (!taski) return i; return -EAGAIN;,last_pid记录的是上一次创建进程的进程号。在Linux中,所有现存的进程的进程号不能相同。定义在fork.c中(P113第22行),拷贝当前进程,int copy_process(int nr, long ebp, long edi, long esi,lon

21、g gs, long none, long ebx, long ecx, long edx, long fs, long es, long ds, long eip, long cs, long eflags, long esp, long ss) 作用:拷贝当前进程的描述符到子进程描述符中 返回:子进程的进程号(P114),调用copy_process的堆栈,CS,EFLAGS,EIP,用户态ESP,用户态SS,DS,ES,FS,EDX,ECX,EBX,call _sys_call_table的返回地址,GS,ESI,EDI,EBP,EAX,call _copy_process的返回地址,函

22、数的参数,find_empty_process()的返回值,task数组空闲项的下标,系统调用的返回地址,Fork系统调用,int fork(void) long _res; _ _asm_ _ volatile(“int $0 x80 : “=a”(_res) : “0”(_NR_fork); if(_res =0) return (type)_res; errno = - _res; return -1; ,eip,copy_mem,int copy_mem(int nr,struct task_struct * p) 作用:修改子进程的私有段的基地址, 并拷贝当前进程的页目录项和页表 参

23、数:nr子进程在task数组中的索引 p 子进程描述符的指针 返回:0表示无错,小于0表示有错,线性地址的分布,4G的线性地址给64个进程使用,每个进程占64M的线性地址 task数组中的第n个进程占用的线性地址是n*64M(n+1)*64M task数组中的第n个进程的所有段的基地址设为n*64M,taskn2,taskn1,task数组,进程数据段,进程代码段,进程数据段,进程数据段,进程代码段,进程数据段,n2*64M,(n2+1)*64M,n1*64M,(n1+1)*64M,线性地址,子进程,父进程,task 数组,线性地址,页目录,页表,copy_process,申请4K页面,设置t

24、ask数组,拷贝父进程描述符,修改子进程描述符,拷贝父进程的 页目录和页表,设置TSS和LDT,进程管理,进程0的创建 创建子进程 调度进程 进程睡眠 终止进程,任务切换的形式,ljmp TSS段选择子:偏移 ljmp 8字节的内存首地址 其中,头4个字节对应偏移(忽略),后4个字节的头2个字节对应TSS段选择子,忽略,任务切换的步骤,从指令JMP的操作数中获取新任务的TSS段选择子 在当前任务的TSS中保存当前任务的状态 为TR装载新任务TSS的段选择子,从新任务的TSS中装载新任务的状态到处理器中 开始执行新任务,schedule,void schedule() /定义在sched.c(P

25、96第104行) 作用:选择一个任务并与当前任务进行切换,选择task数组中第一个 所剩时间片最长的且状 态为可运行的任务,与当前进程进行切换,所有的进程 都已处理完,设置警告且警告超时,给当前进程 设置alarm信号,有信号并处于 可中断睡眠状态,唤醒进程,最长时间片=0,重新给所有任务分配时 间片:counter/2+priority,是,否,是,否,是,否,否,是,switch_to宏,#define switch_to(n) struct long a,b; _tmp; _asm_(cmpl %ecx,currentnt je 1fnt movw %dx,%1nt xchgl %ecx

26、,currentnt ljmp *%0nt cmpl %ecx,last_task_used_mathnt jne 1fnt cltsn 1: :m (* ,dx中存放的是新进程n的TSS段选择子,1,0,2,3,从这里开始,老进程退出CPU,新进程开始运行,除了刚用fork创建的进程,其它进程重新被运行时都从这里开始,调用schedule,时钟中断发生时 发生中断前,进程处于用户态且时间片=0,被动放弃CPU(被抢夺),进程的状态仍然是可运行状态 系统调用返回时 发生中断前,进程处于用户态且时间片=0,被动放弃CPU(被抢夺),进程的状态仍然是可运行状态 睡眠函数内 进程在内核态主动放弃CP

27、U,进程的状态是不可运行状态,时钟中断,Linux设置时钟中断频率为10毫秒,每次中断时调用timer_interrupt,定义在system_call.s(P88第176行),timer_interrupt: push %ds push %es push %fs pushl %edx pushl %ecx pushl %ebx pushl %eax movl $0 x10,%eax mov %ax,%ds mov %ax,%es movl $0 x17,%eax mov %ax,%fs incl jiffies movb $0 x20,%al outb %al,$0 x20 movl CS(

28、%esp),%eax andl $3,%eax pushl %eax call do_timer addl $4,%esp jmp ret_from_sys_call,EFLAGS,EIP,用户态ESP,用户态SS,EDX,ECX,EBX,EAX,fs指向进程数据段,向8259A发送停止中断信号,取中断发生时CS的CPL,CPL,do_timer,中断时进程 处于用户态,用户态运行时间+1,内核态运行时间+1,进程的时间片-1,进程时间片0,中断时进程 处于内核态,返回,schedule,是,是,否,是,否,否,P100第305行,系统调用返回时,movl current,%eax cmpl

29、$0,state(%eax) jne reschedule cmpl $0,counter(%eax) je reschedule,P86第96行,进程管理,进程0的创建 创建子进程 调度进程 进程睡眠 终止进程,进程睡眠,当进程请求的资源无效时,进程将会进入睡眠状态,直到资源有效时。 每个资源上都会有一个等待队列,在该队列上排队的就是为等待此资源而进入睡眠状态的进程。,资源,进程睡眠,进程可以以两种状态进入睡眠 不可中断睡眠(sleep_on) 可中断睡眠(interruptible_sleep_on),sleep_on,void sleep_on(struct task_struct *p

30、) /定义在sched.c(P97第151行) 作用:把任务设置为不可中断睡眠,并把任 务挂在某个等待队列上。 参数:p等待队列的头指针,*p,p,进程1 描述符,*p,p,进程2 描述符,进程1 描述符,*p,进程4,tmp,进程4 描述符,进程3,tmp,进程3 描述符,进程2,tmp,进程2 描述符,进程1,tmp,进程1 描述符,sleep_on,当资源有效时,在该资源等待队列上的进程全部都被唤醒。有可能还会发生资源冲突。 常见的使用的方法是 while(资源无效) sleep_on(资源等待队列头指针的指针);,interruptible_sleep_on,void interrup

31、tible_sleep_on( struct task_struct *p) /定义在sched.c(P97第167行) 作用:把任务设置为可中断睡眠,并把任 务挂在某个等待队列上。 参数:p指向等待队列的头指针的指针,*p,进程4,tmp,进程4 描述符,进程3,tmp,进程3 描述符,进程2,tmp,进程2 描述符,进程1,tmp,进程1 描述符,*p,进程4,tmp,进程4 描述符,进程3,tmp,进程3 描述符,进程2,tmp,进程2 描述符,进程1,tmp,进程1 描述符,有信号,interruptible_sleep_on,当资源有效时或是任一进程有信号时,在该资源等待队列上的进程

32、全部都被唤醒。 资源冲突 没有信号而被唤醒 常见的使用的方法是 while(资源无效,进程管理,进程0的创建 创建子进程 调度进程 进程睡眠 终止进程,进程资源,进程终止时,要释放它占用的所有资源,包括: 内存 进程描述符和内核堆栈占用4K空间 页表和页目录占用的物理页面 代码和数据占用的物理页面 GDT中的LDT和TSS描述符 打开的文件,进程,task 数组,线性地址,页目录,页表,TSSn,LDTn,进程终止的问题,通常父进程在子进程终止后,需要查询子进程的终止状态,但是该状态保存在子进程的进程描述符中。如果,子进程终止时释放了进程描述符,则无法查询终止状态。,通知,进程终止的问题,由父

33、进程负责回收子进程的进程描述符。但是,如果父进程在子进程之前终止,谁来负责回收子进程的进程描述符? 进程在终止时,把所有未终止的子进程过继给进程1。由进程1负责接收这些子进程终止信号,并回收子进程的进程描述符。,sys_exit,int sys_exit(int error_code) /定义在exit.c(P111第137行) 作用:释放进程占用的物理内存并关闭进程打开的文件。 参数:error_code 退出码 返回:无意义,释放代码和数据占用 的物理内存、页表,把子进程过 继给进程1,关闭打开的 文件和终端,修改状态为僵死,schedule,发送信号给父进程,sys_waitpid,in

34、t sys_waitpid(pid_t pid, unsigned long * stat_addr, int options) 作用:如果任意一个符合pid条件的子进程僵死,则释放子进程占用的进程描述符;如果所有符合pid条件的子进程都不处于僵死状态,则按照option选项或者等待或立即返回。(P111第142行),sys_waitpid,参数:pid pid 0等待进程号为pid的子进程 pid = 0等待进程组号等于当前进程 组号的任何一个子进程 pid = -1等待任何一个子进程 pid -1等待进程组号等于-pid的任 何一个子进程,sys_waitpid,参数: stat_addr

35、:存放子进程的退出码(P67) options: options中WNOHANG置位:表示如果没有满足pid标识的子进程是僵死状态,则当前进程马上返回;否则当前进程挂起。 返回:正常返回子进程的pid,出错返回负数。,所有进程都搜索完毕,是符合pid条件的子进程,子进程的状态是僵死,回收子进程的 进程描述符,有符合pid条件的子进程,改状态为可中断睡眠 schedule,设置WNOHANG,收到SIGCHLD信号,返回,是,否,是,否,否,是,是,否,是,否,是,否,讲课内容,中断管理 进程管理 信号处理,信号,信号是一种进程间通讯的方式,这种机制是异步的。 Linux支持32个信号,每个信号

36、用一个整数值来标识。参见书P107表5-5。,信号处理数据结构,参见task_struct,P404第83行 long signal; 对应32个信号,向进程发送信号就是把singal中信号对应的那一位置1。 signal |= 1(信号值-1) long blocked; 对应32个信号,如果某个信号对应的那一位置1表示该信号被屏蔽。 signal /信号处理函数指针,可以是用户自定义的函数 sigset_t sa_mask; /在处理当前信号时需要屏蔽的信号,一般屏蔽本信号 int sa_flags; /改变信号处理过程的标志 void (*sa_restorer)(void); /恢复函

37、数入口地址,用于清除用户堆栈这个 /函数由libc提供,用户无法自行设置 ;,P361第48行,信号处理数据结构,信号响应函数是void(*)(int)类型的,内核在signal.h第45行定义了两个特殊的响应函数。 #define SIG_DFL(void (*)(int)0) #define SIG_IGN(void (*)(int)1) 进程对于SIG_DFL的处理一般是结束进程,对于SIG_IGN一般是忽略,信号处理数据结构,在signal.h第37行由sa_flags标志值的定义 #define SA_NOMASK0 x40000000 /在信号的处理后不保留信号屏蔽设置 #defi

38、ne SA_ONESHOT 0 x80000000 /信号处理函数一旦被调用过,就恢复到SIG_DFL,使用信号,其它模块,信号管理,系统调用,sys_sigaction sys_signal sys_kill,send_sig,注册信号处理函数,这一步可以省略,在省略情况下信号的处理函数是SIG_DFL。参见进程0的定义(P405第115行)。 进程也可以注册自己的信号处理函数。,注册信号处理函数,void sig_handler(int sig) printf(signal n); signal(SIGTERM,sig_handler); int main() signal(SIGTERM

39、,sig_handler); while(1); return 0; ,信号注册系统调用,int sys_signal(int signum, long handler, long restorer) /P105第48行 作用:注册一个自定义信号处理函数 参数:signum信号值 handler信号处理函数指针 restorer恢复函数 返回:上一次注册的处理函数指针,注册信号处理函数,voidmysignal(intsigno)/*mysignalhandler*/ int main(void)structsigactionact,old; act.sa_handler=mysignal;act.sa_flags=0;sigaction(SIGHUP, ,信号注册系统调用,int sys_sigaction(int signum,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论