fcntl(2) - Linux 手册页
名称
fcntl - 操作文件描述符
概要
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ );
描述
fcntl() 对打开的文件描述符 fd 执行以下描述的操作之一。操作由 cmd 决定。
fcntl() 可以接受一个可选的第三个参数。是否需要此参数取决于 cmd。所需的参数类型在每个 cmd 名称后的括号中指出(在大多数情况下,所需的类型是 int,我们使用名称 arg 来标识该参数),如果不需要参数,则指定为 void。
复制文件描述符
- F_DUPFD (int)
- 查找大于或等于 arg 的最小可用文件描述符,并使其成为 fd 的副本。这与 dup2(2) 不同,后者使用完全指定描述符。
- 成功时,返回新的描述符。
详情请参阅 dup(2)。
- F_DUPFD_CLOEXEC (int;自 Linux 2.6.24 起)
- 与 F_DUPFD 相同,但会额外为重复的描述符设置 close-on-exec 标志。指定此标志允许程序避免额外的 fcntl() F_SETFD 操作来设置 FD_CLOEXEC 标志。关于此标志为何有用的解释,请参阅 open(2) 中对 O_CLOEXEC 的描述。
文件描述符标志
- 以下命令用于操作与文件描述符关联的标志。目前,仅定义了一个此类标志:FD_CLOEXEC,即 close-on-exec 标志。如果 FD_CLOEXEC 位为 0,则文件描述符将在 execve(2) 之后保持打开状态,否则将被关闭。
- F_GETFD (void)
- 读取文件描述符标志;忽略 arg。
- F_SETFD (int)
- 将文件描述符标志设置为 arg 指定的值。
文件状态标志
- 每个打开的文件描述都有某些关联的状态标志,由 open(2) 初始化,并可能由 fcntl() 修改。重复的文件描述符(由 dup(2)、fcntl(F_DUPFD)、fork(2) 等创建)引用同一个打开的文件描述,因此共享相同的文件状态标志。
文件状态标志及其语义在 open(2) 中描述。
- F_GETFL (void)
- 获取文件访问模式和文件状态标志;忽略 arg。
- F_SETFL (int)
- 将文件状态标志设置为 arg 指定的值。arg 中的文件访问模式(O_RDONLY, O_WRONLY, O_RDWR)和文件创建标志(例如 O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC)将被忽略。在 Linux 上,此命令只能更改 O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK 标志。
建议性锁 (Advisory locking)
- F_GETLK、F_SETLK 和 F_SETLKW 用于获取、释放和测试记录锁(也称为文件段锁或文件区域锁)的存在性。第三个参数 lock 是一个指向结构体的指针,该结构体至少包含以下字段(顺序未指定)。
-
struct flock { ... short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Starting offset for lock */ off_t l_len; /* Number of bytes to lock */ pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */ ... }; - 该结构体的 l_whence、l_start 和 l_len 字段指定了我们希望锁定的字节范围。文件末尾之后的字节可以被锁定,但文件起始之前的字节不可以。
l_start 是锁的起始偏移量,其解释相对如下位置之一:文件开始(如果 l_whence 为 SEEK_SET);当前文件偏移量(如果 l_whence 为 SEEK_CUR);或文件末尾(如果 l_whence 为 SEEK_END)。在后两种情况下,只要偏移量不位于文件起始之前,l_start 可以是负数。
l_len 指定要锁定的字节数。如果 l_len 为正数,则锁定的范围涵盖从 l_start 到 l_start+l_len-1(包含)的所有字节。将 l_len 指定为 0 具有特殊含义:锁定从 l_whence 和 l_start 指定位置开始直到文件末尾的所有字节,无论文件增长多大。
POSIX.1-2001 允许(但不要求)实现支持负的 l_len 值;如果 l_len 为负,则 lock 所描述的区间涵盖从 l_start+l_len 到 l_start-1(包含)的字节。自 Linux 内核版本 2.4.21 和 2.5.49 起,Linux 支持此特性。
l_type 字段可用于在文件上放置读取锁 (F_RDLCK) 或写入锁 (F_WRLCK)。任意数量的进程可以在文件区域持有读取锁(共享锁),但只有一个进程可以持有写入锁(独占锁)。独占锁会排除所有其他锁,无论是共享锁还是独占锁。单个进程一次只能在文件区域上持有一种类型的锁;如果将新锁应用于已锁定的区域,则现有锁将转换为新的锁类型。(如果新锁指定的字节范围与现有锁的范围不完全重合,此类转换可能涉及拆分、缩小或合并现有锁。)
- F_SETLK (struct flock *)
- 获取锁(当 l_type 为 F_RDLCK 或 F_WRLCK 时)或释放锁(当 l_type 为 F_UNLCK 时),锁定对象为 lock 的 l_whence、l_start 和 l_len 字段指定的字节范围。如果另一个进程持有冲突锁,则此调用返回 -1 并将 errno 设置为 EACCES 或 EAGAIN。
- F_SETLKW (struct flock *)
- 与 F_SETLK 相同,但如果文件上持有冲突锁,则等待该锁释放。如果在等待时捕获到信号,则调用被中断(在信号处理程序返回后),并立即返回(返回值为 -1,errno 设置为 EINTR;参见 signal(7))。
- F_GETLK (struct flock *)
- 在此调用输入时,lock 描述了我们想要在文件上放置的锁。如果可以放置该锁,fcntl() 不会实际放置它,但会在 lock 的 l_type 字段中返回 F_UNLCK,并保持结构体的其他字段不变。如果一个或多个不兼容的锁阻止了该锁的放置,则 fcntl() 会在 lock 的 l_type、l_whence、l_start 和 l_len 字段中返回这些锁之一的详细信息,并将 l_pid 设置为持有该锁的进程的 PID。
- 为了放置读取锁,fd 必须以读取方式打开。为了放置写入锁,fd 必须以写入方式打开。要放置两种类型的锁,应以读写方式打开文件。
除了通过显式的 F_UNLCK 移除外,记录锁在进程终止时或在关闭引用了锁所在文件的任何文件描述符时会自动释放。这很糟糕:这意味着当某个库函数因某种原因决定打开、读取并关闭一个文件(如 /etc/passwd 或 /etc/mtab)时,进程可能会丢失该文件上的锁。
记录锁不会被通过 fork(2) 创建的子进程继承,但会在 execve(2) 期间保留。
由于 stdio(3) 库执行的缓冲作用,应避免在处理该程序包的例程中使用记录锁定;请改用 read(2) 和 write(2)。
强制锁 (Mandatory locking)
- (非 POSIX。) 上述记录锁可以是建议性的,也可以是强制性的,默认情况下是建议性的。
建议性锁不强制执行,仅在协作进程之间有用。
强制锁对所有进程强制执行。如果进程尝试对具有不兼容强制锁的文件区域执行不兼容的访问(例如 read(2) 或 write(2)),则结果取决于其打开的文件描述是否启用了 O_NONBLOCK 标志。如果未启用 O_NONBLOCK 标志,则系统调用将被阻塞,直到锁被移除或转换为与访问兼容的模式。如果启用了 O_NONBLOCK 标志,则系统调用失败并报错 EAGAIN。
要使用强制锁,必须在包含要锁定的文件的文件系统上以及文件本身上启用强制锁定。在文件系统上使用 mount(8) 的“-o mand”选项或 mount(2) 的 MS_MANDLOCK 标志启用强制锁定。通过禁用文件的组执行权限并启用设置组 ID 权限位(参见 chmod(1) 和 chmod(2)),可以在文件上启用强制锁定。
Linux 对强制锁的实现是不可靠的。请参阅下文的 BUGS。
管理信号
- F_GETOWN、F_SETOWN、F_GETOWN_EX、F_SETOWN_EX、F_GETSIG 和 F_SETSIG 用于管理 I/O 可用性信号
- F_GETOWN (void)
- 返回(作为函数结果)当前接收文件描述符 fd 事件相关的 SIGIO 和 SIGURG 信号的进程 ID 或进程组 ID。进程 ID 以正值返回;进程组 ID 以负值返回(但请参见下文 BUGS)。忽略 arg。
- F_SETOWN (int)
- 将接收文件描述符 fd 事件相关的 SIGIO 和 SIGURG 信号的进程 ID 或进程组 ID 设置为 arg 中给出的 ID。进程 ID 指定为正值;进程组 ID 指定为负值。通常,调用进程将自身指定为所有者(即 arg 指定为 getpid(2))。
如果您通过使用 fcntl() 的 F_SETFL 命令在文件描述符上设置 O_ASYNC 状态标志,则每当该文件描述符上变得可进行输入或输出时,就会发送一个 SIGIO 信号。F_SETSIG 可用于获取除 SIGIO 以外的信号。如果此权限检查失败,则信号将被静默丢弃。
向 F_SETOWN 指定的所有者进程(组)发送信号受与 kill(2) 描述相同的权限检查约束,其中发送进程是使用 F_SETOWN 的进程(但请参见下文 BUGS)。
如果文件描述符 fd 引用一个套接字,F_SETOWN 还会选择当带外数据到达该套接字时发送的 SIGURG 信号的接收者。(SIGURG 在 select(2) 将套接字报告为具有“异常条件”的任何情况下发送。)
以下内容在 2.6.x 内核(包括 2.6.11)中适用
如果在运行支持线程组的线程库(例如 NPTL)的多线程进程中为 F_SETSIG 给定一个非零值,则赋予 F_SETOWN 的正值具有不同的含义:它不是标识整个进程的进程 ID,而是标识进程内特定线程的线程 ID。因此,当使用 F_SETSIG 时,可能需要向 F_SETOWN 传递 gettid(2) 的结果而不是 getpid(2) 才能获得合理的结果。(在当前的 Linux 线程实现中,主线程的线程 ID 与其进程 ID 相同。这意味着单线程程序在此场景中同样可以使用 gettid(2) 或 getpid(2)。)但请注意,本段中的陈述不适用于套接字上因带外数据而生成的 SIGURG 信号:此信号总是发送给进程或进程组,具体取决于赋予 F_SETOWN 的值。
- 上述行为在 Linux 2.6.12 中被意外删除,且不会恢复。从 Linux 2.6.32 开始,请使用 F_SETOWN_EX 将 SIGIO 和 SIGURG 信号发送至特定线程。
- F_GETOWN_EX (struct f_owner_ex *) (自 Linux 2.6.32 起)
- 返回由先前 F_SETOWN_EX 操作定义的当前文件描述符所有者设置。信息返回在 arg 指向的结构体中,该结构体具有以下形式
struct f_owner_ex { int type; pid_t pid; };type 字段将具有 F_OWNER_TID、F_OWNER_PID 或 F_OWNER_PGRP 值之一。pid 字段是一个代表线程 ID、进程 ID 或进程组 ID 的正整数。有关更多详细信息,请参阅 F_SETOWN_EX。 - F_SETOWN_EX (struct f_owner_ex *) (自 Linux 2.6.32 起)
- 此操作执行与 F_SETOWN 类似的任务。它允许调用者将 I/O 可用性信号定向到特定线程、进程或进程组。调用者通过 arg 指定信号的目标,arg 是指向 f_owner_ex 结构体的指针。type 字段具有以下值之一,这些值定义了如何解释 pid
- F_OWNER_TID
将信号发送至其线程 ID(调用 clone(2) 或 gettid(2) 返回的值)在 pid 中指定的线程。
- F_OWNER_PID
将信号发送至其 ID 在 pid 中指定的进程。
- F_OWNER_PGRP
将信号发送至其 ID 在 pid 中指定的进程组。(请注意,与 F_SETOWN 不同,此处进程组 ID 指定为正值。)
- F_GETSIG (void)
- 返回(作为函数结果)当输入或输出变得可用时发送的信号。值为零表示发送 SIGIO。任何其他值(包括 SIGIO)是取而代之发送的信号,在这种情况下,如果使用 SA_SIGINFO 安装了信号处理程序,则会有额外信息提供给处理程序。忽略 arg。
- F_SETSIG (int)
- 将输入或输出变得可用时发送的信号设置为 arg 中给定的值。值为零表示发送默认的 SIGIO 信号。任何其他值(包括 SIGIO)是取而代之发送的信号,在这种情况下,如果使用 SA_SIGINFO 安装了信号处理程序,则会有额外信息提供给处理程序。
通过将 F_SETSIG 与非零值结合使用,并为信号处理程序设置 SA_SIGINFO(参见 sigaction(2)),关于 I/O 事件的额外信息将以 siginfo_t 结构体形式传递给处理程序。如果 si_code 字段指示来源为 SI_SIGIO,则 si_fd 字段给出与事件关联的文件描述符。否则,没有迹象表明哪些文件描述符处于挂起状态,您应该使用常规机制(select(2)、poll(2)、设置了 O_NONBLOCK 的 read(2) 等)来确定哪些文件描述符可进行 I/O 操作。
通过选择实时信号(值 >= SIGRTMIN),可以使用相同的信号编号对多个 I/O 事件进行排队。(排队取决于可用内存)。如果为信号处理程序设置了 SA_SIGINFO,则如上所述提供额外信息。
请注意,Linux 对可以排队到进程的实时信号数量有限制(参见 getrlimit(2) 和 signal(7)),如果达到此限制,内核将恢复为传递 SIGIO,并且此信号将被传递给整个进程,而不是特定线程。
- 使用这些机制,程序可以在大多数情况下实现完全异步 I/O,而无需使用 select(2) 或 poll(2)。
O_ASYNC、F_GETOWN、F_SETOWN 的使用是 BSD 和 Linux 特有的。F_GETOWN_EX、F_SETOWN_EX、F_GETSIG 和 F_SETSIG 是 Linux 特有的。POSIX 有异步 I/O 和 aio_sigevent 结构体来实现类似的事情;这些在 Linux 中作为 GNU C 库 (Glibc) 的一部分也可用。
租约 (Leases)
- F_SETLEASE 和 F_GETLEASE(Linux 2.4 起)分别用于在文件描述符 fd 引用的打开文件描述上建立新租约和检索当前租约。文件租约提供了一种机制,使得持有租约的进程(“租约持有者”)在有进程(“租约破坏者”)尝试 open(2) 或 truncate(2) 该文件描述符引用的文件时会收到通知(通过发送信号)。
- F_SETLEASE (int)
- 根据整数 arg 中指定的以下值之一设置或移除文件租约
- F_RDLCK
获取读取租约。当文件被打开进行写入或被截断时,这将导致调用进程收到通知。读取租约只能放置在以只读方式打开的文件描述符上。
- F_WRLCK
获取写入租约。当文件被打开进行读取或写入或被截断时,这将导致调用者收到通知。仅当没有该文件的其他打开文件描述符时,才可以在文件上放置写入租约。
- F_UNLCK
从文件移除我们的租约。
- 租约与打开的文件描述关联(参见 open(2))。这意味着重复的文件描述符(例如由 fork(2) 或 dup(2) 创建的)引用同一个租约,并且可以使用这些描述符中的任何一个修改或释放此租约。此外,租约通过在任何这些重复描述符上执行显式的 F_UNLCK 操作或当所有此类描述符已关闭时被释放。
租约只能在常规文件上获取。非特权进程只能在 UID(所有者)与进程文件系统 UID 匹配的文件上获取租约。具有 CAP_LEASE 能力的进程可以在任意文件上获取租约。
- F_GETLEASE (void)
- 通过返回 F_RDLCK、F_WRLCK 或 F_UNLCK 指示与文件描述符 fd 关联的租约类型,分别表示读取租约、写入租约或无租约。忽略 arg。
- 当进程(“租约破坏者”)执行与通过 F_SETLEASE 建立的租约冲突的 open(2) 或 truncate(2) 时,系统调用会被内核阻塞,并且内核通过向租约持有者发送信号(默认情况下为 SIGIO)来通知它。租约持有者应通过执行准备让其他进程访问文件所需的任何清理工作(例如刷新缓存缓冲区)来响应此信号,然后移除或降级其租约。通过执行指定 arg 为 F_UNLCK 的 F_SETLEASE 命令来移除租约。如果租约持有者当前在文件上持有写入租约,并且租约破坏者正在以读取方式打开文件,则租约持有者将租约降级为读取租约就足够了。这可以通过执行指定 arg 为 F_RDLCK 的 F_SETLEASE 命令来完成。
如果租约持有者未能在 /proc/sys/fs/lease-break-time 中指定的秒数内降级或移除租约,则内核会强制移除或降级租约持有者的租约。
一旦启动租约破坏,F_GETLEASE 会返回目标租约类型(F_RDLCK 或 F_UNLCK,取决于与租约破坏者兼容的内容),直到租约持有者自愿降级或移除租约,或者内核在租约破坏计时器到期后强制执行此操作。
一旦租约被自愿或强制移除或降级,并且假设租约破坏者尚未取消阻塞其系统调用,内核将允许租约破坏者的系统调用继续进行。
如果租约破坏者被阻塞的 open(2) 或 truncate(2) 被信号处理程序中断,则系统调用失败并报错 EINTR,但其他步骤仍会如上所述发生。如果租约破坏者在阻塞于 open(2) 或 truncate(2) 时被信号杀死,则其他步骤仍会如上所述发生。如果租约破坏者在调用 open(2) 时指定了 O_NONBLOCK 标志,则调用立即失败并报错 EWOULDBLOCK,但其他步骤仍会如上所述发生。
用于通知租约持有者的默认信号是 SIGIO,但这可以使用 fcntl() 的 F_SETSIG 命令进行更改。如果执行了 F_SETSIG 命令(即使是指定 SIGIO 的命令),并且信号处理程序是使用 SA_SIGINFO 建立的,则处理程序将接收一个 siginfo_t 结构体作为其第二个参数,并且此参数的 si_fd 字段将保存被其他进程访问的已租用文件的描述符。(如果调用者持有针对多个文件的租约,这很有用)。
文件和目录更改通知 (dnotify)
- F_NOTIFY (int)
- (Linux 2.4 起) 当 fd 引用的目录或其包含的任何文件发生更改时提供通知。要通知的事件在 arg 中指定,这是一个位掩码,通过对以下零个或多个位进行 OR 运算指定
- DN_ACCESS
文件被访问(读取、pread、readv)
DN_MODIFY
文件被修改(写入、pwrite、writev、截断、ftruncate)。
DN_CREATE
文件被创建(open、creat、mknod、mkdir、link、symlink、rename)。
DN_DELETE
文件被取消链接(unlink、重命名到另一个目录、rmdir)。
DN_RENAME
文件在此目录内被重命名(rename)。
DN_ATTRIB
文件的属性被更改(chown、chmod、utime[s])。
- (为了获得这些定义,必须在包含任何头文件之前定义 _GNU_SOURCE 特性测试宏。)
目录通知通常是“一次性的”,应用程序必须重新注册才能接收进一步的通知。或者,如果 arg 中包含 DN_MULTISHOT,则通知将保持有效直到被显式移除。
一系列 F_NOTIFY 请求是累加的,arg 中的事件被添加到已监控的集合中。要禁用所有事件的通知,请进行指定 arg 为 0 的 F_NOTIFY 调用。
通知通过发送信号发生。默认信号是 SIGIO,但这可以使用 fcntl() 的 F_SETSIG 命令更改。在后一种情况下,信号处理程序接收一个 siginfo_t 结构体作为其第二个参数(如果处理程序是使用 SA_SIGINFO 建立的),并且此结构体的 si_fd 字段包含生成通知的文件描述符(在对多个目录建立通知时很有用)。
特别是在使用 DN_MULTISHOT 时,应使用实时信号进行通知,以便可以对多个通知进行排队。
注意: 新应用程序应使用 inotify 接口(自内核 2.6.13 起可用),它为获取文件系统事件通知提供了远优越的接口。参见 inotify(7)。
更改管道容量
- F_SETPIPE_SZ (int;自 Linux 2.6.35 起)
- 将 fd 引用的管道容量更改为至少 arg 字节。非特权进程可以将管道容量调整为系统页面大小与 /proc/sys/fs/pipe-max-size 中定义的限制之间的任何值(参见 proc(5))。尝试将管道容量设置为低于页面大小的值会静默向上舍入到页面大小。非特权进程尝试将管道容量设置在 /proc/sys/fs/pipe-max-size 限制之上会导致 EPERM 错误;特权进程 (CAP_SYS_RESOURCE) 可以覆盖该限制。在为管道分配缓冲区时,如果对实现方便,内核可能会使用大于 arg 的容量。F_GETPIPE_SZ 操作返回实际使用的尺寸。尝试将管道容量设置得小于当前用于存储数据的缓冲区空间会导致 EBUSY 错误。
- F_GETPIPE_SZ (void;自 Linux 2.6.35 起)
- 返回(作为函数结果)fd 引用的管道容量。
返回值
对于成功的调用,返回值取决于操作
- F_DUPFD
新的描述符。
F_GETFD
文件描述符标志的值。
F_GETFL
文件状态标志的值。
- F_GETLEASE
- 在文件描述符上持有的租约类型。
- F_GETOWN
描述符所有者的值。
F_GETSIG
当读取或写入变得可行时发送的信号的值,或者对于传统 SIGIO 行为为零。
- F_GETPIPE_SZ
- 管道容量。
- 所有其他命令
- 零。
- 出错时,返回 -1,并适当地设置 errno。
错误
EACCES 或 EAGAIN
- 操作被其他进程持有的锁禁止。
- EAGAIN
操作被禁止,因为文件已被其他进程内存映射。
EBADF
fd 不是一个打开的文件描述符,或者命令是 F_SETLK 或 F_SETLKW 且文件描述符打开模式与请求的锁类型不匹配。
- EDEADLK
- 检测到指定的 F_SETLKW 命令将导致死锁。
- EFAULT
lock 在您的可访问地址空间之外。
EINTR
对于 F_SETLKW,命令被信号中断;参见 signal(7)。对于 F_GETLK 和 F_SETLK,命令在检查或获取锁之前被信号中断。多发生于锁定远程文件(例如通过 NFS 锁定)时,但有时也会在本地发生。
EINVAL
对于 F_DUPFD,arg 为负或大于允许的最大值。对于 F_SETSIG,arg 不是允许的信号编号。
EMFILE
对于 F_DUPFD,该进程已经打开了最大数量的文件描述符。
ENOLCK
打开了太多的段锁,锁表已满,或者远程锁定协议失败(例如通过 NFS 锁定)。
EPERM
尝试清除设置了仅追加属性的文件上的 O_APPEND 标志。
符合
SVr4, 4.3BSD, POSIX.1-2001。只有 F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK 和 F_SETLKW 操作在 POSIX.1-2001 中指定。
F_GETOWN 和 F_SETOWN 在 POSIX.1-2001 中指定。(要获得它们的定义,请定义 BSD_SOURCE,或值为 500 或更高的 _XOPEN_SOURCE,或定义值为 200809L 或更高的 _POSIX_C_SOURCE。)
F_DUPFD_CLOEXEC 在 POSIX.1-2008 中指定。(要获得此定义,请定义值为 200809L 或更高的 _POSIX_C_SOURCE,或值为 700 或更高的 _XOPEN_SOURCE。)
F_GETOWN_EX、F_SETOWN_EX、F_SETPIPE_SZ、F_GETPIPE_SZ、F_GETSIG、F_SETSIG、F_NOTIFY、F_GETLEASE 和 F_SETLEASE 是 Linux 特有的。(定义 _GNU_SOURCE 宏以获得这些定义。)
说明
原始 Linux fcntl() 系统调用并未设计为处理大文件偏移量(在 flock 结构体中)。因此,Linux 2.4 中添加了 fcntl64() 系统调用。较新的系统调用为文件锁定使用了不同的结构体 flock64,以及相应的命令 F_GETLK64、F_SETLK64 和 F_SETLKW64。但是,使用 glibc 的应用程序可以忽略这些细节,glibc 的 fcntl() 包装函数会在可用时透明地使用较新的系统调用。
dup2(2) 返回的错误与 F_DUPFD 返回的错误不同。
自内核 2.0 起,flock(2) 放置的锁类型与 fcntl() 之间没有交互。
一些系统在 struct flock 中有更多字段,例如 l_sysid。显而易见,如果持有锁的进程可能位于不同的机器上,则仅有 l_pid 不会非常有用。
错误
Linux 系统调用约定在某些架构(特别是 i386)上的限制意味着,如果 F_GETOWN 返回的(负)进程组 ID 落在 -1 到 -4095 范围内,则 glibc 会将返回值错误地解释为系统调用中的错误;也就是说,fcntl() 的返回值将是 -1,而 errno 将包含(正的)进程组 ID。Linux 特有的 F_GETOWN_EX 操作避免了此问题。自 glibc 版本 2.11 起,glibc 通过使用 F_GETOWN_EX 实现 F_GETOWN,使内核 F_GETOWN 问题不可见。
在 Linux 2.4 及更早版本中,当非特权进程使用 F_SETOWN 指定套接字文件描述符的所有者为非调用者的进程(组)时,可能会发生错误。在这种情况下,即使调用者有权向所有者进程(组)发送信号,fcntl() 也可能返回 -1 并将 errno 设置为 EPERM。尽管有此错误返回,文件描述符所有者仍会被设置,并且信号会被发送给所有者。
在所有已知的 Linux 版本中,强制锁的实现都受竞争条件影响,这使得它不可靠:与锁重叠的 write(2) 调用可能会在获取强制锁后修改数据;与锁重叠的 read(2) 调用可能会检测到仅在获取写入锁后才对数据进行的更改。强制锁与 mmap(2) 之间也存在类似的竞争。因此,不建议依赖强制锁。
参见
dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7)
Linux 内核源码目录 Documentation/filesystems/ 中的 locks.txt、mandatory-locking.txt 和 dnotify.txt(在旧内核中,这些文件直接位于 Documentation/ 目录下,而 mandatory-locking.txt 被称为 mandatory.txt)