系统调用的类型六大类

系统调用大致可分为六大类:进程控制(process control)文件管理(file manipulation)设备管理(device manipulation)信息维护(information maintenance)通信(communication) 保护(protection)。

进程控制

执行程序应能正常(end())或异常(abort())停止执行。如果一个系统调用异常停止当前执行的程序,或者程序运行遇到问题并引起错误陷阱,那么有时转储内存到磁盘,并生成错误信息。内存信息转储到磁盘后,可用调试器(debugger)来确定问题原因(调试器为系统程序,用以帮助程序员发现和纠正错误(bug))。

无论是正常情况还是异常情况,操作系统都应将控制转到调用命令解释程序。命令解释程序接着读入下个命令。对于交互系统,命令解释程序只是简单读入下个命令,而假定用户会采取合适命令以处理错误。对于 GUI 系统,弹出窗口可用于提醒用户出错,并请求指引。对于批处理系统,命令解释程序通常终止整个作业,并继续下个作业。当出现错误时,有的系统可能允许特殊的恢复操作。

如果程序发现输入有错并且想要异常终止,那么它也可能需要定义错误级别。错误越严重,错误参数的级别也越高。通过将正常终止的错误级别定义为 0,可以把正常和异常终止放在一起处理。命令解释程序或后面的程序可以利用这种错误级别来自动确定下个动作。

执行一个程序的进程或作业可能需要加载(load())和执行(execute())另一个程序。这种功能允许命令解释程序来执行一个程序,该命令可以通过用户命令、鼠标点击或批处理命令来给定。一个有趣的问题是:加载程序终止时会将控制返回到哪里?与之相关的问题是:原有程序是否失去或保存了,或者可与新的程序一起并发执行?

如果新程序终止时控制返回到现有程序,那么必须保存现有程序的内存映像。因此,事实上创建了一个机制,以便一个程序调用另一个程序。如果两个程序并发继续,那么也就创建了一个新作业或进程,以便多道执行。通常,有一个系统调用专门用于这一目的(create_process() 或 submit_job())。

如果创建了一个新的作业或进程或者一组作业或进程,那么我们应能控制执行。这种控制要能判定和重置进程或作业的属性,包括作业的优先级、最大允许执行时间等(get_ process_attributes() 和 set_process_attributes())。如果发现创建的进程或作业不正确或者不再需要,那么也要能终止它(terminate_process())。

创建了新的作业或进程后,可能要等待其执行完成,也可能要等待一定时间(wait_time())。更有可能要等待某个事件的出现(wait_event())。当事件出现时,作业或进程就会响应(signal_event())。

通常,两个或多个进程会共享数据。为了确保共享数据的完整性,操作系统通常提供系统调用,以允许一个进程锁定(lock)共享数据。这样,在解锁之前,其他进程不能访问该数据。通常,这样的系统调用包括 acquire_lock() 和 release_lock()。这类系统调用用于协调并发进程,将在后续章节详细讨论。

进程和作业控制差异很大,这里通过两个例子加以说明:一个涉及单任务系统,另一个涉及多任务系统。

MS-DOS 操作系统是个单任务的系统,在计算机启动时它就运行一个命令解释程序(图 1a)。由于 MS-DOS 是单任务的,它采用了一种简单方法来执行程序而且不创建新进程。它加载程序到内存,并对自身进行改写,以便为新程序提供尽可能多的空间(图 1b)。

MS-DOS 执行状态
图 1 MS-DOS 执行状态

接着,它将指令指针设为程序的第一条指令。然后,运行程序,或者错误引起中断,或者程序执行系统调用来终止。无论如何,错误代码会保存在系统内存中以便以后使用。之后,命令解释程序中的尚未改写部分重新开始执行。它首先从磁盘中重新加载命令解释程序的其他部分。然后,命令解释程序会向用户或下个程序提供先前的错误代码。

FreeBSD(源于 Berkeley UNIX)是个多任务系统。在用户登录到系统后,用户所选的外壳就开始运行。这种外壳类似于 MS-DOS 外壳:按用户要求,接受命令并执行程序。不过,由于 FreeBSD 是多任务系统,命令解释程序在另一个程序执行,也可继续执行(图 2)。

运行多个程序的FreeBSD
图 2 运行多个程序的 FreeBSD

