对Linux下系统调用的理解

系统调用是应用程序在执行过程中向系统内核申请服务的过程,这些服务包含硬件相关的服务、申请资源、创建进程或者线程。比如要程序要从硬盘读取数据,需要调用fopen打开文件,fread读取文件内容等。

应用程序运行在用户空间,系统以及驱动程序运行在内核空间。如图:

 

举一个形象的例子,我们去银行柜台取钱,客户与银行柜员被玻璃窗分开,柜员所在空间可以看成内核空间,客户所在银行大厅可以看做用户空间。客户把银行卡递给银行柜员,然后根据银行卡上面的存款数目,取出相应的钱,可以看成一次系统调用。至于为什么用户空间和内核空间要隔开,当然是为了安全,如果没有玻璃窗,客户可以随便取钱,那就成了抢银行了,那肯定是不行的。

比如在32位的Linux上运行的应用程序有4GB的虚拟地址空间

 

0xC000,0000~ 0xFFFF,FFFF为系统空间,0x0000,0000~0xC000,0000为用户空间,通过malloc/new申请堆内存资源,便是从0x0000,0000开始向上分配,而函数中参数、局部变量属于栈空间,从0xC000,0000开始向下分配。而不会用到系统空间内存。

系统调用函数数就是操作系统提供给用户程序调用系统资源的一组接口。这样做就使得应用程序与硬件完全隔开,用户不需要关心底层系统调用硬件是如何实现的,降低了编程的难度。同时也提高了系统的安全性,防止用户非法使用资源,使得系统不稳定。还有就是提升了程序的可移植性,不同的系统提供相同的系统调用接口,这样相同的程序就可以运行在不同的硬件和平台上。

用户程序调用系统调用使程序从用户态陷入到内核态。此时程序等待系统调用返回,由于内核进程调度,可能会切换其他进程开始执行,等系统调用返回再继续执行。其中涉及程序挂起保存程序运行所需上下文,根据用户程序传入系统调用号,确定具体的系统调用,等系统调用返回,再根据上下文恢复现场,继续向下执行。所以频繁的系统调用会影响程序的执行效率,这个我们需要注意合理进行系统调用。

 

Linux提供了syscall间接的系统调用。查看man手册

NAME

     syscall - indirect system call

 

SYNOPSIS

     #include <sys/syscall.h>

     #include <unistd.h>

 

     int

     syscall(int number, ...);

 

DESCRIPTION

     Syscall() performs the system call whose assembly language interface has the specified number with the specified arguments.  Symbolic constants for system calls can be found in

     the header file 〈sys/syscall.h〉.

 

RETURN VALUES

     The return value is defined by the system call being invoked.  In general, a 0 return value indicates success.  A -1 return value indicates an error, and an error code is

     stored in errno.

 

我们可以根据指定的参数number也就是系统调用号和根据所调用系统所需的参数来进行系统调用。当然glibc作为linux下使用的开源的标准C库,对系统调用进行了封装,一般失败会返回-1,错误码存在errno中。

glibc是GUN发布的libc库,可移植性好,用起来也比较方便。如果有glibc提供的接口,我们尽量用glibc提供的接口。除非需要定制自己的系统调用,我们可以用syscall进行系统调用。

猜你喜欢

转载自blog.csdn.net/qq_19825249/article/details/108195994