I. Origins of errno
In C Programming, errno is an indispensable variable, especially in network programming. If you have never used errno, it only means that your program is not robust enough. Of course, if you are using getlasterror () on the Win32 platform, the effect is the same.
Why is errno used? I personally think this is a helpless move in the system library design. It is more of a skill than an architectural need. We can observe the function structure and find that there is only one return value for the function parameter. This return value generally carries an error message, such as a negative number indicating an error, and a positive number indicating a correct return value, such as the Recv function. But for some functions that return pointers, such as char * get_str (); this method is obviously useless. Null can indicate an error, but there is no way to make any error. Therefore, errno was born. The global variable errno can store the cause of the Error. When an error occurs, the returned value of the function can be an invalid value to indicate the error.
Ii. thread security of errno
Errno is a global variable, but in a multi-threaded environment, it becomes terrible. When you call a function, you find that the function has an error, but when you use the error cause, it turns into another thread error prompt. Think of it as a terrible thing.
Setting errno as a local variable in the thread is a good idea. In fact, this is what GCC does. It ensures that the cause of errors between threads will not be changed. When you execute a series of processes in a thread serially, The errno is still correct.
See the definition of bits/errno. h:
# Ifndef _ assembler __
/* Function to get address of global 'errno' variable .*/
Extern int * _ errno_location (void) _ Throw _ attribute _ (_ const __));
# If! Defined _ libc | defined _ libc_reentrant
/* When using threads, errno is a per-thread value .*/
# Define errno (* _ errno_location ())
# Endif
# Endif /*! _ Cycler __*/
Errno. H is defined as follows:
/* Declare the 'errno' variable, unless it's defined as a macro
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 .*/
# Ifndef errno
Extern int errno;
# Endif
Obviously, errno is actually used to obtain the value instead of an integer value. This integer is thread-safe.
Iii. Implementation of errno
Static pthread_key_t key;
Static pthread_once_t key_once = pthread_once_init;
Static void make_key ()
{
(Void) pthread_key_create (& Key, null );
}
Int * _ errno ()
{
Int * PTR;
(Void) pthread_once (& key_once, make_key );
If (PTR = pthread_getspecific (key) = NULL)
{
PTR = malloc (sizeof (INT ));
(Void) pthread_setspecific (Key, PTR );
}
Return PTR;
}
Iv. Application of errno
Errno is widely used in libraries, but there are actually more error codes. We need to add more error codes in our system. One way is to use errno directly, and the other way is to define your own user_errno.
If errno is used, strerror may not be resolved, which must be resolved by yourself. However, errno uses thread variables for reference.