为了启动新进程,外壳执行系统调用 fork()。接着,所选程序通过系统调用 exec() 加载到内存,程序开始执行。根据命令执行方式,外壳要么等待进程完成,要么后台执行进程。对于后一种情况,外壳可以马上接受下个命令。当进程在后台运行时,它不能直接接受键盘输入,这是因为外壳已在使用键盘。因此 I/O 可通过文件或 GUI 来完成。

同时,用户可以让外壳执行其他程序,监视运行进程状态,改变程序优先级等。当进程完成时,它执行系统调用 exit() 以终止,并将 0 或非 0 的错误代码返回到调用进程。这一状态(或错误)代码可用于外壳或其他程序。后续章节将通过一个使用系统调用 fork() 和 exec() 的程序例子来讨论进程。

文件管理

下面,我们讨论一些有关文件的常用系统调用。

首先要能创建(create())和删除(delete())文件。这两个系统调用需要文件名称,还可能需要文件的一些属性。一旦文件创建后,就会打开(open())并使用它,也会读(read())、写(write())或重定位(reposition())(例如,重新回到文件开头,或直接跳到文件末尾)。最后,需要关闭(close())文件,表示不再使用它了。

如果采用目录结构来组织文件系统的文件,那么也会需要同样的目录操作。另外,不管是文件还是目录,都要能对各种属性的值加以读取或设置。文件属性包括:文件名、文件类型、保护码、记账信息等。

针对这一功能,至少需要两个系统调用:获取文件属性(get_file_attributes())和设置文件属性(set_file_attributes())。有的操作系统还提供其他系统调用,如文件的移动(move())和复制(copy())。还有的操作系统通过代码或系统调用来完成这些 API 的功能。其他的操作系统可能通过系统程序来实现这些功能。如果系统程序可被其他程序调用,那么这些系统程序也就相当于 API。

设备管理

进程执行需要一些资源,如内存、磁盘驱动、所需文件等。如果有可用资源,那么系统可以允许请求,并将控制交给用户程序;否则,程序应等待,直到有足够可用的资源为止。

操作系统控制的各种资源可看作设备。有的设备是物理设备(如磁盘驱动),而其他的可当作抽象或虚拟的设备(如文件)。多用户系统要求先请求(request())设备,以确保设备的专门使用。在设备用完后,要释放(release())它。这些函数类似于文件的系统调用 open() 和 close()。其他操作系统对设备访问不加管理。这样带来的危害是潜在的设备争用以及可能发生的死锁,这将在后续章节中讨论。

在请求了设备(并得到)后,就能如同对文件一样,对设备进行读(read())、写(write())、重定位(reposition())。事实上,I/O 设备和文件极为相似,以至于许多操作系统如 UNIX 都将这两者组合成文件-设备结构。这样,一组系统调用不但用于文件而且用于设备。有时,I/O 设备可通过特殊文件名、目录位置或文件属性来辨认。

用户界面可以让文件和设备看起来相似,即便内在系统调用不同。在设计、构建操作系统和用户界面时,这也是要加以考虑的。

信息维护

许多系统调用只不过用于在用户程序与操作系统之间传递信息。例如,大多数操作系统都有一个系统调用,以便返回当前的时间(time())和日期(date())。还有的系统调用可以返回系统的其他信息,如当前用户数、操作系统版本、内存或磁盘的可用量等。

还有一组系统调用帮助调试程序。许多系统都提供用于转储内存(dump())的系统调用。对于调试,这很有用。程序 trace 可以列出程序执行时的所有系统调用。甚至微处理器都有一个 CPU 模式,称为单步(single step),即 CPU 每执行一条指令都会产生一个陷阱。调试器通常可以捕获到这些陷阱。

许多操作系统都提供程序的时间曲线(time profile),用于表示在特定位置或位置组合上的执行时间。时间曲线需要跟踪功能或固定定时中断。当定时中断出现时,就会记录程序计数器的值。如有足够频繁的定时中断,那么就可得到花在程序各个部分的时间统计信息。

再者,操作系统维护所有进程的信息,这些可通过系统调用来访问。通常,也可用系统调用重置进程信息(get_process_attributes() 和 set_process_attributes ())。

通信

进程间通信的常用模型有两个:消息传递模型共享内存模型

对于消息传递模型(message-passing model),通信进程通过相互交换消息来传递信息。进程间的消息交换可以直接进行,也可以通过一个共同邮箱来间接进行。在开始通信前,应先建立连接。应知道另一个通信实体名称,它可能是同一系统的另一个进程,也可能是通过网络相连的另一计算机的进程。

