引子
外部设备分为存储性设备和I/O型设备,设备管理通常采用I/O中断、缓冲区管理、通道、设备驱动调度等多种技术。通常有以下功能:
设备中断处理
缓冲区管理
设备分配去配
设备驱动管理
实现虚拟设备
一、I/O硬件原理
1、概念:I/O系统 I/O操作 I/O操作特性
2、I/O控制方式:对CPU和设备的职能进行合理分工
轮询方式:cpu指定交换字节数和起始地址,不断测试设备直到拿到所有数据,串行工作浪费I/O cpu等待时间
中断方式:cpu与设备间有中断请求线,需要cpu时刻准备响应设备中断,若同时有大量设备中断可能丢数据
DMA方式:设备通过DMA控制器直接与内存交换数据,周期窃用总线控制权,不需要cpu干预
通道方式:I/O处理器,与cpu并行,四级链接,三级控制:
CPU(I/O指令) ==> 通道(通道命令) ==> 控制器 (动作序列)==> 设备
3、设备控制器
I/O设备的硬件:机械部件(设备本身)和电子部件(如:设备控制器或适配器,可插入主板扩充槽的印刷电路板)
操作系统实际上是与控制器通信,从磁盘中以字位串读取头标(记录扇区等信息),4096 B扇区和纠错码,由控制器装配成字节,存入控制器内部的缓冲区形成字节快,在确认无错后,复制到内存。
主要功能:
接收和识别CPU或通道发来的命令
实现数据交换
发现和记录设备及自身的状态信息,供CPU处理使用
设备地址识别
二、I/O软件原理
2.1 I/O软件设计需要考虑的问题
1.设备无关性;程序员/用户只需要跟设备抽象打交道
2.出错处理;
3.同步/异步传输;
异步传输:CPU在启动I/O操作后,可继续执行其他工作
同步传输: 阻塞方式,让启动I/O的进程挂起等待,直至数据传输完成
4.缓冲技术;建立缓冲区,让数据的到达率和离去率相匹配,以提高系统吞吐率
2.2 I/O软件层次/ I/O子系统层次
1. 中断处理程序;
2. 设备驱动程序;
3. 独立于设备的I/O软件;
4. 用户空间的I/O软件;
下四层构成内核空间I/O软件 ,linux系统编写C程序调用printf()的过程如下图:
1. 用户程序调用标准库函数printf() ;
2. printf函数中通过一系列系统调用转到write()函数,write()中有陷阱指令(用户态->内核态)int 0x80 (IA-32);
3. 进程进入内核态,系统调用处理程序system_call() --系统调用的唯一入口,开始执行;
4. 将根据EAX寄存器中的系统调用号跳转到当前系统调用对应的系统调用服务例程sys_write();
5. 执行结束后返回用户态,接着执行后面一条指令。
//write()封装函数对应的汇编代码,AT&T格式
write:
push1 %ebx // 将EBX入栈
movl $4, %eax // 将系统调用号送EAX
movl 8(%esp), %ebx // 将第一个参数fd送EBX
movl 12(%esp), %ecx // 将第二个参数buf送ECX
movl 16(%esp), %edx // 将第三个参数n送EDX
int $0x80 // 进入系统调用处理程序system_call执行
cmpl $-132, %eax // 检查返回值,假定最大出错码为131
jbe .L1 // 若无错误,跳转至.L1
negl %eax // 将返回值取负送EAX
movl %eax, error // 将EAX值送error
movl $-1, %eax // 将write函数返回值置-1
.L1: popl %ebx
ret
2.2.1 I/O中断处理程序
2.2.2 I/O设备驱动程序功能
1.设备初始化;
2.执行设备驱动例程;
3、调用和执行中断处理程序
2.2.3 独立于设备的I/O软件
执行适用于所有设备的常用功能,并向用户层软件提供一致性接口
1.设备命名与保护;
2.提供与设备无关的快尺寸;
3, 缓冲技术;
4.设备分配与状态跟踪;
5.错误处理与报告(与设备无关)
2.2.4 用户空间的I/O软件
unix高级环境编程中的各种I/O,如标准I/O、 系统级I/O(read.write)
C标准I/O库函数的不足:
1. 不存在加锁、解锁保证文件的安全性
2. 所有I/O是同步的,程序必须执行完I/O后才能继续执行
3. 无法使用其完成某些I/O功能
4. 进行网络编程易于出现缓冲区溢出
故常常自行封装系统级I/O构造适合自己的I/O软件,windows API:CreateFile()..
三、I/O硬件和软件的接口
I/O设备
设备控制器
I/O端口及其编址
四、缓冲技术(待补充)
五、驱动调度技术
提高磁盘I/O速度的方法
六、设备分配
设备独立性:逻辑设备 映射为 物理设备
七、虚拟设备:脱机外围计算机
八、Linux设备管理(待完善)
5种I/O模型:
阻塞I/O
非阻塞I/O
复用型I/O
信号驱动I/O
异步I/O
基本过程:数据-> 内核缓冲区 ->进程缓冲区
8.1 高级I/O
非阻塞I/O、记录锁、I/O多路转接(select/poll)、异步I/O、readv和writev、存储映射I/O
指定非阻塞I/O的标志:
1. 调用open指定O_NONBLOCK;
2. 已经打开的描述符调用fcntl,由该函数打开O_NONBLOCK文件状态标志;
POSIX.1要求:对于一个非阻塞的描述符,如果无数据可读,则read返回-1,errno设置为EAGAIN
非阻塞I/O: open、read、write设置为NONBLOCK,通过轮询的方式读写数据;
设备锁
8.2 终端I/O
工作模式:规范模式输入处理,以行为单位处理,对于每个读请求,终端驱动程序最多返回一行
非规范模式输入处理,输入字符不装配成行
终端设备是由通常位于内核中的中断驱动程序控制的,每个终端设备都有一个输入队列和输出队列
如果打开了回显功能,则在输入队列和输出队列之间有一个隐含的链接
struct termios {
tcflag_t c_iflag; /* input flag 通过终端设备驱动程序控制字符的输入 剥除输入字节的第8位,允许输入奇偶校验*/
tcflag_t c_oflag; /* output flag 控制字符的输出, */
tcflag_t c_cflag; /* control flag RS-232串行线, 忽略调制解题器的状态线,每个字符的一个或两个停止位*/
tcflag_t c_lflag; /* local flags 影响驱动程序与用户的接口,回显开关,*/
cc_t cc_c[NCCS]; /* control characters */
}
c_cflag终端标志
c_iflag终端标志
c_lflag终端标志
c_oflag终端标志
终端I/O函数
与终端有关函数的关系
终端行规程
#include <termios.h>
/* 获取和设置终端属性 */
int tcgetattr(int fd, struct termios *termptr)
int tcsetattr(int fd, int opt, const struct termios *termptr)
/* 波特率函数 */
speed_t cfgetispeed(const struct termios *termptr)
speed_t cfgetospeed(const struct termios *termptr)
int cfsetispeed(const struct termios *termptr, speed_t speed);
int cfsetospeed(const struct termios *termptr, speed_t speed);
#include <stdio.h>
/* 确定控制终端的名字 */
char *ctermid(char *ptr)