第五讲系统调用new.ppt

上传人:本田雅阁 文档编号:2563346 上传时间:2019-04-09 格式:PPT 页数:120 大小:1.45MB
返回 下载 相关 举报
第五讲系统调用new.ppt_第1页
第1页 / 共120页
第五讲系统调用new.ppt_第2页
第2页 / 共120页
第五讲系统调用new.ppt_第3页
第3页 / 共120页
亲,该文档总共120页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第五讲系统调用new.ppt》由会员分享,可在线阅读,更多相关《第五讲系统调用new.ppt(120页珍藏版)》请在三一文库上搜索。

1、第五讲 系统调用,系统调用简介 文件管理 进程管理 信号 进程间通信,1,5.1系统调用简介,系统调用概念 为了利用创建文件、进程创建和复制及进程间通信这些操作系统提供的服务,应用程序必须和操作系统之间交互。这种交互通过“系统调用”来实现。 系统调用是程序员和linux内核的函数接口。 对程序员来说,系统调用就象库函数(事实上有些就是库函数,由这些库函数再进行真正的系统调用),只是前者直接在linux的核心执行子程序调用。,2,系统调用类别,文件管理 进程管理 错误管理,3,文件管理系统调用的层次结构,文件,特殊文件,目录文件,open,close,read,write,lseek,unlin

2、k,chown dup2 fcntl fstat ftruncate stat truncate sync dup link,套接字,Internet套接字,mknod ioctl pipe,getdents,accept bind connect listen socket,gethostbyname gethostname htonl htons inet_addr inet_ntoa,4,进程管理系统调用的层次结构,进程,信号,nice chdir wait fork exec exit,alarm singnal kill pause,5,错误处理系统调用的层次结构,错误处理,perr

3、or,6,5.2 文件管理,文件管理系统调用能够操作所有的普通文件、特殊文件和目录文件,包括: 基于磁盘的文件 终端 打印机等设备 进程间通信功能,如管道和套接字 多数情况下,最初使用open()访问或创建文件,如果系统调用成功,则返回一个称为“文件描述符”的小整数,用于对该文件的I/O操作。如果open()失败,返回-1。,7,int fd; /file descriptor fd=open(fileName,); /*open file, return file descriptor*/ If(fd=-1) /*deal with error condition */ fcntl (fd,

4、); /*set some I/O flags if necessary */ ,典型的文件操作事件序列,8,read(fd,); /* read from file */ write(fd,); /write to file lseek(fd,); /seek within file close(fd); /close the file,freeing file descriptor,典型的文件操作事件序列,9,文件描述符从0开始按顺序编号,前三个描述符具有特定含义: 0 标准输入(stdin)- - -键盘 1 标准输出(stdout)- - -显示器 2 标准错误(stderr) 单个文

5、件能打开几次,因此它可以有多个文件描述符,文件,fd1,fd2,fd3,5.2.1文件描述符,10,每个文件描述符有其专有的属性集,与它所关联的文件无关。这些属性包括: 记录文件中进行读写操作的偏移量的文件指针; 指示如果进程调用exec(),文件描述符是否应自动关闭的标志; 指示对文件的所有输出是否应追加到文件末尾的标志;,5.2.1文件描述符,11,以下属性只在文件是管道和套接字这样的特殊文件时才有意义: 指示如果文件当前不包含任何输入,进程是否应阻塞来自该文件的输入的标志; 指示如果文件输入变为可用,应发送一个SIGIO信号的进程ID或进程组的数字; 系统调用open()和fcntl()

6、能操作这些标志。,5.2.1文件描述符,12,打开文件open() 读文件read() 写文件write() 移动文件指针lseek() 关闭文件close() 删除文件unlink(),5.2.2 文件管理系统调用,13,函数定义 int open (char *fileName, int mode ,int permissions) open只能以只读或读写方式打开或创建文件,fileName是一个绝对/相对路径的文件名,mode打开模式,permissions是代表文件权限标志的一个编码值,该值只在创建文件时提供。 预定义的读/写标志和混合标志的值在”/usr/include/fcntl

