fcntl , dup 或 dup2 子例程
用途
控制打开的文件描述符。
库
标准 C 库 (libc.a)
Berkeley 兼容性库 (libbsd.a) (对于 fcntl 子例程)
语法
#include < fcntl.h >
int fcntl ( 文件描述符, 指挥, 论据) int 文件描述符, 指挥, 论据;
#include <unistd.h>
int dup( FileDescriptor) int FileDescriptor;
描述
fcntl 子例程对 FileDescriptor 参数指定的打开文件执行控制操作。 如果系统上安装了网络文件系统 (NFS) ,那么打开的文件可以驻留在另一个节点上。 弗纳特尔 子例程用于执行以下操作:
- 打开文件描述符重复。
- 请设置并获取文件描述符标志。
- 设置并获取 file-status 标志。
- 管理记录锁定。
- 管理异步 I/O 所有权。
- 关闭多个文件。
弗纳特尔 子例程提供的功能与 重复 和 dup2 子例程相同。
如果 FileDescriptor 引用了终端设备或套接字,那么可以使用异步 I/O 工具。 通常通过将 ioctl 子例程与 FIOASYNC, 菲奥塞敦和 FIOGETOWN 命令配合使用来启用这些设施。 但是,如果应用程序与 libbsd.a 库链接,那么兼容 BSD 的机制也可用。
当 FileDescriptor 参数引用共享内存对象时, fcntl 子例程仅管理 F_DUPFD, F_DUP2FD, F_GETFD, F_SETFD, F_GETFL和 F_CLOSEM 命令。
使用 libbsd.a 库时,通过使用 F_SETFL 命令并在 Argument 参数中设置 FASYNC 标志来启用异步 I/O。 F_GETOWN 和 F_SETOWN 命令将获取当前异步 I/O 所有者,并设置异步 I/O 所有者。 但是,仅当文件描述符是指终端设备或套接字时,这些命令才有效。
所有包含 弗纳特尔 子例程的应用程序都必须符合设置为特定值的 _BSD 。 可接受的值为 43 和 44。 此外,所有套接字应用程序都必须包含 BSD libbsd.a 库。
常规记录锁定信息
锁可以是 执行 或 咨询锁定 ,也可以是 读 或 写锁定。
注意: 在与文件锁定配合使用时,缓冲 I/O 无法正常工作。 请不要对将要锁定的文件使用标准 I/O 包例程。
要使锁定成为强制锁定,必须设置该文件的强制锁定属性; 例如,必须设置 (_ENFMT) 位,但必须清除 _IXGRP, (_IXUSR)和 _IXOTH 位。 否则,该锁定是咨询锁定。 给定文件可以具有咨询或强制锁定,但不能同时具有这两种锁定。 sys/mode.h 文件的描述包含文件属性的描述。
当进程对文件的某个部分进行强制锁定时,任何其他进程都无法使用 读 或 写 子例程访问该文件的该部分。 此外, 开 和 截断 子例程无法截断文件的锁定部分,并且 弗朗 子例程不能修改文件的锁定部分。 如果另一个进程尝试读取或修改文件的已锁定部分,那么该进程将休眠到该部分解锁为止,或者返回并带有错误指示。
当进程对文件的某个部分持有咨询锁定时,其他任何进程都无法使用 弗纳特尔 子例程锁定该文件的该部分 (或重叠部分)。 (不会影响其他子例程。) 因此,进程必须自愿调用 弗纳特尔 子例程,以便使咨询锁定生效。
当进程在文件的某个部分上持有读锁定时,其他进程也可以在该部分或其子集上设置读锁定。 读锁定也称为 共享 锁定。
读锁阻止任何其他进程在受保护区域的任何部分上设置写锁。 如果读锁定也是强制锁定,那么任何其他进程都无法修改受保护区域。
要对其进行读锁定的文件描述符必须已打开且具有读访问权。
当进程在文件的某个部分上持有写锁定时,其他任何进程都无法在该部分上设置读锁定或写锁定。 写锁定也称为 排他 锁定。 对于文件的特定部分,任何时候都只能存在一个写锁定和不存在读锁定。
如果锁定也是强制锁定,那么其他任何进程都无法读取或修改受保护区域。
以下关于文件锁定的一般规则适用:
- 在锁定部分的中间更改或解锁部分文件时,会将两个较小的部分锁定在原始锁定部分的每一端。
- 如果调用进程持有对文件的锁定,那么该锁定可以替换为以后对 弗纳特尔 子例程的调用。
- 当进程关闭给定进程的文件的 任何 文件描述符时,将除去与该文件相关联的所有锁定。
- 在 叉 子例程运行后,子进程不会继承锁定。注: 不会始终检测到分布式系统中由于文件锁定而导致的死锁。 当此类死锁可能发生时,请求这些锁定的程序应该设置超时计时器。
锁定可以从文件的当前结束处开始和扩展,但相对于文件的开始处不能为负数。 通过设置以下项,可以将锁定设置为扩展至文件末尾:l_len字段为 0。 如果这种锁也具有以下的l_start和l_whence字段设置为 0 ,将锁定整个文件。 该l_len,l_start和l_whence锁定字段是 群 结构的一部分。
当应用程序使用 32 位锁定接口 (F_SETLK) 来锁定文件的区域,并且锁定范围的最后一个字节包含 MAX_OFF (2 Gb-1) 时,解锁请求的锁定范围将扩展为包含 MAX_END (2 ^ ^ 63-1)。
参数
复制文件描述符
| 项 | 描述 |
|---|---|
| F_DUPFD | 返回新的文件描述符,如下所示:
|
正在设置文件描述符标志
| 项 | 描述 |
|---|---|
| F_GETFD | 获取与 FileDescriptor 参数指定的文件描述符相关联的 close-on-exec 标志 (FD_CLOEXEC 位)。 将忽略 参数 参数。 文件描述符标志与单个文件描述符相关联,并且不影响其他与同一文件相关联的文件。 |
| F_SETFD | 将 Argument 参数的值分配给与 FileDescriptor 参数关联的 close-on-exec 标志 (FD_CLOEXEC 位)。 如果 FD_CLOEXEC 标志值为 0 ,那么文件将在对 执行 子例程的任何调用中保持打开状态; 否则,文件将在成功执行 执行 子例程时关闭。 |
| 获取文件描述符长度 | 获取与 FileDescriptor 参数指定的文件描述符相关联的打开文件描述的文件状态标志和文件访问方式。 打开文件描述是在打开文件时设置的,并且仅应用于与对该文件的特定调用相关联的那些文件描述符。 此打开的文件描述符不影响引用同一文件且具有不同打开文件描述的其他文件描述符。 file-status 标志具有以下值:
文件访问方式的值如下所示:
可以使用 fcntl.h 文件中定义的 O_ACCMODE 掩码从返回值中抽取文件访问标志。 |
| F_SETFL | 根据由 参数 参数指定的相应位设置文件状态标志。 为与 FileDescriptor 参数指定的文件描述符相关联的打开文件描述设置文件状态标志。 可以设置下列标志:
O_NDELAY 和 O_NONBLOCK 标志仅影响针对从同一 开 子例程派生的文件描述符的操作。 在 BSD 中,这些操作适用于引用该对象的所有文件描述符。 |
设置文件锁定
| 项 | 描述 |
|---|---|
| F_GETLK | 获取有关阻止 群 结构中描述的锁定的第一个锁定的信息。 自变量 参数应该是指向类型 struct flock的指针,如 flock.h 文件中所定义。 由 弗纳特尔 子例程检索到的信息将覆盖由 参数 参数指向的 结构 群 中的信息。 如果找不到会阻止创建此锁定的锁定,那么结构将保持不变,但锁定类型除外 (l_type) 设置为 F_UNLCK。 |
| F_SETLK | 根据 参数 参数所指向的锁定描述来设置或清除文件段锁定。 自变量 参数应该是指向类型 struct flock的指针,该类型在 flock.h 文件中定义。 F_SETLK 选项用于建立读 (或共享) 锁定 (F_REDLCK) ,或写 (或互斥) 锁定 (F_WRLCK) ,以及除去任一类型的锁定 (F_UNLCK)。 锁定类型由 fcntl.h 文件定义。 如果无法设置共享或互斥锁定,那么 弗纳特尔 子例程将立即返回。 |
| F_SETLKW | 执行与 F_SETLK 选项相同的功能,除非现有锁定阻止读或写锁定,在这种情况下,进程将休眠,直到文件的部分可自由锁定为止。 如果在fcntl子程序等待区域时接收到要捕获的信号,则中断fcntl子程序,返回-1 并将errno全局变量设置为EINTR。 该锁定操作未完成。 |
| 项 | 描述 |
|---|---|
| F_GETLK64 | 获取有关阻止 flock64 结构中描述的锁定的第一个锁定的信息。 自变量 参数应该是指向类型为 struct flock64的对象的指针,如 flock.h 文件中所定义。 fcntl 子例程检索的信息将覆盖 Argument 参数指向的 struct flock64 中的信息。 如果找不到会阻止创建此锁定的锁定,那么结构将保持不变,但锁定类型除外 (l_type) 设置为 F_UNLCK。 |
| F_SETLK64 | 根据 参数 参数所指向的锁定描述来设置或清除文件段锁定。 自变量 参数应该是指向类型 struct flock64的指针,该类型在 flock.h 文件中定义。 F_SETLK 选项用于建立读 (或共享) 锁定 (F_REDLCK) ,或写 (或互斥) 锁定 (F_WRLCK) ,以及除去任一类型的锁定 (F_UNLCK)。 锁定类型由 fcntl.h 文件定义。 如果无法设置共享或互斥锁定,那么 弗纳特尔 子例程将立即返回。 |
| F_SETLKW64 | 执行与 F_SETLK 选项相同的功能,除非现有锁定阻止读或写锁定,在这种情况下,进程将休眠,直到文件的部分可自由锁定为止。 如果在fcntl子程序等待区域时接收到要捕获的信号,则中断fcntl子程序,返回-1 并将errno全局变量设置为EINTR。 该锁定操作未完成。 |
设置进程标识
| 项 | 描述 |
|---|---|
| F_GETOWN | 获取当前接收 SIGIO 和 SIGURG 信号的进程标识或进程组。 进程组将作为负值返回。 |
| F_SETOWN | 设置要接收 SIGIO 和 SIGURG 信号的进程或进程组。 通过提供负 参数 值来指定进程组。 否则,会将 参数 参数解释为进程标识。 |
正在关闭文件描述符
| 项 | 描述 |
|---|---|
| F_CLOSEM | 关闭从 FileDescriptor 到当前打开的最高文件描述符 (U_maxofile) 的所有文件描述符。 |
| 旧 | 指定打开的文件描述符。 |
| 新 | 指定由 dup2 子例程返回的打开的文件描述符。 |
兼容性接口
lockfx 子例程 (lockfx Subroutine)
当 命令 参数为 F_SETLK, F_SETLKW或 F_GETLK时,以及当以如下方式使用时, 弗纳特尔 子例程的功能类似于 洛克菲克斯 子例程:
fcntl (文件描述符, 指挥, 论据)
等同于:
lockfx (文件描述符, 指挥, 论据)
dup 和 dup2 子例程
弗纳特尔 子例程函数类似于 重复 和 dup2 子例程,当以以下方式使用时:
dup (FileDescriptor)等同于:
fcntl (FileDescriptor, F_DUPFD, 0) dup2 (Old, New)等同于:
close (New);
fcntl(Old, F_DUPFD, New)在以下方面, 重复 和 dup2 子例程与 弗纳特尔 子例程不同:
- 如果New参数指定的文件描述符大于或等于OPEN_MAX,则dup2子程序返回-1并将errno变量设置为EBADF。
- 如果由 旧 参数指定的文件描述符有效且等于由 新建 参数指定的文件描述符,那么 dup2 子例程将返回由 新建 参数指定的文件描述符,而不关闭该文件描述符。
- 如果由 旧 参数指定的文件描述符无效,那么 dup2 子例程将不成功,并且不会关闭由 新建 参数指定的文件描述符。
- dup和dup2子程序成功完成后,返回值等于新参数;否则,返回值为-1。
返回值
成功完成后,返回的值将取决于 命令 参数的值,如下所示:
| 项 | 描述 |
|---|---|
| 命令 | 返回值 |
| F_DUPFD | 新的文件描述符 |
| F_GETFD | 标志的值 (只定义了 FD_CLOEXEC 位) |
| F_SETFD | 非-1的值 |
| 获取文件描述符长度 | 文件标志的值 |
| F_SETFL | 非-1的值 |
| F_GETOWN | 描述符所有者的值 |
| F_SETOWN | 非-1的值 |
| F_GETLK | 非-1的值 |
| F_SETLK | 非-1的值 |
| F_SETLKW | 非-1的值 |
| F_CLOSEM | 非-1 的值。 |
如果fcntl子程序失败,则返回值为-1,并设置 errno全局变量来指示错误。
错误代码
如果以下一个或多个条件成立,那么 弗纳特尔 子例程不成功:
| 项 | 描述 |
|---|---|
| EACCES | 命令 参数为 F_SETLK; 锁定类型为共享锁定或互斥锁定,并且要锁定的文件段已由另一个进程互斥锁定,或者类型为互斥锁定,并且要锁定的文件段的某些部分已由另一个进程共享锁定或互斥锁定。 |
| EBADF | FileDescriptor 参数不是有效的打开文件描述符。 |
| EDEADLK | 命令 参数为 F_SETLKW; 锁定被另一个进程中的某个锁定阻止,并将调用进程置于休眠状态,等待该锁定变为空闲状态将导致死锁。 |
| ENOTTY | 文件描述符未引用终端设备或套接字。 |
| 电子文件 | 命令 参数为 F_DUPFD,并且当前打开的文件描述符的最大数目为 (OPEN_MAX)。 |
| EINVAL | 命令 参数为 F_DUPFD,并且 参数 参数为负数或大于或等于 OPEN_MAX。 |
| EINVAL | 为 命令 参数. 提供的值不合法 |
| EINVAL | 尝试锁定第 5 个或第. 个管道 |
| ESRCH | 命令 参数的值为 F_SETOWN,并且指定为 参数 参数的进程标识未在使用中。 |
| EINTR | 命令 参数为 F_SETLKW ,并且进程在等待获取锁定时接收到信号。 |
| Eoverflow | 命令 参数为 F_GETLK ,并且未能在 群 结构中表示块锁定。 |
如果下列其中一项或两项成立,那么 重复 和 dup2 子例程将失败:
| 项 | 描述 |
|---|---|
| EBADF | 旧 参数指定了无效的打开文件描述符,或 新建 参数指定了超出范围的文件描述符。 |
| 电子文件 | 文件描述符的数目超过 OPEN_MAX 值,或者没有文件描述符高于 新建 参数的值。 |
如果 NFS 安装在系统上,那么如果以下情况成立,那么 fcntl 子例程可能会失败:
| 项 | 描述 |
|---|---|
| 时间已到 | 连接已超时。 |