`

系统调用与函数调用的区别

阅读更多

1 、系统调用和库函数的关系

系统调用通过软中断 int 0x80 从用户态进入内核态。

函数库中的某些函数调用了系统调用。

函数库中的函数可以没有调用系统调用,也可以调用多个系统调用。

编程人员可以通过函数库调用系统调用。

高级编程也可以直接采用 int 0x80 进入系统调用,而不必通过函数库作为中介。

如果是在核心编程,也可以通过 int 0x80 进入系统调用,此时不能使用函数库。因为函数库中的函数是内核访问不到的。

2 从用户调用库函数到系统调用执行的流程。

1) 假设用户调用 ssize_t write (int fields, cont void *buff, size_t nbytes); 库 函数。

2) 库函数会执行 int 0x80 中断。因为中断使得进程从用户态进入内核态,所以参数通过

寄存器传送。

3) 0x80 中断对应的中断例程被称为 system call handler 。其工作是:

i. 存储大多数寄存器到内核堆栈中。这是汇编代码写的。

ii. 执行真正的系统调用函数―― system call service routine 。这是 C 代码。

iii. 通过 ret_from_sys_call () 返回,回到用户态的库函数。这是汇编代码。

转自:http://hi.baidu.com/shcup/blog/item/b0a96c1205bbb2ddf7039e95.html

Linux 下对文件操作有两种方式:系统调用 ( system call )和库函数调用( Library functions )。可以参考《 Linux 程序设计》(英 文原版为《 Beginning Linux Programming 》,作者是 Neil Matthew Richard Stones )第三章 : Working with files

1 、系统调用

系统调用提供的函数如 open, close, read, write, ioctl 等,需包含头文件 unistd.h 。以 write 为例:其函数 原型为 size_t write(int fd, const void *buf, size_t nbytes) ,其操作对象为文件描述符或文 件句柄 fd(file descriptor) ,要想写一个文件,必须先以可写权限用 open 系统调用打开一个文件,获得所打开文 件的 fd ,例如 fd=open(\"/dev/video\", O_RDWR) fd 是一个整型值,每新打开一个文件,所获得 的 fd 为当前最大 fd 1 Linux 系统默认分配了 3 个文件描述符值: 0 standard input 1 standard output 2 standard error

系统调用通常用于底层文件访问( low-level file access ), 例如在驱动程序中对设备文件的直接访问。

系统调用是操作系统相关的,因此一般没有跨操作系统的可移植性。

系统调用发生在内核空间,因此如果在用户空间的一般应用程序中使用系统调用来进行文件操作,会有用户 空间到内核空间切换的开销。事实上,即使在用户空间使用库函数来对文件进行操作,因为文件总是存在于存储介质上,因此不管是读写操作,都是对硬件(存储 器)的操作,都必然会引起系统调用。也就是说,库函数对文件的操作实际上是通过系统调用来实现的。例如 C 库函数 fwrite() 就是通过 write() 系统调用 来实现的。

这样的话,使用库函数也有系统调用的开销,为什么不直接使用系统调用呢?这是因为,读写文件通常是大 量的数据(这种大量是相对于底层驱动的系统调用所实现的数据操作单位而言),这时,使用库函数就可以大大减少系统调用的次数。这一结果又缘于缓冲区技术。 在用户空间和内核空间,对文件操作都使用了缓冲区,例如用 fwrite 写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲区满或者写操作结束时,才将用户缓冲区的 内容写到内核缓冲区,同样的道理,当内核缓冲区满或写结束时才将内核缓冲区内容写到文件对应的硬件媒介。

2 、库函数调用

标准 C 库函数提供的文件操作函数如 fopen, fread, fwrite, fclose, fflush, fseek 等,需包含头文件 stdio.h 。以 fwrite 为例,其函数原型为 size_t fwrite(const void *buffer, size_t size, size_t item_num, FILE *pf) ,其操作对象为文件指针 FILE *pf ,要想写一个文件,必须先以可写权限用 fopen 函数打开一个 文件,获得所打开文件的 FILE 结构指针 pf ,例如 pf=fopen(\"~/proj/filename\", \"w\") 。实际上,由于库函数对文件的操作最终是通过系统调用实现 的,因此,每打开一个文件所获得的 FILE 结构指针都有一个内核空间的文件描述符 fd 与之对应。同样有相应的预定义的 FILE 指针: stdin standard input stdout standard output stderr standard error

库函数调用通常用于应用程序中对一般文件的访问。

库函数调用是系统无关的,因此可移植性好。

由于库函数调用是基于 C 库的,因此也就不可能用于内核空间的驱动程序中对设备的操作

转自 http://blog.csdn.net/mmz_xiaokong/archive/2010/03/17/5390372.aspx

理解库函数的区别和系统调用,首先要里理解 Unix kernel mode user mode 。考虑下面的函数段:

int main()

{

int fd = create("filename",0666);

exit(0);

}

在执行 main 函数时,是在 user mode 下执行,当遇到 create 函数时,继续在 user mode 下执行。然后系统将两个参数 "filenam" "0666" 压入栈中或者某个寄存器,接着执行库函数 create 。在库函数 create 执行开始,系统仍然处在 user mode 下,接着系统将 create 系统调用的 unique number 压入寄存器(比如说 r0 ),然后执行指令 trap operating system trap )使系统进入 kernel mode ,并且处理系统调用。这时,系统意识到要进行系统调用的 invoke ,于是从寄存器 r0 中取出 create 系统调用的 unique number ,从系统调用表中查找得知要 invoke 的系统调用是 create ,然后执行。执行完毕后返回库函数 create 的调用,库函数负责检查系统调用的执行情况(检查某些寄存器的值),然后库函数 create 根据检查的结果返回相应的值。

在这里, trap 指令类似于一个系统中断,而系统调用 create 是一个特殊的中断处理函数( inerrupt handler )。

APUE UNIX 环境高级编程)上的陈述:

所有操作系统都提供多种服务的入 口点,由此程序向系统核请求服务。各种版本的 Unix

提供经良好定义的有限数目的入口 点,经过这些入口点进入系统核,这些入口点被称之为

系统调用 (system call) ,系统调用是我们不能更改的一种 Unix 特征。 Unix 版本 7 提供了约

50 个系统调用, 4 3+BSD 提供了约 110 个,而 SVR4 则提供了约 120 个。

系统调用界面总是在 Unix 程序员手册的第二部分中说明。其定义也包括在 C 语言中。这与很 多较早期的操作系统是不同的,这些系统按传统都在机器的汇编语言中定义系统核入口点。

Unix 所使用的技术是为每条系统调用在标准 C 库中设置一个具有同样名字的函数。用户进程用标准 C 调用序列来调用这些函数,然后,函数用系统所要求的技术调用相应的系统核服务。

例如函数可将一个或几个 C 参数送入通用寄存器,然后执行某个产生软中断进入系统核的机器指令。从应用角度考虑,我们可将系统 调用视作为 C 函数。

Unix 程序员手册的第三部分定义了程序员可以使用的通用函数。虽然这些函数可能会调用 一个或几个系统核的系统调用, 但是它们并不是系统核的入口点。例如, printf 函数会调 write 系统调用以进行输出操作,但函数 strcpy( 复制一字符串 ) atoi( 变换 ASCII 为整数 ) 并不使用任何系统调用。

从实施者的角度,系统调用和库函 数之间有重大区别,但从用户角度其区别并不非常重要。 从本书的目的出发,系统调用和库函数在本书中都以正常的 C 函数的形式出现。两者都对应 用程序提供服务,但是,我们应当理解,如果希望的话,我们可以代换库函数,但是通常我们却不能代换系 统服务。

以存储器分配函数 malloc 为例。有多种方法可以进行存储器分配及与其相关的无用区收集 操作 ( 最佳适应,首次适应等 ) ,并不存在对所有程序都最佳的一种技术。 Unix 系统调用中 处理存储器分配的是 sbrk(2) ,它不是一个通用的存储器管理器。它增加或减少指定字节数 的进程地址空间。如何管理该地 址空间却取决于进程。存储器分配函数 malloc(3) 实现一 种特定类型的分配。如果我们不喜欢其操作方式,则我们可以定义自己的 malloc 函数,极 其可能,它还是要调用 sbrk 系统调用。事实上,有很多软件包,它们实现自己的存储器分 配算法,但仍使用 sbrk 系统调用。

从中可见,两者职责不同,相互分 开,要核中的系统调用分配另外一块空间给进程,而库 函数 malloc 则管理这种空间。

另一个可说明系统调用和库函数之 间的差别的例子是, Unix 提供决定当 前时间和日期的界 面。某些操作系统提供一个系统调用以返回时间,而另一个则返回日期。任何特殊的处理 ,例如正常时制和日光节约时制 之间的转换,由系统核处理或要求人的干予。 Unix 则不同 ,它只提供一条系统调用,该系统调用返回国际标准时公元一九七 年一月一日午夜来所以 经过的秒数。对该值的任何解释, 例如将其变换成人们可读的,使用本地时区的时间和日 期,都留给用户进程运行。在标准 C 库中,提供了若干例程以处理大多数情况。这些库函数处理各种细节,例如各种日光节约时算法。

应用程序可以或者调用系统调用, 或者库函数,而很多库函数则会调用系统调用。 另一个系统调用和库函数之间的差别是:系统调用通常提供一种最小界面,而库函数通常 提供比较复杂的功能。我们从 sbrk 系统调用和 malloc 库函数之间的差别中看到了这一点, 在以后当比较不带缓存的 I/O 库数 ( 3 ) 以及标准 I/O 标准 ( 在第 5 ) 时,我们还将看到这 种差别。

进程控制系统调用 (fork exec wait) 通常由用户的应用程序直接调用。 ( 请回忆程序 1.5 的基本 shell) 但是为了简化某些常见的情况, UNIX 系统也提供了一些库函数;例如 system popen 。在 8.12 节中,我们将说明 system 函数的一种实现,它使用基本的进程控制系统调用。在 10.18 中,我们还将强化这一实例以正确地处理信号。

为使读者了解大多数程序员应用的 Unix 系统界面,我们不得不既说明系统调用,只介绍某 些库函数。例如若我们只说明 sbrk 系统调用,那么就会忽略很多应用程序使用的 malloc 库函数。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics