【Linux系统编程】 Linux系统调用概述

系统调用概述
系统调用,顾名思义,说的是操作系统提供给用户程序调用的一组“特殊”接口。用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务,比如用户可以通过文件系统相关的调用请求系统打开文件、关闭文件或读写文件,可以通过时钟相关的系统调用获得系统时间或设置定时器等。

从逻辑上来说,系统调用可被看成是一个内核与用户空间程序交互的接口——它好比一个中间人,把用户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给用户空间。

系统服务之所以需要通过系统调用来提供给用户空间的根本原因是为了对系统进行“保护”,因为我们知道 Linux 的运行空间分为内核空间与用户空间,它们各自运行在不同的级别中,逻辑上相互隔离。所以用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间函数。比如我们熟悉的“hello world”程序(执行时)就是标准的用户空间进程,它使用的打印函数 printf 就属于用户空间函数,打印的字符“hello word”字符串也属于用户空间数据。

但是很多情况下,用户进程需要获得系统服务(调用系统程序),这时就必须利用系统提供给用户的“特殊接口”——系统调用了,它的特殊性主要在于规定了用户进程进入内核的具体位置;换句话说,用户访问内核的路径是事先规定好的,只能从规定位置进入内核,而不准许肆意跳入内核。有了这样的陷入内核的统一访问路径限制才能保证内核安全无误。我们可以形象地描述这种机制:作为一个游客,你可以买票要求进入野生动物园,但你必须老老实实地坐在观光车上,按照规定的路线观光游览。当然,不准下车,因为那样太危险,不是让你丢掉小命,就是让你吓坏了野生动物。

系统调用的实现
系统调用是属于操作系统内核的一部分的,必须以某种方式提供给进程让它们去调用。CPU 可以在不同的特权级别下运行,而相应的操作系统也有不同的运行级别,用户态和内核态。运行在内核态的进程可以毫无限制的访问各种资源,而在用户态下的用户进程的各种操作都有着限制,比如不能随意的访问内存、不能开闭中断以及切换运行的特权级别。显然,属于内核的系统调用一定是运行在内核态下,但是如何切换到内核态呢?

答案是软件中断。软件中断和我们常说的中断(硬件中断)不同之处在于,它是通过软件指令触发而并非外设引发的中断,也就是说,又是编程人员开发出的一种异常(该异常为正常的异常)。操作系统一般是通过软件中断从用户态切换到内核态。
? ? ? ??

中断有两个重要的属性,中断号和中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表(Interrupt Vector Table),这个数组存储了所有中断处理程序的地址,而中断号就是相应中断在中断向量表中的偏移量。更多详细说明请看《系统调用的实现原理》。

系统调用和库函数的区别
Linux 下对文件操作有两种方式:系统调用(system call)和库函数调用(Library functions)。

库函数由两类函数组成:

1)不需要调用系统调用

不需要切换到内核空间即可完成函数全部功能,并且将结果反馈给应用程序,如strcpy、bzero 等字符串操作函数。

2)需要调用系统调用

需要切换到内核空间,这类函数通过封装系统调用去实现相应功能,如 printf、fread等。

系统调用是需要时间的,程序中频繁的使用系统调用会降低程序的运行效率。当运行内核代码时,CPU工作在内核态,在系统调用发生前需要保存用户态的栈和内存环境,然后转入内核态工作。系统调用结束后,又要切换回用户态。这种环境的切换会消耗掉许多时间。

库函数访问文件的时候根据需要,设置不同类型的缓冲区,从而减少了直接调用 IO 系统调用的次数,提高了访问效率。缓冲区详情请看《浅谈标准I/O缓冲区》。

这个过程类似于快递员给某个区域(内核空间)送快递一样,快递员有两种方式送:

1)来一件快递就马上送到目的地,来一件送一件,这样导致来回走比较频繁(系统调用)

2)等快递攒着差不多后(缓冲区),才一次性送到目的地(库函数调用)

原文地址:https://blog.51cto.com/14527980/2437492

时间: 2024-10-14 01:15:50

【Linux系统编程】 Linux系统调用概述的相关文章

Linux系统编程——Linux系统调用

系统调用概述 系统调用,顾名思义,说的是操作系统提供给用户程序调用的一组"特殊"接口.用户程序可以通过这组"特殊"接口来获得操作系统内核提供的服务,比如用户可以通过文件系统相关的调用请求系统打开文件.关闭文件或读写文件,可以通过时钟相关的系统调用获得系统时间或设置定时器等. 从逻辑上来说,系统调用可被看成是一个内核与用户空间程序交互的接口--它好比一个中间人,把用户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给用户空间. 系统服务之所以需要通过系统调

LINUX系统编程 由REDIS的持久化机制联想到的子进程退出的相关问题

