文章目录
- 1.Linux系统调用
- 2.为什么用户程序不直接访问系统内核提供的服务?
- 3.文件描述符
- (1)内核如何区分和引用特定的文件?
- (2) 一个进程启动时, 通常会打开3个文件
- 4.Linux文件IO函数说明
- (1)open函数
- (2)creat函数
- (3)close函数
- (4)read函数
- (4)write函数
- 5.ioctl函数
1.Linux系统调用
- 系统调用: 操作系统提供给用户程序调用的一组“特殊” 接口, 用户程序可以通过这组“特殊” 接口来获得操作系统内核提供的服务
- 系统调用和普通调用的区别:
系统调用是由OS内核提供的,运行于内核态;
普通的函数调用是由函数库或用户自己提供的,运行于用户态;
有一些标准的C语言库函数,在Linux系统上的实现,都是通过系统调用来完成的。
2.为什么用户程序不直接访问系统内核提供的服务?
- 为了更好地保护内核空间, 将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和
用户态) , 它们分别运行在不同的级别上, 在逻辑上是相互隔离的。 因此, 用户进程在通常情况下不允许访问内核数据, 也无法使用内核函数, 它们只能在用户空间操作用户数据, 调用用户空间的函数 - 进行系统调用时, 程序运行空间从用户空间进入内核空间, 处理完后再返回到用户空间
- 系统调用并不是直接与程序员进行交互的, 它仅仅是一个通过软中断机制向内核提交请求, 以获取内核服务的接口。
原理:进程先用适当的值填充寄存器,然后调用一个特殊的指令,该指令会跳转到事先定义的内核中的位置,该位置是用户进程可读,但是不可写的。
在Intel中,这是由中断0x80实现的,此时硬件就知道此时是在操作系统的内核中运行,有了内核的权限就可以使用内核的服务了,该内核的位置是system_call,会检查系统的调用号,该号码告诉内核我们的进程是在请求哪种服务,然后查看系统调用表,找到所调用的内核函数的入口地址, 接着调用函数,返回后做一些系统检查,最后在返回到进程 - 在实际使用中程序员调用的通常是用户编程接口——API。
- Linux中的系统调用包含在Linux的libc库中, 通过标准的C函数调用方法可以调用
在跳转到内核态时,由系统调用处理程序和服务例程,然后依次返回给用户态 - 系统命令相对API更高了一层, 它实际上是一个可执行程序, 它的内部调用了用户编程接口(API) 来实现相应的功能。
- eg:
3.文件描述符
(1)内核如何区分和引用特定的文件?
-
通过文件描述符。 文件描述符是一个非负的整数, 它是一个索引值, 并指向在内核中每个进程打开文件的记录表。 当打开一个现存文件或创建一个新文件时, 内核就向进程返回一个文件描
述符;当需要读写文件时, 也需要把文件描述符作为参数传递给相应的函数。
(2) 一个进程启动时, 通常会打开3个文件
- 在POSIX应用程序中,整数0,1,2被代换成了符号常数,这些常数都是定义在unstd.h中;
- 文件描述符的范围是:0-OPENMAX,允许每个进程打开的文件数0-OPENMAX
4.Linux文件IO函数说明
(1)open函数
- eg:
(2)creat函数
(3)close函数
(4)read函数
-
read函数实际读到的字节数少于要求读的字节数时:
(a) 读普通文件,在读到要求字节数之前就到达文件尾;
(b)当从终端设备读,通常一次最多读一行;
(c)当从网络读时,网络中的缓冲机制可能造成返回值小于所要求读的字节数;
(d)某些面向记录的设备,如磁带,一次最多返回一个记录; - 读操作完成后,文件的当前位置将从读之前的位置加上实际读的字节数
- 当有错误发生时则返回-1,错误代码存入errno中,而文件读写位置则无法预期
(4)write函数
-
数据无法一次性读完时
第二次读buf中数据时,读位置指针并不会自动移动,
按如下格式实现读位置移动: write(fp, p1+len, (strlen(p1)-len),直至指针恢复 - Write一次可以写的最大数据范围是8192
写入数据大小最好小于buff中的值
Count参数值大于SSIZE_MAX,则write调用的结果未定义
Count参数值为0时, write调用会立即返回0这个值 - Write调用返回时,内核已经将缓冲区所提供的数据复制到内核的缓冲区,但是无法保证数据已经写出到预定的目的地
通常指的是:物理设备作为目的地,因为系统调用的速度比硬盘写入的速度要快,所以系统内核采用延后写入的机制来处理,内核会在后台搜集所有脏缓冲区(有数据写入的缓冲区),将这些缓冲区安排成最佳顺序,接着写入磁盘中,内核安排写入顺序主要是基于性能的考虑,而不是根据用户的执行顺序,即与缓冲区写入的先后无关。 - eg:
5.ioctl函数
- 应用层与驱动函数的ioctl之间的联系
- 在驱动程序中实现的ioctl函数体内,实际上是有一个switch{case}结构,每一个case对应一个命令码,做出一些相应的操作
- ioctl中命令码是唯一联系用户程序命令和驱动程序支持的途径
命令与设备是一一对应的;
内核提供宏,用能够理解的字符串来生成命令码;或者利用命令码得到用户能够理解的字符串,已表明对应设备类型,序列号,数据传送方向,和数据传输尺寸 - "幻数"是一个字母,数据长度也是8,用一个特定的字母来标明设备类型