10.3 errno.h
包含标准头文件 <errno.h> 以测试某些库函数存储在 errno 中的值。 在程序启动时,存储的值为零。 库函数只存储大于零的值。 任何库函数都可以更改存储的值,但仅在此处记录明确??要求库函数存储值的情况。
要测试库函数是否在 errno 中存储了值,程序应该在调用库函数之前立即将值存储在 errno 中。
#define EDOM <#if expression>
#define EILSEQ <#if expression> [added with Amendment 1]
#define ERANGE <#if expression>
#define errno <int modifiable lvalue>
实现可以在此标准标头中定义其他宏,你可以测试它们与存储的值是否相等。 所有这些附加宏的名称都以 E 开头。例如,以下宏是由 Posix 添加的:
#define E2BIG [argument list too long]
#define EACCES [process lacks access permission]
#define EAGAIN [resource temporarily unavailable]
#define EBADF [bad file descriptor]
#define EBADMSG [bad message]
#define EBUSY [resource is busy]
#define ECANCELED [operation canceled]
#define ECHILD [no child process present]
#define EDEADLK [resource deadlock was avoided]
#define EEXIST [file already exists]
#define EFAULT [bad memory address]
#define EFBIG [file would become too big]
#define EINPROGRESS [asynchronous operation not completed]
#define EINTR [operation interrupted by a signal]
#define EINVAL [invalid argument]
#define EIO [input/output error]
#define EISDIR [can't write to a directory]
#define EMFILE [process has too many files open]
#define EMLINK [too many links to a file]
#define EMSGSIZE [bad message buffer size]
#define ENAMETOOLONG [file name too long]
#define ENFILE [system has too many files open]
#define ENODEV [invalid device operation]
#define ENOENT [bad file or directory name]
#define ENOEXEC [can't execute file]
#define ENOLCK [too many locks on a file or record]
#define ENOMEM [insufficient memory]
#define ENOSPC [insufficient space on a device]
#define ENOSYS [unimplemented function]
#define ENOTDIR [invalid directory name]
#define ENOTEMPTY [directory not empty]
#define ENOTSUP [unsupported feature[
#define ENOTTY [bad I/O control operation]
#define ENXIO [bad device specifier]
#define EPERM [process lacks permission]
#define EPIPE [write to a broken pipe]
#define EROFS [write to a read-only file system]
#define ESPIPE [seek on a pipe]
#define ESRCH [process search failed]
#define ETIMEDOUT [time limit expired]
#define EXDEV [link across file systems]
10.3.1 EDOM
#define EDOM <#if expression> 宏产生存储在 errno 中的域错误值。
10.3.2 EILSEQ
#define EILSEQ <#if expression> [added with Amendment 1]
该宏在无效的多字节序列上产生存储在 errno 中的值。
10.3.3 ERANGE
#define ERANGE <#if expression> 宏产生范围错误时存储在 errno 中的值。
10.3.4 errno
#define errno <int modifiable lvalue>
该宏指定一个对象,该对象在某些库错误时分配的值大于零。
10.4 fcntl.h
该文件包含文件描述符控制功能。 int fcntl(int fd, int cmd, ...); [POSIX]
10.4.1 fcntl
int fcntl(int fd, int cmd, ...); [POSIX]
fcntl 提供对描述符的控制。 参数 fd 是由 cmd 操作的描述符,如下所述。 第三个参数称为 arg 并且在技术上是指向 void 的指针,但它被某些命令解释为 int 并被其他命令忽略。
命令是:
表 10-1 fcntl 命令
命令 | 描述 |
---|
F_DUPFD | 返回一个新的描述符,如下所示: 1.大于或等于arg 的最小可用描述符,它被解释为一个int。 2.与原始描述符相同的对象引用。 3.如果对象是文件,则新描述符共享相同的文件偏移量。 4.相同的访问模式(读、写或读/写)。 5.相同的文件状态标志(即,两个文件描述符共享相同的文件状态标志)。 6.与新文件描述符关联的close-on-exec 标志被清除以在execve 系统调用中保持打开状态。 | F_GETFD | 获取与文件描述符 fd 关联的 close-on-exec 标志为 FD_CLOEXEC。 如果与 FD_CLOEXEC 的返回值为 0,则文件将在 exec 中保持打开状态,否则文件将在 exec 执行时关闭(arg 被忽略)。 | F_SETFD | 将与 fd 关联的 close-on-exec 标志设置为 arg,其中 arg 为 0 或 FD_CLOEXEC,如上所述。 | F_GETFL | 获取描述符状态标志,如下所述(arg 被忽略)。 | F_SETFL | 将描述符状态标志设置为 arg,它被解释为一个 int。 | F_GETOWN | 获取当前接收SIGIO和SIGURG信号的进程ID或进程组; 进程组作为负值返回(arg 被忽略)。 | F_SETOWN | 设置进程或进程组接收SIGIO和SIGURG信号; 通过将 arg 提供为负数来指定进程组,否则 arg 被解释为进程 ID。 参数 arg 被解释为 int。 | F_CLOSEM | 关闭所有大于等于 fd 的文件描述符。 | F_MAXFD | 返回进程当前打开的最大文件描述符数。 |
F_GETFL 和 F_SETFL 标志的标志如下:
表 10-2 fcntl 标志
标志 | 描述 |
---|
O_NONBLOCK | 非阻塞 I/O; 如果没有数据可用于读取调用,或者写入操作会阻塞,则读取或写入调用将返回 -1 并带有错误 EAGAIN。 | O_APPEND | 强制每次写入附加在文件末尾; 对应open的O_APPEND标志。 | O_ASYNC | 当 I/O 可能时,例如,在有要读取的数据时,启用 SIGIO 信号发送到进程组。 |
有几个命令可用于执行建议文件锁定; 它们都在以下结构上运行:
struct flock {
off_t l_start; /* starting offset */
off_t l_len; /* len = 0 means until end of file */
pid_t l_pid; /* lock owner */
short l_type; /* lock type: read/write, etc. */
short l_whence; /* type of l_start */
};
可用于寻访记录锁定的命令如下:
表 10-3 寻访记录锁定命令
命令 | 描述 |
---|
F_GETLK | 获取阻止第三个参数 arg 指向的锁描述的第一个锁,将其作为指向 structflock 的指针(见上文)。 检索到的信息会覆盖在群结构中传递给 fcntl 的信息。 如果没有找到会阻止创建此锁的锁,则此函数调用使结构保持不变,但锁类型 l_type 设置为 F_UNLCK。 | F_SETLK | 根据第三个参数 arg 指向的锁描述设置或清除文件段锁,该参数作为指向 structflock 的指针(见上文)。 正如 l_type 的值所指定的,F_SETLK 用于建立共享(或读)锁(F_RDLCK)或排他(或写)锁(F_WRLCK),以及删除任一类型的锁(F_UNLCK)。 如果无法设置共享锁或排他锁,fcntl 会立即返回 EAGAIN。 | F_SETLKW | 此命令与 F_SETLK 相同,只是如果共享锁或排他锁被其他锁阻塞,则进程等待直到可以满足请求。 如果在 fcntl 等待区域时接收到要捕获的信号,如果信号处理程序未指定 SA_RESTART,则 fcntl 将被中断。 |
当在文件的某个段上设置共享锁时,其他进程可以在该段或其一部分上设置共享锁。 共享锁可防止任何其他进程在受保护区域的任何部分设置排他锁。 如果文件描述符未以读取访问权限打开,则共享锁请求失败。
排他锁可防止任何其他进程在受保护区域的任何部分设置共享锁或排他锁。 如果文件不是以写访问权限打开的,则对独占锁的请求将失败。
l_whence 的值是 SEEK_SET、SEEK_CUR 或 SEEK_END,表示相对偏移量 l_start 字节将分别从文件开头、当前位置或文件结尾开始测量。 l_len 的值是要锁定的连续字节数。 如果 l_len 为负,则结果未定义。 l_pid 字段仅与 F_GETLK 一起使用,以返回持有阻塞锁的进程的进程 ID。 F_GETLK 请求成功后,l_whence 的值为 SEEK_SET。
锁可以开始并延伸到文件的当前结尾之外,但不能在文件开头之前开始或延伸。 如果 l_len 设置为零,则将锁设置为扩展到该文件的文件偏移的最大可能值。 如果 l_whence 和 l_start 指向文件的开头,并且 l_len 为零,则整个文件被锁定。 如果应用程序只希望对整个文件进行锁定,flock 系统调用会更有效。
文件中的每个字节最多设置一种类型的锁。 在从 F_SETLK 或 F_SETLKW 请求成功返回之前,当调用进程在请求指定的区域中先前存在对字节的锁定时,指定区域中每个字节的先前锁定类型被新的锁定类型替换。 如上面在共享锁和排他锁的描述中所指定的,当另一个进程在指定区域中的字节上存在现有锁并且任何这些锁的类型与要求。
这个接口完全遵循 AT&T System V UNIX 和 IEEE Std 的愚蠢语义。 1003.1-1988 (``POSIX.1’’) 要求当该文件的任何文件描述符被该进程关闭时,删除与给定进程的文件关联的所有锁。 这种语义意味着应用程序必须知道子程序库可以访问的任何文件。 例如,如果更新密码文件的应用程序在进行更新时锁定了密码文件数据库,然后调用 getpwnam 检索记录,则由于 getpwnam 打开、读取和关闭密码数据库,锁定将丢失。 数据库关闭将释放进程与数据库关联的所有锁,即使库例程从未请求数据库上的锁。 这个接口的另一个小的语义问题是锁不会被使用 fork 函数创建的子进程继承。 flock 接口具有更合理的最后关闭语义,并允许子进程继承锁。 对于希望在使用库例程时确保其锁的完整性或希望将锁传递给其子级的应用程序,建议调用flock。 请注意,flock 和 fcntl 锁可以安全地同时使用。
当进程终止时,与给定进程的文件关联的所有锁都将被删除。
如果控制锁定区域的进程通过尝试锁定另一个进程的锁定区域而进入睡眠状态,则可能发生死锁。 此实现检测到在锁定区域解锁之前休眠会导致死锁并因 EDEADLK 错误而失败。
成功完成后,返回值取决于 cmd 如下:
表 10-4 fcntl 的返回值
值 | 描述 |
---|
F_DUPFD | 一个新的文件描述符。 | F_GETFD | flag 的值(仅定义了低位)。 | F_GETFL | 标志的值。 | F_GETOWN | 文件描述符所有者的值。 | F_MAXFD | 进程打开的最高文件描述符的值。 | other | -1 以外的值。 |
否则,返回值 -1 并设置 errno 以指示错误。
|