每台网络计算机都有一个主机名(hostname),这是众所周知的。另外,每台主机也都有一个网络标识符,如IP地址。类似地,每个进程有进程名(process name),它通常可转换成标识符,以便操作系统引用。系统调用 get_hostid() 和 get_processid() 可以执行这类转换。这些标识符再传给通用系统调用 open() 和 close()(由文件系统提供),或专用系统调用 open_connection() 和 close_connection(),这取决于系统通信模型。

接受进程应通过系统调用 accept_connection() 来许可通信。大多数可接受连接的进程为专用的守护进程(daemon),即专用系统程序。它们执行系统调用 wait_for_connection(),在有连接时会被唤醒。通信源称为客户机(client),而接受后台程序称为服务器(server),它们通过系统调用 read_message() 和 write_message() 来交换消息。系统调用 close_connection() 终止通信。

对于共享内存模型(shared-memory model),进程通过系统调用 shared_memory_create() 和 shared_memory_attach() 创建共享内存,并访问其他进程拥有的内存区域。

注意,操作系统通常需要阻止一个进程访问另一个进程的内存。共享内存要求两个或多个进程都同意取消这一限制,这样它们就可通过读写共享区域的数据来交换信息。这种数据的类型是由这些进程来决定的,而不受操作系统的控制。进程也负责确保不会同时向同一个地方进行写操作。

上面讨论的两种模型常用于操作系统,而且大多数系统两种都实现了。消息传递对少量数据的交换很有用,因为没有冲突需要避免。与用于计算机间的共享内存相比,它也更容易实现。共享内存在通信方面具有高速和便捷的特点,因为当通信发生在同一计算机内时,它可以按内存传输速度来进行。不过,共享内存的进程在保护和同步方面有问题。

保护

保护提供控制访问计算机的系统资源的机制。过去,只有多用户的多道计算机系统才要考虑保护。随着网络和因特网的出现,所有计算机(从服务器到手持移动设备)都应考虑保护。

通常,提供保护的系统调用包括 set_permission() 和 get_permission(),用于设置资源(如文件和磁盘)权限。系统调用 allow_user() 和 deny_user() 分别用于允许和拒绝特定用户访问某些资源。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


