本文共 2150 字,大约阅读时间需要 7 分钟。
分层结构:寄存器、高速缓存、内存、磁盘、磁带
寄存器:典型存储容量:32位CPU中为32*32位,而在64位CPU中位64*64位。
内存(主存):RAM
只读存储器(ROM)在工厂中就被编程完毕,然后再也不能被修改。
CMOS :易失性
信息写在磁盘上的一系列同心圆上。任意一个给定臂的位置,每个磁头可以读取一段环形区域,称为磁道。把一个给定臂的位置上的所有磁道合并起来,组成了一个柱面。每个磁道划分为若干个扇区,扇区的典型值为512字节。
I/O设备一般包括两个部分:设备控制器和设备本身。
专门与设备控制器对话,发出命令并接收响应的软件,称为设备驱动程序。设备驱动程序必须装入操作系统中,这样它可在核心态中运行。
实现输入输出的方式:三种
忙等待:CPU一直轮询设备直到对应的I/O操作完成。
设备驱动程序启动设备并且让该设备在操作完成时发出一个中断。
为I/O使用一种特殊的直接存储器访问。
依赖 BIOS 基本输入输出程序。
物理内存通常小于逻辑地址空间大小,采用虚拟内存技术。
mount系统调用允许把在CD-ROM上的文件系统连接到程序所希望的根文件系统上。如果当CD-ROM安装好,目录b中有任何不能访问的文件,则是因为/b指向了CD-ROM的根目录(文件系统几乎总是安装在空目录上。)
特殊文件:快特殊文件和字符特殊文件。特殊文件保存在/dev目录中。
进程要想发现它所写入的输出文件是管道而不是真正的文件,需要使用特殊的系统调用。
shell不是操作系统的一部分,shell是终端用户与操作系统之间的界面。
用户登录时,同时启动一个shell。它以终端作为标准输入和标准输出。例如用户输入date
于是shell创建一个子进程,并运行data程序作为子进程。在该子进程运行期间,shell等待它结束。
举例说明:read系统调用
它的调用由C程序完成,方法是调用一个与该系统调用名称相同的库过程:read
count=read(fd, buffer, nbytes);
调用程序首先把参数压进堆栈,由于历史的原因,C以及C++编译器使用逆序(必须把第一个参数赋给printf(格式字串),放在堆栈的顶部)。
接着是对库过程的实际调用。
在库过程中,一般把系统调用的编号放在操作系统所期望的地方,如寄存器中,然后执行一个trap指令。
trap指令与过程指令存在两个方面的差别:1. trap副作用是切换到内核态。2. trap指令不能跳转到任意地址上。
跟随在trap指令后的内核代码开始检查系统调用编号,然后发出正确的系统调用处理命令。
系统调用句柄运行
返回给用户空间库过程
返回到用户程序
用户程序清除堆栈,
具体过程如下图:
POSIX提供的过程调用:包括进程,文件,目录及文件系统,杂项
考虑shell如何使用fork。键入一条命令后,shell创建一个新的子进程。这个子进程必须执行用户的命令。通过使用execve系统调用可以实现这一点,这个系统调用会引起整个核心映像被一个文件所替代。我们用一个高度简化的shell说明fork、waitpid以及execve的使用。
execve有三个参数:将要执行的文件名称、一个指向变量数组的指针,以及一个指向环境数组的指针。
exit系统调用有一个参数,退出状态,该参数通过waitpid系统调用中的statloc返回给父进程。
unix进程将存储空间分为:正文段、数据段、堆栈段
数据段的扩展是显示地通过系统调用brk进行的。brk不是posix的系统调用。
stat返回文件信息,对于一个打开的文件而言,fstat调用完成同样的工作。
kill系统调用供用户或用户进程发送信号用。若一个进程准备好捕捉一个特定的信号,那么在信号到来时,运行一个信号处理程序。如果该进程还没有准备好,那么信号的到来会杀死该进程(此调用名称的由来)
kill(传送信号给指定的进程)
相关函数 raise,signal
表头文件 #include<sys/types.h>
#include<signal.h>
定义函数 int kill(pid_t pid,int sig);
函数说明
kill()可以用来送参数sig指定的信号给参数pid指定的进程。参数
pid有几种情况:
pid>0 将信号传给进程识别码为pid 的进程。
pid=0 将信号传给和目前进程相同进程组的所有进程
pid=-1 将信号广播传送给系统内所有的进程
pid<0 将信号传给进程组识别码为pid绝对值的所有进程
参数sig代表的信号编号可参考附录D
返回值 执行成功则返回0,如果有错误则返回-1。
错误代码:
EINVAL 参数sig 不合法
ESRCH 参数pid 所指定的进程或进程组不存在
EPERM 权限不够无法传送信号给指定进程