19:22:01 2014-08-27 引言: 以前对wait waitpid 以及exit这几个函数只是大致上了解,但是看REDIS的AOF和RDB 2种持久化时 均要处理子进程运行完成退出和父进程需要做的什么事情,所以特定看了UNIX环境编程和LINUX系统编程这2本书 重新梳理下整个要点. 内容: 一般而言: 如果程序类似于下面的情况: if((pid=fork())==0) { dochildtthing(); exit(0); } else if(pid>0) { dofathertt

Linux系统编程@进程通信(一)

进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统的一个分支) POSIX进程间通信(POSIX:可移植操作系统接口,为了提高UNIX环境下应用程序的可移植性.很多其他系统也支持POSIX标准(如:DEC OpenVMS和Windows).) 现在Linux使用的进程间通信方式包括: 管道(pipe).有名管道(FIFO) 信号(signal) 消

Linux系统编程札记:进程通信(一)    

进程简单来讲就是一个程序的一次执行,这里说的进程一般都指的是运行在用户态的进程,而处于用户态的不同进程之间是彼此相互隔离的,它们必须通过某种方式来进行通信,具体理由如下: (1)数据传输:有时候一个进程需要将它的数据发送给另一个进程. (2)资源共享:有时候多个进程之间需要共享同样的资源. (3)通知事件:有时候一个进程需要向另一个或一组进程发送消息,通知它们发生了某个事件. (4)进程控制:有些进程希望能够完全控制另一个进程的执行,此时控制进程希望能够拦截另一进程的所有操作,并能够及时知道它的

嵌入式 Linux系统编程(一)——文件IO

嵌入式 Linux系统编程(一)--文件IO 一.文件IO概念 linux文件IO操作有两套大类的操作方式:不带缓存的文件IO操作,带缓存的文件IO操作.不带缓存的属于直接调用系统调用(system call)的方式,高效完成文件输入输出.它以文件标识符(整型)作为文件唯一性的判断依据.这种操作不是ASCI标准的,与系统有关,移植有一定的问题.而带缓存的是在不带缓存的基础之上封装了一层,维护了一个输入输出缓冲区,使之能跨OS,成为ASCI标准,称为标准IO库.不带缓存的方式频繁进行用户态 和内核

嵌入式 Linux系统编程(三)——标准IO库

嵌入式 Linux系统编程(三)--标准IO库 与文件IO函数相类似,标准IO库中提供的是fopen.fclose.fread.fwrite等面向流对象的IO函数,这些函数在实现时本身就要调用linux的文件IO这些系统调用. 一.标准IO库函数的缓冲机制 由于IO设备的访问速度与CPU的速度相差好几个数量级,为了协调IO设备与CPU的速度的不匹配,对于块设备,内核使用了页高速缓存,即数据会先被拷贝到操作系统内核的页缓存区中,然后才会从操作系统内核的缓存区拷贝到应用程序的地址空间. 当应用程序尝

嵌入式 Linux系统编程(四)——文件属性

嵌入式 Linux系统编程(四)--文件属性 一.文件属性概述 Linux 文件的属性主要包括:文件的节点.种类.权限模式.链接数量.所归属的用户和用户组.最近访问或修改的时间等内容.文件属性示例如下: 多个文件属性查看: ls -lih 1341714 -rw-r--r-- 1 root root 2.5K May 28 10:24 bit_marco.c 1341718 -rw-r--r-- 1 root root 2.1K May 28 09:08 bit_marco.c~ 1341706

嵌入式 Linux系统编程(六)——系统信息

嵌入式 Linux系统编程(六)--系统信息 一.时间 Linux系统下常用的时间类型:time_t.struct tm.struct timeval.struct timespec. 1.time_t类型时间 time_t实际是一个长整型.其值表示为从UTC(coordinated universal time)时间1970年1月1日00时00分00秒(也称为Linux系统的Epoch时间)到当前时刻的秒数.由于time_t类型长度的限制,它所表示的时间不能晚于2038年1月19日03时14分

linux系统编程之错误处理

在linux系统编程中,当系统调用出现错误时,有一个整型变量会被设置,这个整型变量就是errno,这个变量的定义在/usr/include/errno.h文件中 1 #ifndef _ERRNO_H 2 3 /* The includer defined __need_Emath if he wants only the definitions 4 of EDOM and ERANGE, and not everything else. */ 5 #ifndef __need_Emath 6 #

linux系统编程视频 百度网盘下载

本帖最后由 雇佣兵333 于 2015-5-19 16:15 编辑 c教程目录: Linux开发快速入门培训gcc快速入门Makefile快速入门GDB快速入门 Linux系统编程之文件篇01认识计算机系统(上)计算机系统组成计算机系统硬件组成总线I/O设备内存处理器(运算器+控制器) 02认识计算机系统(下)什么是操作系统Linux内核模块操作系统管理硬件操作系统三个基本抽象进程上下文切换进程虚地址空间虚拟文件系统(VFS) 03系统编程介绍系统编程与应用编程系统资源系统调用系统调用与C库关系