第8讲 系统调用

上传人:飞*** 文档编号:51433345 上传时间:2018-08-14 格式:PPT 页数:36 大小:449.50KB
返回 下载 相关 举报
第8讲 系统调用_第1页
第1页 / 共36页
第8讲 系统调用_第2页
第2页 / 共36页
第8讲 系统调用_第3页
第3页 / 共36页
第8讲 系统调用_第4页
第4页 / 共36页
第8讲 系统调用_第5页
第5页 / 共36页
点击查看更多>>
资源描述

《第8讲 系统调用》由会员分享,可在线阅读,更多相关《第8讲 系统调用(36页珍藏版)》请在金锄头文库上搜索。

1、第八讲 系统调用系统调用与API、系统命令、内核函数系统调用处理程序及服务例程如何使用系统调用添加新的系统调用 系统调用,顾名思义,说的是操作系统 提供给用户程序调用的一组“特殊”接口。 从逻辑上来说,系统调用可被看成是一 个内核与用户空间程序交互的接口它好比一个中间人,把用户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给用户空间。系统调用内核的出口联系: (1)API有可能和系统调用的调用形式一致; 如:read();(2) API和系统调用关注的都是函数名、参数类型及返回代码的含义;(3)一个API函数有可能调用多个系统调用,有可能不调用系统调用(如:abs(),或者几个A

2、PI函数有可能均调用了同一个系统调用(如:malloc( ),calloc( ),free( )均调用了brk( )。系统调用与API区别:(1)应用编程接口(API) 是一组函数定义,这些函数说明了如何获得一个给定的服务;而系统调用是通过软中断向内核发出一个明确的请求;(2)系统调用的实现是在内核完成的,而API函数是在函数库中实现的。 联系:(1)系统命令相对应用编程接口更高一层,每个系统命令都是一个可执行程序,比如ls、hostname等;(2)系统命令的实现调用了系统调用,可通过“strace 命令名”查看 。系统调用与系统命令pid;#include #include #includ

3、e #include int main(void) long ID1,ID2;ID1=syscall(SYS_getpid); /* 直接调用内核函数printf(“syscall(SYS_getpid)= %dn”,ID1);ID2=getpid( ); /*调用系统调 用printf(“getpid( )=%dn”,ID2;return (0);直接调用内核函 数必须通过 syscall函数 xyz() system_call: sys_xyz() ret_from_sys_ call: iretxyz() int 0x80 sys_xy z() 在应用程序 在libc标准库 系统调用 系

4、统调用 调用中的 中的封装例程 处理程序 服务例程 系统调用用户态 内核态系统调用执行过程 1、程序调用libc库的封装函数 2、调用软中断 int 0x80 进入内核。 3、在内核中首先执行system_call函数,接着根 据系统调用号在系统调用表中查找到对应的系统 调用服务例程 4、执行该服务例程 5、执行完毕后,转入ret_from_sys_call例程, 从系统调用返回 系统调用执行过程 系统调用处理程序系统调用处理程序(system_call)(system_call)可参见可参见( system_call的代码在源码/kernel/entry.s中 Entry(system_ca

5、ll)的下一行:调用处理程序(system_call)执行流程图系统调用过程示意图系统调用处理程序及服务例程 vv系统调用号:系统调用号:内核实现了很多不同的系统调用内核实现了很多不同的系统调用 ,用系统调用号来进行识别,在进行系统调用时,用系统调用号来进行识别,在进行系统调用时 ,该参数被保存到,该参数被保存到eaxeax寄存器中;寄存器中;vv系统调用表:系统调用表:将系统调用号和服务例程关联起将系统调用号和服务例程关联起 来,存放在来,存放在sys_call_tablesys_call_table中,有中,有NR_syscallsNR_syscalls 个表项(个表项(256256个),

6、第个),第n n个表项包含系统调用号为个表项包含系统调用号为 n n的的服务例程的地址。服务例程的地址。(/usr/src/linux-2.4.18/include/asm/unistd.h中)vv系统调用服务例程:系统调用服务例程:实现系统调用的内核函数实现系统调用的内核函数 ,在内核中,在内核中,xyz()xyz()系统调用对应的服务例程的名系统调用对应的服务例程的名 字通常为字通常为SYS_xyzSYS_xyz()()。(在/usr/src/linux-2.4.18/ kernel/sys.c中)系统调用处理程序及服务例程 系统调用处理程序系统调用处理程序system_callsyste

7、m_call:是系统调用在内是系统调用在内 核的公共入口,是核的公共入口,是linuxlinux中系统调用唯一的入口点中系统调用唯一的入口点 ,通过软中断,通过软中断intint 0x80 0x80到达;到达; (/usr/src/linux-2.4.18/arch/i386/kernel/entry.S中) 系统调用处理程序执行下列操作:系统调用处理程序执行下列操作:在内核栈保存大多数寄存器的内容;在内核栈保存大多数寄存器的内容;调用所谓系统调用服务例程的相应的内核函调用所谓系统调用服务例程的相应的内核函 数来处理系统调用;数来处理系统调用;通过通过ret_from_sys_call( re

8、t_from_sys_call( ) )函数从系统调函数从系统调 用返回。用返回。v系统调用的进入可分为“用户程序调用系统调用 处理程序(system_call)”和“系统调用处理程序 调用各个服务例程”两部分,下面分两部分来说 明:(1)Linux的系统调用使用第0x80号中断向量项作为总的入口,即系 统调用处理程序的入口地址;(2)在系统调用处理程序中,通过语句“call * SYMBOL_NAME(sys_call_table)(,%eax,4)”来调用各 个服务程序。系统调用处理程序及服务例程 v每个系统调用至少有一个参数,即通过eax寄存器传 递来的系统调用号; v系统调用处理程序的

9、参数首先传递给系统调用处理程 序在CPU中的寄存器,然后再复制到内核堆栈。 v用寄存器传递参数必须满足两个条件:每个参数的长度不能超过寄存器的长度参数的个数不能超过6个(包括eax中传递的系统调用号),若多于6个,用一个单独的寄存器指向 进程地址空间中这些参数值所在的一个内存区即可 。 v服务例程的返回值必须写到eax寄存器中。参数传递 / 提供类型提供类型pid_tpid_t的定义的定义 #include / / 提供函数的定义提供函数的定义 pid_tpid_t getpid(voidgetpid(void); );getpidgetpid的作用很简单,就是返回当前进程的进程的作用很简单,

10、就是返回当前进程的进程IDID,请看请看 以下的例子:以下的例子:/ / getpid_test.cgetpid_test.c #include main() main() printf(“Theprintf(“The current process ID is % current process ID is %dn“,getpiddn“,getpid();(); 编译并运行程序getpid_test.c:$gcc getpid_test.c -o getpid_test$./getpid_testThe current process ID is 19802.fork2.fork v在2.4

11、.4版内核中,fork是第2号系统调用,它 在Linux函数库中的原型是:#include / 提供类型pid_t的 定义 #include / 提供函数的定义 pid_t fork(void);vfork系统调用的作用是复制一个进程。当一个 进程调用它,完成后就出现两个几乎一模一样 的进程,也由此得到了一个新进程。与进程相关的系统调用n n/ fork_test.c / fork_test.c / #include / #include#include #include main() main() pid_tpid_t pidpid; ;n n/ /此时仅有一个进程此时仅有一个进程 pidp

12、id=fork();=fork(); /此时已经有两个进程在同时运行此时已经有两个进程在同时运行 if(pidif(pidvoid exit(int status); v从exit的名字就能看出,这个系统调用是用来 终止一个进程的。无论在程序中的什么位置, 只要执行到exit系统调用,进程就会停止剩下 的所有操作,清除包括PCB在内的各种数据结 构,并终止本进程的运行。/ exit_test1.c #include / #include#includemain() printf(“this process will exit!n“); exit(0); printf(“never be dis

13、played!n“); 编译后运行:$gcc exit_test1.c -o exit_test$./exit_test1this process will exit! 可以看到,程序并没有打印后面的“never be displayed!n“ ,因为在此之前,在执行到exit(0)时,进程就已经终止了 。exit系统调用带有一个整数类型的参数 status,可以利用这个参数传递进程结 束 时的状态,比如说,该进程是正常结束 的 ,还是出现某种意外而结束的,一般来 说 ,0表示没有意外的正常结束;其他的 数 值表示出现了错误,进程非正常结束。 在 实际编程时,可以用wait系统调用接收 子 进

14、程的返回值,从而针对不同的情况进 行 不同的处理。v在一个进程调用了exit之后,该进程并非 马上就消失掉,而是留下一个称为僵尸进 程(Zombie)的数据结构。v在Linux进程的5种状态中,僵尸进程是非 常特殊的一种,它已经放弃了几乎所有内 存空间,没有任何可执行代码,也不能被 调度,仅仅在进程列表中保留一个位置, 记载该进程的退出状态等信息供其他进程 收集,除此之外,僵尸进程不再占有任何 内存空间。当一个进程已退出,但其父进程还没有调用系统 调用wait(稍后介绍)对其进行收集之前的这 段时间里,它会一直保持僵尸状态,利用这个 特点,来写一个简单的小程序:/ zombie.c #incl

15、ude #include main() pid_t pid; pid=fork();if(pidif(pid1579 pts/0R 0:00 ps -ax 中间的“Z”就是僵尸进程的标志,它表示1578号进程现 在就是一个僵尸进程。4.wait wait调用可收集僵尸进程留下的信息,同时使这 个进程彻底消失。waitwait的函数原型是:的函数原型是: #include / #include / 提供类型提供类型pid_tpid_t的定义的定义 #include #include pid_tpid_t wait(intwait(int * *statusstatus) )进程一旦调用了进程一旦调用了waitwait,就立即阻塞自己,由就立即阻塞自己,由waitwait自动分析是自动分析是 否当前进程的某个子进程已经退出,如果让它找到了这样一否当前进程的某个子进程已经退出,如果让它找到了这样一 个已经变成僵尸的子进程,个已经变成僵尸的子进程,waitwait就会收集这个子进程的信息就会收集这个子进程的信息 ,并把它彻底销毁后返回;如果没有找到这样一个子进程,并把它彻底销毁后返回;如果没有找到这样一个子进程, waitwait就会一直阻塞在这里,直到有一个出现为止。就会一直阻塞在这里,直到有一个出现为止。参数参数stat

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 商业/管理/HR > 其它文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号