ioctl
在计算中,ioctl 是对设备特定的输入/输出操作和其他不能用常规系统调用表达的操作的系统调用。 它需要一个指定请求代码的参数; 调用的效果完全取决于请求代码。 请求代码通常是特定于设备的。
例如,可以指示物理设备弹出光盘的 CD-ROM 设备,则驱动程序将提供 ioctl 请求代码来执行此操作。 与设备无关的请求代码有时用于让用户空间访问仅由核心系统软件使用或仍在开发中的内核功能。 ioctl 系统调用以该名称首次出现在 Unix 版本 7 中。 大多数 Unix 和类 Unix 系统都支持它,包括 Linux 和 macOS,但可用的请求代码因系统而异。Microsoft Windows 在其 Win32 API 中提供了一个类似的函数,名为“DeviceIoControl”。
背景
传统的操作系统可以分为两层,用户空间和内核。 文本编辑器等应用程序代码驻留在用户空间,而操作系统的底层设施(如网络堆栈)驻留在内核中。 内核代码处理敏感资源并实现应用程序之间的安全性和可靠性屏障; 因此,操作系统会阻止用户模式应用程序直接访问内核资源。 用户空间应用程序通常通过系统调用向内核发出请求,其代码位于内核层。
系统调用通常采用“系统调用向量”的形式,其中用索引号指示所需的系统调用。 例如,exit() 可能是 1 号系统调用,而 write() 号是 4。系统调用向量然后用于为请求找到所需的内核函数。 这样,传统的操作系统通常会向用户空间提供数百个系统调用。
尽管系统调用是访问标准内核设施的权宜之计,但系统调用有时不适用于访问非标准硬件外围设备。 必然地,大多数硬件外围设备(也称为设备)只能在内核中直接寻址。 但是用户代码可能需要直接与设备通信; 例如,管理员可能会在以太网接口上配置媒体类型。 现代操作系统支持多种设备,其中许多设备提供大量功能。 内核设计者可能没有预见到其中一些设施,因此内核很难提供使用这些设备的系统调用。
为了解决这个问题,内核被设计成可扩展的,并且可以接受一个额外的模块,称为设备驱动程序,它运行在内核空间,可以直接寻址设备。 ioctl 接口是一个单一的系统调用,用户空间可以通过它与设备驱动程序进行通信。 设备驱动程序上的请求根据此 ioctl 系统调用进行引导,通常通过设备句柄和请求编号进行引导。 因此,基本内核可以允许用户空间访问设备驱动程序,而无需了解设备支持的设施,也不需要难以管理的大量系统调用。