
(系统调用)

大家好,很高兴又和大家见面啦!!!
在上一篇内容中我们介绍了操作系统中的中断与异常的相关内容:
在今天的内容中,我们会认识操作系统中的系统调用,下面我们进入今天的内容吧!!!
在前面的内容中,我们有介绍过,操作系统是作为用户和计算机硬件之间的接口,需要向上提供一些简单易用的服务。主要包括命令接口和程序接口。其中,程序接口是由一组系统调用组成。
graph TB
A[用户]
B[应用程序]
C[操作系统]
D[硬件]
A--->B--->C--->D
A--->C
C---> |命令接口| A
C---> |程序接口|B系统调用是操作系统提供给应用程序使用的接口,可视为一种供应用程序调用的特殊函数。应用程序可以通过系统调用请求获得操作系统内核的服务
既然系统调用可以设为特殊的函数,那么它又与库函数之间有哪些区别呢?
在我们学习的高级编程语言(如C语言、C++、JAVA……)中,这些高级语言会提供一些库函数供我们使用,如C语言中的标准输入函数:scanf,标准输出函数:printf,取绝对值函数:abs……,这些库函数有一些就会涉及到系统调用(如输入、输出函数),而另一些则不涉及(如取绝对值)。
因此,对比库函数而言,系统调用是实现某些库函数的更加底层的特殊函数。
高级编程语言会通过将一些系统调用封装成库函数,用来隐藏一些系统调用的细节,以便为程序员提供更加方便的编程功能。
系统调用(System Call)是用户应用程序(运行在“用户态”)请求操作系统内核(运行在“内核态”)为其提供服务或访问硬件资源的唯一通道和接口。
它的核心作用可以概括为:在保证系统安全、稳定和多任务高效运行的前提下,为应用程序提供必要的底层服务。
设想一下,当不存在系统调用时,若多个应用程序要访问同一个共享资源,此时会出现什么情况呢?
如果没有系统调用,多个应用程序同时尝试使用一个共享资源(如CPU、内存、硬盘、打印机、网络等),整个系统将陷入混乱、冲突和不安全的状态。
具体会出现的问题可以分为以下几类:
没有系统调用,操作系统就无法接管CPU的控制权。
没有系统调用,所有程序的内存空间将完全不设防。
对于打印机、硬盘、声卡等硬件,如果没有协调,输出将会是混乱的。
这与设备竞争类似,但更侧重于文件等数据资源。
也就是说,如果没有系统调用,计算环境将退回到无政府状态:
因此,系统调用是操作系统为用户程序提供服务的唯一安全通道,同时也是管理和保护系统资源的最根本机制。它就像是城市中的交通信号灯和交通法规,如果没有它们,所有车辆(应用程序)在路口(共享资源)只会挤成一团,事故频发,谁也无法高效通行。
系统中的各种共享资源都由操作系统同一掌管,因此凡事与共享资源相关的操作(如存储分配、I/O传输及文件管理等),都必须通过系统调用方式向操作系统提出服务请求,由操作系统代为完成,并将处理结果返回给应用程序。这样就可以保证系统的稳定性和安全性,防止用户进行非法操作。
通常,一个操作系统提供的系统调用命令有几十条乃至上白条之多,每个系统调用都有唯一的系统调用号。这些系统调用按功能大致可以分为以下几类:
显然,系统调用相关功能涉及系统资源管理、进程管理之类的操作,对整个系统的影响非常大,因此系统调用的处理需要由操作系统内核程序负责完成,要运行在内核态。
在说明系统调用过程之前,我们需要先理解什么是陷入指令:
陷入指令(Trap Instruction) 是计算机体系结构和操作系统中一个非常关键的概念。它指的是一条特殊的机器指令,当 CPU 执行这条指令时,会主动、有意识地触发一个从用户态(User Mode)到内核态(Kernel Mode)的切换,并将控制权交给操作系统内核预先定义好的处理程序。
下面我们再来看一下系统调用的整个过程:
graph TB
A[系统调用号1]
B[系统调用号2]
C[参数1]
D[参数2]
E[堆栈]
F[...]
A--->E
B--->E
F--->E
C--->E
D--->E
f[...]--->E
G[陷入指令]graph TB
A[CPU]--->B[调用指令1]
A--->C[调用指令2]
A--->D[...]graph LR
f[用户态CPU]--->e[陷入指令]--->a[内核态CPU]graph TB
a[PC]
B[PSW]
C[通用寄存器存内容]
e[...]
f[堆栈]
a--->f
B--->f
C--->f
e--->fgraph LR
a[系统调用1]--->b[CPU]--->c[系统调用1处理子程序]
d[系统调用2]--->b--->e[系统调用2处理子程序]
f[...]--->b--->g[...]为了更好的分析系统调用类型,在系统中配置了一张系统调用入口表,表中的每个表项都对应一个系统调用,根据系统调用号可以找到该系统调用处理子程序的入口地址,如下所示:
系统调用号 | 子程序入口地址 |
|---|---|
000000 | 123456 |
000001 | 112233 |
…… | …… |
graph LR
a[内核态CPU]--->B[用户态CPU]graph TB
A[系统调用号3]
B[系统调用号4]
C[参数3]
D[参数4]
E[堆栈]
F[...]
A--->E
B--->E
F--->E
C--->E
D--->E
f[...]--->E系统调用的整个过程,我们可以简单的理解为:
graph TB
A[用户态CPU执行用户程序进程]--->a[用户程序调用系统调用]--->b[用户态CPU执行陷入指令]--->c[内核态CPU执行系统调用]--->d[内核态CPU执行返回指令]
d--->e[用户态CPU执行后续进程]今天的内容到这里就结束了,通过本文的学习,我们系统地梳理了操作系统系统调用(System Call) 的核心概念与工作机制。让我们简单回顾一下重点:
理解系统调用,是理解操作系统如何管理资源、提供服务并保障安全的关键一步。
希望这篇内容对你有帮助!如果觉得有收获,欢迎点赞👍、收藏⭐️!有任何想法或问题,也欢迎在评论区💬留言交流。别忘了转发➡️给更多朋友,一起学习进步!
精彩继续,下一篇我们将学习《操作系统结构》,大家记得关注账号,不要错过更新!感谢大家的支持,我们下一篇再见!