errno 值的宏定义

  1. 输入

cd /usr/include/asm-generic
ls
gedit errno.h 或者 vim errno.h

查看

  1. 或者使用man手册

man 3 errno

  • 以下摘自 /usr/include/asm

/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_GENERIC_ERRNO_H
#define _ASM_GENERIC_ERRNO_H

#include <asm-generic/errno-base.h>

#define EDEADLK 35 /* Resource deadlock would occur /
#define ENAMETOOLONG 36 /
File name too long /
#define ENOLCK 37 /
No record locks available */

/*

  • This error code is special: arch syscall entry code will return
  • -ENOSYS if users try to call a syscall that doesn’t exist. To keep
  • failures of syscalls that really do exist distinguishable from
  • failures due to attempts to use a nonexistent syscall, syscall
  • implementations should refrain from returning -ENOSYS.
    /
    #define ENOSYS 38 /
    Invalid system call number */

#define ENOTEMPTY 39 /* Directory not empty /
#define ELOOP 40 /
Too many symbolic links encountered /
#define EWOULDBLOCK EAGAIN /
Operation would block /
#define ENOMSG 42 /
No message of desired type /
#define EIDRM 43 /
Identifier removed /
#define ECHRNG 44 /
Channel number out of range /
#define EL2NSYNC 45 /
Level 2 not synchronized /
#define EL3HLT 46 /
Level 3 halted /
#define EL3RST 47 /
Level 3 reset /
#define ELNRNG 48 /
Link number out of range /
#define EUNATCH 49 /
Protocol driver not attached /
#define ENOCSI 50 /
No CSI structure available /
#define EL2HLT 51 /
Level 2 halted /
#define EBADE 52 /
Invalid exchange /
#define EBADR 53 /
Invalid request descriptor /
#define EXFULL 54 /
Exchange full /
#define ENOANO 55 /
No anode /
#define EBADRQC 56 /
Invalid request code /
#define EBADSLT 57 /
Invalid slot */

#define EDEADLOCK EDEADLK

#define EBFONT 59 /* Bad font file format /
#define ENOSTR 60 /
Device not a stream /
#define ENODATA 61 /
No data available /
#define ETIME 62 /
Timer expired /
#define ENOSR 63 /
Out of streams resources /
#define ENONET 64 /
Machine is not on the network /
#define ENOPKG 65 /
Package not installed /
#define EREMOTE 66 /
Object is remote /
#define ENOLINK 67 /
Link has been severed /
#define EADV 68 /
Advertise error /
#define ESRMNT 69 /
Srmount error /
#define ECOMM 70 /
Communication error on send /
#define EPROTO 71 /
Protocol error /
#define EMULTIHOP 72 /
Multihop attempted /
#define EDOTDOT 73 /
RFS specific error /
#define EBADMSG 74 /
Not a data message /
#define EOVERFLOW 75 /
Value too large for defined data type /
#define ENOTUNIQ 76 /
Name not unique on network /
#define EBADFD 77 /
File descriptor in bad state /
#define EREMCHG 78 /
Remote address changed /
#define ELIBACC 79 /
Can not access a needed shared library /
#define ELIBBAD 80 /
Accessing a corrupted shared library /
#define ELIBSCN 81 /
.lib section in a.out corrupted /
#define ELIBMAX 82 /
Attempting to link in too many shared libraries /
#define ELIBEXEC 83 /
Cannot exec a shared library directly /
#define EILSEQ 84 /
Illegal byte sequence /
#define ERESTART 85 /
Interrupted system call should be restarted /
#define ESTRPIPE 86 /
Streams pipe error /
#define EUSERS 87 /
Too many users /
#define ENOTSOCK 88 /
Socket operation on non-socket /
#define EDESTADDRREQ 89 /
Destination address required /
#define EMSGSIZE 90 /
Message too long /
#define EPROTOTYPE 91 /
Protocol wrong type for socket /
#define ENOPROTOOPT 92 /
Protocol not available /
#define EPROTONOSUPPORT 93 /
Protocol not supported /
#define ESOCKTNOSUPPORT 94 /
Socket type not supported /
#define EOPNOTSUPP 95 /
Operation not supported on transport endpoint /
#define EPFNOSUPPORT 96 /
Protocol family not supported /
#define EAFNOSUPPORT 97 /
Address family not supported by protocol /
#define EADDRINUSE 98 /
Address already in use /
#define EADDRNOTAVAIL 99 /
Cannot assign requested address /
#define ENETDOWN 100 /
Network is down /
#define ENETUNREACH 101 /
Network is unreachable /
#define ENETRESET 102 /
Network dropped connection because of reset /
#define ECONNABORTED 103 /
Software caused connection abort /
#define ECONNRESET 104 /
Connection reset by peer /
#define ENOBUFS 105 /
No buffer space available /
#define EISCONN 106 /
Transport endpoint is already connected /
#define ENOTCONN 107 /
Transport endpoint is not connected /
#define ESHUTDOWN 108 /
Cannot send after transport endpoint shutdown /
#define ETOOMANYREFS 109 /
Too many references: cannot splice /
#define ETIMEDOUT 110 /
Connection timed out /
#define ECONNREFUSED 111 /
Connection refused /
#define EHOSTDOWN 112 /
Host is down /
#define EHOSTUNREACH 113 /
No route to host /
#define EALREADY 114 /
Operation already in progress /
#define EINPROGRESS 115 /
Operation now in progress /
#define ESTALE 116 /
Stale file handle /
#define EUCLEAN 117 /
Structure needs cleaning /
#define ENOTNAM 118 /
Not a XENIX named type file /
#define ENAVAIL 119 /
No XENIX semaphores available /
#define EISNAM 120 /
Is a named type file /
#define EREMOTEIO 121 /
Remote I/O error /
#define EDQUOT 122 /
Quota exceeded */

