<errno.h>定义了整数变量extern int errno。errno是一个由POSIX和ISO C标准定义的符号,由系统调用和某些库函数根据事件来设置它,用以表明哪里有问题。这个值只有当调用的返回表明错误的时候有用(比如,对于大多数的系统调用是-1,对于大多数的库函数来说是-1或NULL),正确的函数也可以修改errno。
在程序启动时,errno 设置为零,系统调用或 C 标准库中的特定函数修改它的值为一些非零值以表示某些类型的错误。有效的错误number都是非零的,系统调用和库函数不会把errno设为0。 对于某些系统调用和库函数(比如,getpriority(2)),没有错误的时候也会返回-1。在这种情况下,可以在调用之前先将errno设为0,当不确定有没有错误的时候,可以通过查看errno是不是一个非零值来确定是否发生错误。
ISO C标准将errno定义为一个可以修改的int型左值,并且不允许准确声明,errno可能是一个宏,也可能被定义成一个变量,这个具体要看编译器自己的实现。
系统调用或库函数正确执行,并不保证errno的值不会被改变。
✏️ 1、线程安全性
早些时候,POSIX.1曾把errno定义成extern int errno这种形式,但这种形式实现的errno在多线程环境下是不安全的,errno变量是被多个线程共享的,这样可能线程A发生某些错误改变了errno的值,线程B虽然没有发生任何错误,但是当它检测errno的值的时候,线程B会以为自己发生了错误。
# ifndef __ASSEMBLER__/* Function to get address of global `errno' variable. */externint*__errno_location (void) __THROW __attribute__ ((__const__));# if!defined_LIBC||defined_LIBC_REENTRANT/* When using threads, errno is a per-thread value. */# defineerrno (*__errno_location ())# endif# endif /* !__ASSEMBLER__ */#endif /* _ERRNO_H */
在error.h中:
/* Declare the `errno' variable, unless it's defined as a macro by bits/errno.h. This is the case in GNU, where it is a per-thread variable. This redeclaration using the macro still works, but it will be a function declaration without a prototype and may trigger a -Wstrict-prototypes warning. */#ifndeferrnoexternint errno;#endif
可以清晰的看到,bits/errno.h对errno进行了重定义。从 __attribute__ ((__const__))推测出__errno_location ()会返回与参数无关的与线程绑定的一个特定地址,应用层直接从该地址取出errno的。(关于__attribute__用法可以参考Using GNU C attribute)。但是上面使用了条件编译,也就是有两种方法可以使得gcc重定义errno:
显然,__errno_location() 函数的返回值就是__hurd_threadvar_location(_HURD_THREADVAR_ERRNO) 函数的返回值被强转成 int * 了,那 __hurd_threadvar_location(_HURD_THREADVAR_ERRNO) 又是什么函数呢?
在头文件 <hurd/threadvar.h>中有:
#include<machine-sp.h>/* Define __thread_stack_pointer. *//* Return the location of the current thread's value for the per-thread variable with index INDEX. */externunsignedlongint*__hurd_threadvar_location (enum __hurd_threadvar_index __index) __THROW /* This declaration tells the compiler that the value is constant given the same argument. We assume this won't be called twice from the same stack frame by different threads. */__attribute__ ((__const__));_HURD_THREADVAR_H_EXTERN_INLINE unsignedlongint*__hurd_threadvar_location (enum __hurd_threadvar_index __index){return__hurd_threadvar_location_from_sp (__index,__thread_stack_pointer ());}
enum__hurd_threadvar_index{ _HURD_THREADVAR_MIG_REPLY, /* Reply port for MiG user stub functions. */ _HURD_THREADVAR_ERRNO, /* `errno' value for this thread. */ _HURD_THREADVAR_SIGSTATE, /* This thread's `struct hurd_sigstate'. */ _HURD_THREADVAR_DYNAMIC_USER, /* Dynamically-assigned user variables. */ _HURD_THREADVAR_MALLOC, /* For use of malloc. */ _HURD_THREADVAR_DL_ERROR, /* For use of -ldl and dynamic linker. */ _HURD_THREADVAR_RPC_VARS, /* For state of RPC functions. */ _HURD_THREADVAR_LOCALE, /* For thread-local locale setting. */ _HURD_THREADVAR_CTYPE_B, /* Cache of thread-local locale data. */ _HURD_THREADVAR_CTYPE_TOLOWER, /* Cache of thread-local locale data. */ _HURD_THREADVAR_CTYPE_TOUPPER, /* Cache of thread-local locale data. */ _HURD_THREADVAR_MAX /* Default value for __hurd_threadvar_max. */};externunsignedlongint __hurd_threadvar_stack_mask;externunsignedlongint __hurd_threadvar_stack_offset;externunsignedlongint __hurd_threadvar_stack_mask;externunsignedlongint __hurd_threadvar_stack_offset;externunsignedlongint __hurd_sigthread_stack_base;externunsignedlongint __hurd_sigthread_stack_end;externunsignedlongint*__hurd_sigthread_variables;
注释如下:
/* The per-thread variables are found by ANDing this mask with the value of the stack pointer and then adding this offset. In the multi-threaded case, cthreads initialization sets __hurd_threadvar_stack_mask to ~(cthread_stack_size - 1), a mask which finds the base of the fixed-size cthreads stack; and __hurd_threadvar_stack_offset to a small offset that skips the data cthreads itself maintains at the base of each thread's stack. In the single-threaded case, __hurd_threadvar_stack_mask is zero, so the stack pointer is ignored; and __hurd_threadvar_stack_offset gives the address of a small allocated region which contains the variables for the single thread. *//* A special case must always be made for the signal thread. Even when there is only one user thread and an allocated region can be used for the user thread's variables, the signal thread needs to have its own location for per-thread variables. The variables __hurd_sigthread_stack_base and __hurd_sigthread_stack_end define the bounds of the stack used by the signal thread, so that thread can always be specifically identified. *//* At the location described by the two variables above, there are __hurd_threadvar_max `unsigned long int's of per-thread data. */
#ifndef_ASM_GENERIC_ERRNO_BASE_H#define_ASM_GENERIC_ERRNO_BASE_H#defineEPERM1 /* Operation not permitted */#defineENOENT2 /* No such file or directory */#defineESRCH3 /* No such process */#defineEINTR4 /* Interrupted system call */#defineEIO5 /* I/O error */#defineENXIO6 /* No such device or address */#defineE2BIG7 /* Argument list too long */#defineENOEXEC8 /* Exec format error */#defineEBADF9 /* Bad file number */#defineECHILD10 /* No child processes */#defineEAGAIN11 /* Try again */#defineENOMEM12 /* Out of memory */#defineEACCES13 /* Permission denied */#defineEFAULT14 /* Bad address */#defineENOTBLK15 /* Block device required */#defineEBUSY16 /* Device or resource busy */#defineEEXIST17 /* File exists */#defineEXDEV18 /* Cross-device link */#defineENODEV19 /* No such device */#defineENOTDIR20 /* Not a directory */#defineEISDIR21 /* Is a directory */#defineEINVAL22 /* Invalid argument */#defineENFILE23 /* File table overflow */#defineEMFILE24 /* Too many open files */#defineENOTTY25 /* Not a typewriter */#defineETXTBSY26 /* Text file busy */#defineEFBIG27 /* File too large */#defineENOSPC28 /* No space left on device */#defineESPIPE29 /* Illegal seek */#defineEROFS30 /* Read-only file system */#defineEMLINK31 /* Too many links */#defineEPIPE32 /* Broken pipe */#defineEDOM33 /* Math argument out of domain of func */#defineERANGE34 /* Math result not representable */#endif
#ifndef_ASM_GENERIC_ERRNO_H#define_ASM_GENERIC_ERRNO_H#include<asm-generic/errno-base.h>#defineEDEADLK35 /* Resource deadlock would occur */#defineENAMETOOLONG36 /* File name too long */#defineENOLCK37 /* No record locks available */#defineENOSYS38 /* Function not implemented */#defineENOTEMPTY39 /* Directory not empty */#defineELOOP40 /* Too many symbolic links encountered */#defineEWOULDBLOCK EAGAIN /* Operation would block */#defineENOMSG42 /* No message of desired type */#defineEIDRM43 /* Identifier removed */#defineECHRNG44 /* Channel number out of range */#defineEL2NSYNC45 /* Level 2 not synchronized */#defineEL3HLT46 /* Level 3 halted */#defineEL3RST47 /* Level 3 reset */#defineELNRNG48 /* Link number out of range */#defineEUNATCH49 /* Protocol driver not attached */#defineENOCSI50 /* No CSI structure available */#defineEL2HLT51 /* Level 2 halted */#defineEBADE52 /* Invalid exchange */#defineEBADR53 /* Invalid request descriptor */#defineEXFULL54 /* Exchange full */#defineENOANO55 /* No anode */#defineEBADRQC56 /* Invalid request code */#defineEBADSLT57 /* Invalid slot */#defineEDEADLOCK EDEADLK#defineEBFONT59 /* Bad font file format */#defineENOSTR60 /* Device not a stream */#defineENODATA61 /* No data available */#defineETIME62 /* Timer expired */#defineENOSR63 /* Out of streams resources */#defineENONET64 /* Machine is not on the network */#defineENOPKG65 /* Package not installed */#defineEREMOTE66 /* Object is remote */#defineENOLINK67 /* Link has been severed */#defineEADV68 /* Advertise error */#defineESRMNT69 /* Srmount error */#defineECOMM70 /* Communication error on send */#defineEPROTO71 /* Protocol error */#defineEMULTIHOP72 /* Multihop attempted */#defineEDOTDOT73 /* RFS specific error */#defineEBADMSG74 /* Not a data message */#defineEOVERFLOW75 /* Value too large for defined data type */#defineENOTUNIQ76 /* Name not unique on network */#defineEBADFD77 /* File descriptor in bad state */#defineEREMCHG78 /* Remote address changed */#defineELIBACC79 /* Can not access a needed shared library */#defineELIBBAD80 /* Accessing a corrupted shared library */#defineELIBSCN81 /* .lib section in a.out corrupted */#defineELIBMAX82 /* Attempting to link in too many shared libraries */#defineELIBEXEC83 /* Cannot exec a shared library directly */#defineEILSEQ84 /* Illegal byte sequence */#defineERESTART85 /* Interrupted system call should be restarted */#defineESTRPIPE86 /* Streams pipe error */#defineEUSERS87 /* Too many users */#defineENOTSOCK88 /* Socket operation on non-socket */#defineEDESTADDRREQ89 /* Destination address required */#defineEMSGSIZE90 /* Message too long */#defineEPROTOTYPE91 /* Protocol wrong type for socket */#defineENOPROTOOPT92 /* Protocol not available */#defineEPROTONOSUPPORT93 /* Protocol not supported */#defineESOCKTNOSUPPORT94 /* Socket type not supported */#defineEOPNOTSUPP95 /* Operation not supported on transport endpoint */#defineEPFNOSUPPORT96 /* Protocol family not supported */#defineEAFNOSUPPORT97 /* Address family not supported by protocol */#defineEADDRINUSE98 /* Address already in use */#defineEADDRNOTAVAIL99 /* Cannot assign requested address */#defineENETDOWN100 /* Network is down */#defineENETUNREACH101 /* Network is unreachable */#defineENETRESET102 /* Network dropped connection because of reset */#defineECONNABORTED103 /* Software caused connection abort */#defineECONNRESET104 /* Connection reset by peer */#defineENOBUFS105 /* No buffer space available */#defineEISCONN106 /* Transport endpoint is already connected */#defineENOTCONN107 /* Transport endpoint is not connected */#defineESHUTDOWN108 /* Cannot send after transport endpoint shutdown */#defineETOOMANYREFS109 /* Too many references: cannot splice */#defineETIMEDOUT110 /* Connection timed out */#defineECONNREFUSED111 /* Connection refused */#defineEHOSTDOWN112 /* Host is down */#defineEHOSTUNREACH113 /* No route to host */#defineEALREADY114 /* Operation already in progress */#defineEINPROGRESS115 /* Operation now in progress */#defineESTALE116 /* Stale file handle */#defineEUCLEAN117 /* Structure needs cleaning */#defineENOTNAM118 /* Not a XENIX named type file */#defineENAVAIL119 /* No XENIX semaphores available */#defineEISNAM120 /* Is a named type file */#defineEREMOTEIO121 /* Remote I/O error */#defineEDQUOT122 /* Quota exceeded */#defineENOMEDIUM123 /* No medium found */#defineEMEDIUMTYPE124 /* Wrong medium type */#defineECANCELED125 /* Operation Canceled */#defineENOKEY126 /* Required key not available */#defineEKEYEXPIRED127 /* Key has expired */#defineEKEYREVOKED128 /* Key has been revoked */#defineEKEYREJECTED129 /* Key was rejected by service *//* for robust mutexes */#defineEOWNERDEAD130 /* Owner died */#defineENOTRECOVERABLE131 /* State not recoverable */#defineERFKILL132 /* Operation not possible due to RF-kill */#defineEHWPOISON133 /* Memory page has hardware error */#endif