7、.h”中定义: O_RDONLY以只读方式打开; O_WRONLY以只写方式打开; O_RDWR以读写方式打开,5.2.2.1 打开文件open(),14,创建文件 /.开始的文件名使其成为隐藏文件 sprintf ( tmpName,”. rev.%d”, getpid(); /创建临时文件,可读写,设置文件权限 tmpfd=open (tmpName, O_CREAT | O_RDWR,0600) if(tmpfd=-1) fatalError(); 打开已经存在的文件 fd=open (fileName, O_RDONLY); if (fd=-1) fatalError();,5.2.2

8、.1打开文件open(),15,函数定义 ssize_t read(int fd, void* buf, size_t count) read()从文件描述符fd引用的文件读取count个字节到缓冲区buf。 调用成功,read()返回它读取的字节数,否则返回-1;如果在已经读取了最后一个字节后调用read(),它返回0,表示到达了文件末尾。 例:charsRead=read (fd, buffer, BUFFER_SIZE); if(charRead=0) break; / end of file If(charRead=-1) fatalError(); /error,5.2.2.2读文件

9、read(),16,函数定义 ssize_t write(int fd, void* buf, size_t count) write()从缓冲区buf向文件描述符fd引用的文件复制count个字节。 字节从当前文件位置开始写入,然后更新当前文件位置。如果设置fd的O_APPEND标志,则每次写操作前文件位置被置为文件末尾。 调用成功,write()返回它复制的字节数,否则返回-1;进程应该总是检查返回值,如果返回值不是count,可能磁盘已写满。,5.2.2.3写文件write(),17,例: /* Copy line to temporary file if reading from st

10、din */ if (standardInput) charsWritten = write (tmpfd, buffer, charsRead); if(charsWritten != charsRead) fatalError (); ,5.2.2.3写文件write(),18,函数定义 off_t lseek(int fd, off_t offset, int mode) fd是文件描述符,offset是一个长整数,mode描述该如何解释offset。 “/usr/include/stdio.h”中定义了mode的三个取值: SEEK_SET offset相对于文件的开始 SEEK_CU

11、R offset相对于当前文件位置 SEEK_END offset相对于文件末尾,5.2.2.4移动文件指针lseek(),19,如果试图移动文件指针到文件头之前,lseek()会失败。 如果成功,lseek()返回当前文件指针位置,否则返回-1 例: /* Find line and read */ lseek (fd, lineStarti, SEEK_SET); charsRead = read (fd, buffer, lineStarti+1 - lineStarti);,5.2.2.4 移动文件指针lseek(),20,函数定义 int close(int fd) 如果fd是和特定

12、打开文件关联的最后一个文件描述符,给该文件分配的内核资源将被收回。 当一个进程结束时,它所有的文件描述符都会自动关闭,但最好当完成文件操作时关闭文件。 如果关闭一个已经关闭的文件,会发生错误。 调用成功,close()返回0,否则返回-1。 例: close (fd); /* Close input file */,5.2.2.5 关闭文件close(),21,函数定义 int unlink(const char* fileName) unlink()删除从文件名fileName指向文件的硬链接。如果fileName是指向文件的最后一个链接,文件的资源被收回。 如果调用成功,unlink()返

13、回0,否则返回-1。 例: /* Remove temp file */ if (standardInput) unlink (tmpName);,5.2.2.6 删除文件unlink(),22,例:reverse -c fileName reverse将输入文件的各行逆序显示在标准输出上。如果不指定文件名,则逆序显示标准输入的内容。 当使用-c选项时,reverse还颠倒每一行中的字符。 $gcc reverse.c -o reverse $cat test Chirstmas is coming, The days that grow shorter. $./reverse c test

14、.retrohs worg that syad ehT ,gnimoc si samtsrihC,5.2.3文件管理实例,23,例:reverse -c fileName $cat test | ./reverse The days grow shorter. Christmas is coming.,5.2.3文件管理实例,24,reverse的工作过程 步骤 操作 函数 系统调用 分析命令行 ParseCommmandLine, open processOptions 打开输入文件或 读取标准输入,创 pass1 open 建存储输入的临时文件 读取文件,把各行的起始 pass1,trac

15、kLines read 偏移量保存在数组中 反向读取文件,把每行复制 pass2,processLine, lseek 到标准输出,如果选择-c, reverseLine 字符也会逆序输出。 关闭文件,如果是临时文件, pass2 close 删除临时文件,25,名称 功能 stat() 获得文件信息 opendir() 打开目录 readdir() 读目录 closedir() 关闭目录 chown() 改变文件所有者和文件组 chmod() 改变文件权限 dup() 复制文件描述符 fcntl() 对各种文件特性的访问,5.2.4其他文件管理系统调用,26,名称 功能 truncate 截

16、短文件 sync 调度所有文件缓冲区清空到磁盘 mknod 创建特殊文件 link 创建硬链接 ioctl 控制设备 fchown 同chown fchmod 同chmod dup2 同dup ftruncate 同truncate,27,例1:把文件test.txt的组改为cs,该组的组ID为62 /*mychown.c*/ main () int flag; flag = chown (“test.txt“, -1, 62); /* Leave user ID unchanged */ if (flag = -1) perror(“chown.c“); $ls -l test.txt -r

17、w-r-r- 1 glass music 3 May 25 11:42 test.txt $ls -l test.txt -rw-r-r- 1 glass cs 3 May 25 11:42 test.txt,5.2.4其他文件管理系统调用,28,例2:把文件test.txt的权限标志改为600,即只有文件所有者拥有读写权限。 /*mychomod.c*/ main () int flag; flag = chmod (“test.txt“, 0600); /* Use an octal encoding */ if (flag = -1) perror (“chmod.c“); $ls -l

18、 test.txt -rw-r-r- 1 glass music 3 May 25 11:42 test.txt $ls -l test.txt -rw- 1 glass cs 3 May 25 11:42 test.txt,5.2.4其他文件管理系统调用,29,例3:创建一个文件test.txt,然后通过4个不同的文件描述符写这个文件。 /*mydup.c*/ #include #include main () int fd1, fd2, fd3; fd1 = open (“test.txt“, O_RDWR | O_TRUNC); printf (“fd1 = %dn“, fd1); wr

19、ite (fd1, “whats“, 6);,5.2.4其他文件管理系统调用,30,例3:续 fd2 = dup (fd1); /* Make a copy of fd1 */ printf (“fd2 = %dn“, fd2); write (fd2, “ up“, 3); close (0); /* Close standard input */ fd3 = dup (fd1); /* Make another copy of fd1 */ printf (“fd3 = %dn“, fd3); write (0, “ doc“, 4); dup2 (fd3, 2); /* Duplicat

20、e channel 3 to channel 2 */ write (2, “?n“, 2); ,5.2.4其他文件管理系统调用,31,读取文件属性,32,struct stat,33,读取文件属性代码,if(stat(argv1,34,打开/关闭目录文件,35,读写目录内容,36,示例,37,定位目录位置,38,添加删除目录,39,返回/修改当前工作路径操作,40,示例,41,进程相关的定义: 1 进程是一个独立的可调度的活动。 进程是一个抽象实体,当它执行某个任务时,要分配和释放各种资源。 进程是可以并行执行的计算部分。 进程是一个具有独立功能的程序,关于某个数据集合的一次可以并发执行的活

21、动,是处于活动状态的计算机程序。是Linux系统基本调度单位。 进程和程序的区别: 几个进程可以并发的执行一个程序 一个进程可以顺序的执行几个程序,5.3 进程管理,42,Linux进程是一个正在运行或可运行的程序的唯一实例。 Linux系统中的每个进程都具有下列属性: 一些代码 一些数据 一个堆栈 一个唯一的进程号PID Init进程:linux系统启动时,系统中只有一个可见进程,叫init,其PID为1。在linux创建进程的唯一方法是复制现有进程,所以init进程是所有随后进程的祖先进程。,5.3 进程管理,43,当一个进程复制时,父进程和子进程实际上是完全相同的(除了PID,PPID和

22、运行库等。) 子进程的代码、数据和堆栈是父进程的副本。但是子进程也许会把代码替换为另一个可执行文件的代码,将自己和父进程区分开来。 子进程终止时,系统将它的死亡消息传递给父进程,以便父进程采取适当的操作。,5.3.1 父进程和子进程,44,5.3.2 进程的状态,一个既在的进程调用fork创建一个新进程,TASK_ZOMBIE(进程被终止),TASK_RUNNING(就绪,但是没有在运行),TASK_RUNNING(正在运行),进程等待中,Task forks,进程调度选择一个task,进程被高优先级的进程抢占,进程调用do_exit()终止执行,进程睡眠,在等待特定事件或资源的等待队列上,事

23、件发生或资源可用,进程被唤醒,并被放到运行队列中,45,执行,等待,就绪,时间片到,调度,因等待事件发生而唤醒,等待某个事件发生而睡眠,5.3.2 进程的状态,46,fork 复制进程 getpid 获得进程号PID getppid 获得父进程号PPID exit 终止进程 wait 等待子进程 exec 替换进程的代码、数据和堆栈,5.3.3 进程管理的系统调用,47,函数定义 pid_t fork(void) fork()使进程复制自己。子进程继承父进程的代码、数据、堆栈、打开的文件描述符和信号表的副本。子进程的PID和父进程的PPID不同。 调用成功,返回子进程的PID给父进程,返回0给

24、子进程。调用失败,返回-1给父进程,没有创建子进程。,5.3.3.1 fork(),48,例1:fork()的使用。 /*myfork.c*/ #include main () int pid; printf (“Im the original process with PID %d and PPID %d.n“, getpid (), getppid (); pid = fork (); /* Duplicate. Child and parent continue from here */ if (pid != 0) /* pid is non-zero, so I must be the

25、 parent */ printf (“Im the parent process with PID %d and PPID %d.n“, getpid (), getppid (); printf (“My childs PID is %dn“, pid); else /* pid is zero, so I must be the child */ printf (“Im the child process with PID %d and PPID %d.n“, getpid (), getppid (); printf (“PID %d terminates.n“, getpid ()

26、); /* Both processes execute this */ ,49,说明:1,父进程的PPID指向执行myfork.c 程序的shell的PID; 2,父进程不等待子进程的死亡就终止是非常危险的。 3,孤儿进程。如果父进程在子进程之前死亡,子进程就会自动被初始进程init收养。,init,子进程仍未终止,父进程首先死亡,收养子进程,5.3.3.1 fork(),50,例2:避免孤儿进程。 /*orphan.c*/ #include main () int pid; printf (“Im the original process with PID %d and PPID %d.n

27、“, getpid (), getppid (); pid = fork (); /* Duplicate. Child and parent continue from here */ if (pid != 0) /* Branch based on return value from fork () */ printf (“Im the parent process with PID %d and PPID %d.n“, getpid (), getppid (); printf (“My childs PID is %dn“, pid); else sleep (5); /* Make

28、sure that the parent terminates first */ printf (“Im the child process with PID %d and PPID %d.n“, getpid (), getppid (); printf (“PID %d terminates.n“, getpid () ); ,51,5.3.3.2 getpid()和getppid(),函数定义 pid_t getpid(void)和pid_t getppid(void) getpid()和geppid()分别返回 一个进程的ID和父进程的ID。 它们总能成功执行。,52,函数定义 voi

29、d exit(int status) exit()关闭一个进程的所有文件描述符,收回进程的代码、数据和堆栈,然后终止进程。 当进程终止时,它向父进程发送一个SIGCHLD信号,并等待它的终止码status被接受。status值在0255间。 等待父进程接受它的终止码的进程叫僵尸进程。父进程通用执行wait()接受子进程的终止码。 init进程总是会接受其子进程的终止码。 exit()不返回,5.3.3.3 exit(),53,例: /*myexit.c*/ #include Main() Printf(“Im going to exit with return code 42n”); exit

30、(42); 运行:$./myexit Im going to exit with return code 42 $echo $status 42,5.3.3.3 exit(),54,僵尸进程 终止的进程在父进程接受它的返回码之前不能离开系统。如果它的父进程已经死亡,它将成为孤儿被init收养。如果它的父进程还活着,但一直都没执行wait()接受子进程的返回码,该进程就成为僵尸进程。 僵尸进程没有任何代码、数据或堆栈,占用不了多少资源,但它存在于系统的任务列表中。,5.3.3.4 僵尸进程,55,例:僵尸进程 /*zombie.c*/ #include main () int pid; pid

31、= fork (); /* Duplicate */ if (pid != 0) /*Be parent process */ while (1) /* Never terminate, and never execute a wait () */ sleep (1000); else /*Be child process*/ exit (42); /* Exit with a silly number */ ,5.3.3.4 僵尸进程,56,$./zombie & 后台执行 $ps 显示进程状态 PID TTY TIME CMD 15870 pts2 00:00:00 bash 15896

32、pts2 00:00:00 zombie 15897 pts2 00:00:00 zombie 15898 pts2 00:00:00 ps $kill 15896 杀死父进程 $ps 15870 pts2 00:00:00 bash 15898 pts2 00:00:00 ps,5.3.3.4 僵尸进程,57,函数定义 pid_t wait(int* status) wait()使一个进程挂起,直到该进程的一个子进程终止。 wait()调用成功,返回终止子进程的PID,并把状态码放入status中。 如果一个进程执行wait() ,而它没有子进程,wait()调用失败,立即返回-1。如果进程

33、执行了wait(),而它的一个或几个进程已经是僵尸进程,则立即返回一个僵尸进程的状态码。,5.3.3.5 等待子进程wait(),58,例:系统调用wait() /*mywait.c*/ #include main () int pid, status, childPid; printf (“Im the parent process and my PID is %dn“, getpid (); pid = fork (); /* Duplicate */ if (pid != 0) /* Branch based on return value from fork () */ printf

34、(“Im the parent process with PID %d and PPID %dn“, getpid (), getppid (); childPid = wait ( ,59,函数定义 int execl(const char*path, const char* arg0, const char*arg1, , const char* argn, NULL) int execv(const char*path, const char* argv ) int execlp(const char* path, const char* arg0, const char*arg1, ,

35、 const char* argn, NULL) int execvp(const char*path, const char* argv ) execl和execlp完全相同,execv和execvp完全相同。execl()和execv()要求提供可执行文件的绝对或相对路径名,而execlp()和execvp()使用$PATH环境变量查找path。 如果没有找到可执行文件,系统调用返回-1;否则进程用可执行文件替换它的代码、数据和堆栈, exec的成功调用不返回任何值。,5.3.3.6区分进程exec(),60,例:/*myexec.c*/ #include main () printf (

36、“Im process %d and Im about to exec an ls -ln“, getpid (); execl (“/bin/ls“, “ls“, “-l“, NULL); /* Execute ls */ printf (“This line should never be executedn“); 运行:$./myexec Im process %d and Im about to exec an ls l total 125 -rw-r-r- 1 glass cs 277 Feb 15 00:47 myex.c ,5.3.3.6区分进程exec(),61,后台处理 例:

37、/*background.c*/ #include main (argc, argv) int argc; char* argv ; if (fork () = 0) /* Child */ execvp (argv1, 执行:$background sleep 60 $ps PID TTY TIME CMD 16073 pts0 00:00:00 sleep 60,62,函数定义 int nice(int delta) nice()在进程的当前优先级中添加delta。合法的优先级值在-20+19之间。只有超级用户(root)才能指定导致负值的delta。 如果调用成功,返回新的nice值,调

38、用失败返回-1。注意:这可能会导致问题,因为-1这个值是完全合法的。,5.3.3.7 改变优先级nice(),63,例:/*mynice.c*/ #include main () printf (“original priorityn“); system (“ps -l“); /* Execute a ps */ nice (0); /* Add 0 to my priority */ printf (“running at priority 0n“); system (“ps -l“); /* Execute another ps */ nice (10); /* Add 10 to my

39、priority */ printf (“running at priority 10n“); system (“ps -l“); /* Execute the last ps */ ,5.3.3.7 改变优先级nice(),64,uid_t getuid() 返回调用进程的真正用户ID uid_t geteuid() 返回调用进程的有效用户ID gid_t getgid() 返回调用进程的真正用户组ID gid_t getegid() 返回调用进程的有效用户组ID ID号对应在”/etc/passwd”和”/etc/group”文件中列出的用户ID和用户组ID,这些调用总是成功的。 int

40、setuid(uid_t id) int seteuid(uid_t id) int setgid(uid_t id) int setegid(uid_t id) 这些调用只有被超级用户执行或被调用进程的真正用户和用户组执行时才会成功。如果成功,返回0,否则返回-1。,5.3.3.8其它进程管理系统调用,65,5.4 信号,程序必须处理没有预期的或不可预知的事件,如: 浮点错误 掉电 闹钟“响铃” 子进程的死亡 用户的终止请求(即ctrl-c) 用户的挂起请求(即ctrl-z) 这些事件发生时,必须中断正常的程序流进行处理。当linux意识到发生这样的一个事件时,它会给相应进程发送一个信号。每

41、个可能的事件对应一个唯一的用数字表示的信号。,66,5.4.1 信号简介,例:如果进程中出现浮点错误,内核给出错的进程发送信号8,内核,进程,信号#8,浮点错误信号,67,不是只有内核才能发送信号,任何进程都可以 给其他进程发送信号,只要它有权限。 一段特殊的用于处理或忽略特定信号的程序叫 做“信号处理程序”。处理信号过程中,收到信号的进 程挂起它当前的控制流,执行信号处理程序,处理结 束时恢复原来的控制流。,5.4.1 信号简介,68,Linux支持两种信号类型: 1.标准信号-传统的UNIX信号 2.实时信号(或排队信号) 传统信号传递给进程是通过设置位图中的一位来完成的,位图中每一位对应

42、一个信号。因此,无法表示同一个信号的多个实例。因为位图只能表示1(有信号)和0(无信号) POSIX1003.1b为实时进程定义了排队信号。同一个信号的连续实例是有效的,需要被正确地传递。为了使用排队信号,必须使用系统调用sigaction(),而不是signal()。,5.4.2 信号类型,69,信号在”/usr/include/signal.h”或”/usr/include/asm/signal.h”和其他平台特定的头文件中定义。 程序员可以选择特定的信号触发用户提供的信号处理程序或内核提供的处理程序,或者忽略。 默认的处理程序通常执行下面的一个操作: (1)终止进程并在一个核心文件中生成

43、内存的转储(core) (2)终止进程,不生成核心映像文件(quit) (3)忽略并放弃信号(ingnore) (4)挂起进程(stop) (5)恢复进程(restore),5.4.3 信号定义,70,Linux中定义的标准POSIX信号 宏名 编号 默认操作 描述 SIGHUP 1 quit 控制进程的挂起或死亡 SIGINT 2 quit 键盘中断 SIGQUIT 3 core 退出 SIGILL 4 core 非法指令 SIGABRT 6 core 中止 SIGTSTP 20 stop 停止(挂起)进程 SIGTTIN 21 stop 后台读取tty设备 SIGTTOU 22 stop

44、后台写入tty设备,5.4.3 信号定义,71,Kill -l 命令可以查看所有的信号 kill -l 其它信号的定义及信息,参见帮助手册第7部分的信号内容。(“man 7 signal”) 终端信号 向前台进程发送信号的最简单的方法是按下键盘的ctrl-c键 或ctrl-z键。 (1)当终端识别出ctrl-c时,它向当前前台作业中的所有进程发送一个SIGINT信号。 (2)与此类似,ctrl-z使终端向当前前台作业中的所有进程发送一个SIGTSTP信号。 默认情况下,SIGINT 信号终止进程,SIGTSTP信号挂起进程。,5.4.3 信号定义,72,函数定义:unsinged int al

45、arm(unsigned int count) alarm()指示内核在经过count指定的秒数后发送SIGALARM信号(编号14)给调用进程。如果已经设置了闹钟,覆盖已设置的闹钟。如果count为0,表示取消以前的闹钟。 返回值为发送闹钟信号前所剩余的秒数 SIGALARM的默认处理程序显示信息“Alarm clock”并终止进程。,5.4.4 信号的工作过程 -请求闹钟信号alarm(),73,例:/*alarm.c*/ #include main () alarm (3); /* Schedule an alarm signal in three seconds */ printf (“Looping forever.n“); while (1); printf (“This li

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1