#define ENOMEDIUM 123 /* No medium found /
#define EMEDIUMTYPE 124 /
Wrong medium type /
#define ECANCELED 125 /
Operation Canceled /
#define ENOKEY 126 /
Required key not available /
#define EKEYEXPIRED 127 /
Key has expired /
#define EKEYREVOKED 128 /
Key has been revoked /
#define EKEYREJECTED 129 /
Key was rejected by service */

/* for robust mutexes /
#define EOWNERDEAD 130 /
Owner died /
#define ENOTRECOVERABLE 131 /
State not recoverable */

#define ERFKILL 132 /* Operation not possible due to RF-kill */

#define EHWPOISON 133 /* Memory page has hardware error */

#endif

<think>在C语言中,`errno`是一个全局变量(通常是一个,展开为可修改的左),用于存储系统调用和库函数调用失败时的错误代码。当系统调用或库函数发生错误时,它们通常会返回一个特殊(如-1或NULL)并设置`errno`以指示具体的错误原因。 `EINTR`是定义在`<errno.h>`头文件中的一个错误代码常量,表示系统调用被信号中断(Interrupted system call)。当系统调用正在执行时,如果进程捕获到一个信号并处理它,那么某些系统调用可能会被中断,此时系统调用会返回-1(或错误)并设置`errno`为`EINTR`。 ### 关键点: 1. **errno**: - 声明在`<errno.h>`中 - 每个线程都有独立的errno(在多线程环境中) - 使用`perror()`或`strerror()`可以输出错误描述 2. **EINTR**: - 通常为4(在Linux系统中) - 常见于慢速系统调用(如`accept`, `read`, `write`, `wait`等) - 需要特殊处理:通常重新调用被中断的系统调用 ### 示例代码:处理EINTR的accept ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> // 必须包含 int main() { int server_fd = socket(AF_INET, SOCK_STREAM, 0); // ... 绑定和监听 ... while (1) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int client_sock; // 循环处理accept被信号中断的情况 while (1) { client_sock = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_sock >= 0) { break; // 成功接受连接 } // 检查错误类型 if (errno == EINTR) { printf("accept interrupted, retrying...\n"); continue; // 重新尝试accept } // 其他错误则退出 perror("accept failed"); exit(EXIT_FAILURE); } // 处理客户端连接 printf("New connection accepted\n"); close(client_sock); } return 0; } ``` ### 处理其他可能被中断的系统调用 对于`read`、`write`等系统调用,同样需要处理`EINTR`: ```c ssize_t safe_read(int fd, void *buf, size_t count) { ssize_t n; do { n = read(fd, buf, count); } while (n == -1 && errno == EINTR); // 被中断时重试 return n; } ``` ### 为什么需要处理EINTR? 在早期的UNIX系统中,系统调用被信号中断后不会自动重启。POSIX标准允许系统调用在信号处理后返回`EINTR`,要求应用程序处理这种情况。现代系统提供了`SA_RESTART`标志(通过`sigaction`设置)来自动重启被中断的系统调用,但并非所有系统调用都支持自动重启(如`accept`、`recv`等)。 ### 自动重启系统调用 使用`sigaction`设置信号处理时指定`SA_RESTART`: ```c struct sigaction sa; sa.sa_handler = handler_function; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; // 关键:自动重启被中断的系统调用 sigaction(SIGINT, &sa, NULL); ``` 但注意:`SA_RESTART`并不适用于所有系统调用(如套接字超时操作)。 ### 总结处理策略 1. **循环重试**:对可能返回`EINTR`的系统调用进行循环重试 2. **使用SA_RESTART**:对信号处理函数设置自动重启标志 3. **检查文档**:确认系统调用是否支持自动重启 --- §§相关问题§§: 1. 在Linux中,哪些系统调用会被信号中断并返回EINTR? 2. 如何设计一个安全的信号处理函数? 3. 在多线程程序中处理信号有哪些注意事项? 4. 除了EINTR,还有哪些常见的errno错误码需要特殊处理?</think>### `errno` 和 `EINTR` 的详细解释 在 Unix/Linux 系统编程中,`errno` 和 `EINTR` 是处理系统调用错误的关键机制: #### 1. `errno` - 错误代码变量 `errno` 是一个全局整型变量(实际是线程局部存储),用于存储最近发生的系统调用错误代码。 **特性**: - 声明在 `<errno.h>` 头文件中 - 系统调用失败时设置,成功时不修改 - 必须立即检查,可能被后续调用覆盖 - 使用 `perror()` 或 `strerror()` 可转换为可读错误信息 **常用函数**: ```c #include <errno.h> // 声明 errno #include <string.h> // 声明 strerror() // 示例用法 if (some_syscall() == -1) { printf("Error %d: %s\n", errno, strerror(errno)); perror("some_syscall failed"); // 自动添加描述 } ``` #### 2. `EINTR` - 被中断的系统调用 `EINTR` 是定义在 `<errno.h>` 中的错误代码常量,表示系统调用被信号中断。 **含义**: - 数通常是 4(在 Linux 系统中) - 当进程在执行阻塞系统调用时收到信号 - 系统调用未完成即返回 - **需要特殊处理**:通常应重试被中断的调用 **常见场景**: ```c // 典型处理模式 while (1) { int result = accept(sockfd, addr, addrlen); if (result >= 0) { // 成功 break; } if (errno == EINTR) { // 被信号中断,重试 continue; } // 其他错误处理 perror("accept failed"); break; } ``` ### 完整错误处理示例 ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <string.h> void handle_client(int client_fd) { char buffer[256]; ssize_t n; // 带EINTR处理的read循环 while ((n = read(client_fd, buffer, sizeof(buffer))) { if (n == -1) { if (errno == EINTR) { printf("Read interrupted, retrying...\n"); continue; } perror("read error"); break; } // 处理数据 write(STDOUT_FILENO, buffer, n); } close(client_fd); } int main() { int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == -1) { perror("socket creation failed"); exit(EXIT_FAILURE); } struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(8080), .sin_addr.s_addr = INADDR_ANY }; if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind failed"); close(server_fd); exit(EXIT_FAILURE); } if (listen(server_fd, 5) < 0) { perror("listen failed"); close(server_fd); exit(EXIT_FAILURE); } printf("Server listening on port 8080\n"); while (1) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int client_fd; // 带EINTR处理的accept循环 while (1) { client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd >= 0) break; if (errno == EINTR) { printf("Accept interrupted, retrying...\n"); continue; } perror("accept failed"); exit(EXIT_FAILURE); } printf("Accepted new connection\n"); handle_client(client_fd); } close(server_fd); return 0; } ``` ### 关键错误处理模式 #### 1. 通用错误处理模板 ```c int result = system_call(...); if (result == -1) { switch (errno) { case EINTR: // 被信号中断,重试 continue; case EAGAIN: // 或 EWOULDBLOCK // 资源暂时不可用,稍后重试 usleep(10000); continue; case ECONNRESET: // 连接被对方重置 close(fd); break; default: // 其他错误 perror("system_call failed"); exit(EXIT_FAILURE); } } ``` #### 2. 自动重试 ```c #define CALL_WITH_RETRY(syscall, ...) ({ \ __typeof__(syscall(__VA_ARGS__)) __ret; \ do { \ __ret = syscall(__VA_ARGS__); \ } while (__ret == -1 && errno == EINTR); \ __ret; \ }) // 使用示例 int client_fd = CALL_WITH_RETRY(accept, server_fd, addr, addrlen); ``` ### 常见需要处理 EINTR 的系统调用 | **系统调用** | **描述** | **典型处理** | |-------------|---------|------------| | `accept()` | 接受连接 | 循环重试 | | `read()` | 读取数据 | 循环重试 | | `write()` | 写入数据 | 循环重试 | | `connect()` | 建立连接 | 检查错误类型 | | `waitpid()` | 等待子进程 | 循环重试 | | `nanosleep()` | 高精度睡眠 | 计算剩余时间重试 | ### 重要注意事项 1. **信号处理**:使用 `sigaction` 替代 `signal`,设置 `SA_RESTART` 标志可自动重启部分系统调用 ```c struct sigaction sa = { .sa_handler = handler, .sa_flags = SA_RESTART // 关键:自动重启被中断的调用 }; sigaction(SIGUSR1, &sa, NULL); ``` 2. **非阻塞I/O**:设置文件描述符为非阻塞模式可避免某些阻塞问题 ```c int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); ``` 3. **线程安全**:在多线程程序中,`errno` 是线程局部变量,可安全使用 4. **错误恢复**:不是所有错误都应重试,如 `EBADF`(错误文件描述符)需要终止程序 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值