起步 处理器架构,参考 x86是指intel的开发的一种32位指令集 intel和amd早期的cpu都支持这种指令集 AMD比Intel率先制造出了商用的兼容x86的CPU,AMD称之为AMD64 Intel选择了设计一种不兼容x86的全新64为指令集,称之为IA-64,后来支持AMD64的指令集,
pscp pscp -P 22 C:\work\test.txt root@192.168.1.5:/home/data pscp -P 22 root@192.168.1.5:/home/data/test.txt C://work// 检索 find / -name default.config
文件处理 ls -a # 显示所有文件 ls -l # 显示详细信息 ls -d # 显示路径 mkdir /目录名称 # 创建目录 cd /目录名称 # 切换目录 pwd # 显示当前路径 rmdir /目录名称 # 删除目录 cp -rp [目录名称] [目标目录] # 复制目录到目标目录 cp
准备一台电脑(我就用联想拯救者r7000演示) 参考博客制作启动盘 插上U盘,启动电脑,一直按F2 进入如下页面后,将U盘设置为第一启动项,点击exit,保存并退出 之后进入如下页面,选择第三项 进入如下页面,选择第四项 进入如下页面,选择第一项,选中后,先不要点Enter 按e键,将inst.st
认识 Linux系统是参考了UNIX系统作为模板开发的,但没有使用UNIX的代码;是UNIX的一种,但不是衍生版 在Linux内核的基础上开发是发行版 分区 逻辑分区永远从5开始 步骤 挂载:可理解为分配盘符,挂载点即是盘符名;不同之处:Linux中是以空目录名称作为盘符 Hda 第一块硬盘 Hda
文件处理命令 以 . 开头的文件是隐藏文件 以 - 开头表示这是一个文件 以 d 开头表示是一个目录 以 l 开头表示是一个软链接 第一个root是所有者,第二个root是所属组 ls -h 以文件默认大小后缀 显示 ls -i 查看i节点(唯一标识) 所有者:只能有一个,可变更 所属组:只能有一个
参考 01 02 03 前提环境 本地安装VirtualBox,并安装CentOS8,配置网络后,window系统上putty能连接到CentOS8服务器 配置步骤 右键服务器复制 启动复制后的服务器,查看ip和hostname发现和原来的服务器一样,需要修改 hostname # 查看主机名 vi
文件搜索命令 星号匹配任意字符,问号匹配任意单个字符 -iname 根据文件名查找且不区分大小写 -ok 命名会有一个询问的步骤 如果没有找到指定文件,可输入命令:updatedb 更新文件资料库;除tmp目录不在文件资料库收录范围之内 locate -i 文件名 # 检索时不区分大小写 which
安装环境 安装最新版的Virtual Box,点击安装 下载centos8镜像 创建虚拟机,可参考 选择下载到本地的镜像 设置启动顺序 点击启动 启动过程中报错:“FATAL:No bootable medium found!” 1.没有选择iso镜像 2.光驱没有排在第一位置 3.镜像只能选择x8
Linux严格区分大小写 所有内容文件形式保存,包括硬件 Linux不靠扩展名区分文件类型 挂载:将设备文件名和挂载点(盘符)连接的过程 Linux各个目录的作用 bin表示二进制 服务器注意事项 远程服务器不允许关机,只能重启 重启时应该关闭服务 不要在服务器访问高峰运行高负载命令 远程配置防火墙
IDE连接Linux,上传下载文件 参考1 参考2 连接Linux 上传下载文件 本地项目打包后上传 查看是否上传成功,右键下载 补充 后端项目开发完成后,需clean掉临时文件target文件夹,且只推送修改过的文件 前端项目开发的过程中,需要在每个子组件中使用scoped,确保每个子组件中的编码
起步 LTS与普通版本的区别 LTS版本的发布周期更长,更加稳定 安装jdk sudo mkdir /usr/lib/jvm # 在Ubuntu中创建目录 pscp D:\安装包\linux源码包\jdk-8u291-linux-x64.tar.gz chnq@192.168.0.102:/tmp
前言 最近在b站上看了兄弟连老师的Linux教程,非常适合入门:https://www.bilibili.com/video/BV1mW411i7Qf 看完后就自己来试着玩下,正好手上有台空闲的电脑就尝试不使用虚拟机的方式安装Linux系统 安装步骤 制作启动盘 下载ISO镜像,我这里下载的是Cen
新建虚拟电脑 设置内存和处理器 设置硬盘大小 完成 设置 查看光驱 设置启动顺序 点击启动 选择第1项 进入图形安装界面 选择安装位置,开始安装 设置root密码 重启 登录 查看本地文件夹 配置网络,点击设置 查看宿主机ip C:\Users\ychen λ ipconfig 无线局域网适配器 W
源码包安装需手动下载后安装 二进制包则在package目录下 rpm命令管理rpm包 若某个rpm包依赖于某个模块,需要到网站www.rpmfind.net查询该模块依赖的包,安装这个包后自动安装模块,之后就能安装rpm包了 安装升级时使用包全名 查询卸载时使用包名 虚拟机中的Linux系统安装rp
首先进入命令模式,再输入以下命令 命令模式用于输入命令 插入模式可对文件编写操作 编辑模式下的命令是在冒号后输入 :12, 15d # 删除指定范围的行,这里是删除12到15行 :n1,n2s/old/new/g ## 表示从n1行到n2行,old表示旧的字符串 vim使用小技巧:自定义快捷键,如快
使用源码包安装,需要自己指定安装位置,通常是 /usr/local/软件名/ linux中要想启动执行文件,应使用绝对路径 /绝对路径/rpm包名 start ## 执行方式一 service rpm包名 start ## 执行方式二 使用源码包安装后,由于自定义安装路径,就不能使用service命
网络命令 在收邮件的用户中,输入 mail 可查看邮件信息,输入序列号查看详细信息 在mail命令下,输入h 查看所有邮件的列表 输入:d 序列号 # 删除邮件 last # 统计所有用户登录或重启时间,用于日志查询 lastlog # 显示包括未登录用户的登录时间 lastlog -u 用户id
若要使用yum管理,必须能连接网络,首先配置网络IP 进入yum源文件中启动容器 使用yum源头安装rpm包不需要进入package路径,同时也不需要使用包全名,会有yum自动管理 安装软件组
简介 client即是本机安装的docker,相当于git Docker_host相当于centos系统 registry则是docker仓库,相当于GitHub 镜像用于创建docker容器,一个镜像可以创建多个docker容器 容器是由镜像创建的运行实例,(镜像相当于类,容器相当于类创建的对象)