Although MSVC is definitely not POSIX compliant, errno is implemented in the MSVC runtime (at least as of MSVC2008) in a threadsafe manner. Although the documentation states that it is extern int errno it's actually implemented as a #define to a function which allows thread-safety to be imposed.
The main reason for using errno is to give more information about the error condition. This is especially useful in situations where most (or even all) possible return values of a function are actually valid return values. Consider the fopen() function, which returns a pointer to a FILE .
It defines macros for reporting and retrieving error conditions using the symbol errno (short for "error number"). errno acts like an integer variable. A value (the error number) is stored in errno by certain library functions when they detect errors. At program startup, the value stored is zero.
To detect an error, an application must set errno to 0 before calling the function and check whether it is nonzero after the call. Affected functions include strcoll() , strxfrm() , strerror() , wcscoll() , wcsxfrm() , and fwide() . The C Standard allows these functions to set errno to a nonzero value on success.
Yes, it is thread safe. On Linux, the global errno variable is thread-specific. POSIX requires that errno be threadsafe.
See http://www.unix.org/whitepapers/reentrant.html
In POSIX.1, errno is defined as an external global variable. But this definition is unacceptable in a multithreaded environment, because its use can result in nondeterministic results. The problem is that two or more threads can encounter errors, all causing the same errno to be set. Under these circumstances, a thread might end up checking errno after it has already been updated by another thread.
To circumvent the resulting nondeterminism, POSIX.1c redefines errno as a service that can access the per-thread error number as follows (ISO/IEC 9945:1-1996, §2.4):
Some functions may provide the error number in a variable accessed through the symbol errno. The symbol errno is defined by including the header , as specified by the C Standard ... For each thread of a process, the value of errno shall not be affected by function calls or assignments to errno by other threads.
Also see http://linux.die.net/man/3/errno
errno is thread-local; setting it in one thread does not affect its value in any other thread.
Errno isn't a simple variable anymore, it's something complex behind the scenes, specifically for it to be thread-safe.
See $ man 3 errno
:
ERRNO(3) Linux Programmer’s Manual ERRNO(3)
NAME
errno - number of last error
SYNOPSIS
#include <errno.h>
DESCRIPTION
...
errno is defined by the ISO C standard to be a modifiable lvalue of
type int, and must not be explicitly declared; errno may be a macro.
errno is thread-local; setting it in one thread does not affect its
value in any other thread.
We can double-check:
$ cat > test.c
#include <errno.h>
f() { g(errno); }
$ cc -E test.c | grep ^f
f() { g((*__errno_location ())); }
$
In errno.h, this variable is declared as extern int errno;
Here is what the C standard says:
The macro
errno
need not be the identifier of an object. It might expand to a modifiable lvalue resulting from a function call (for example,*errno()
).
Generally, errno
is a macro which calls a function returning the address of the error number for the current thread, then dereferences it.
Here is what I have on Linux, in /usr/include/bits/errno.h:
/* 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
In the end, it generates this kind of code:
> cat essai.c
#include <errno.h>
int
main(void)
{
errno = 0;
return 0;
}
> gcc -c -Wall -Wextra -pedantic essai.c
> objdump -d -M intel essai.o
essai.o: file format elf32-i386
Disassembly of section .text:
00000000 <main>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 e4 f0 and esp,0xfffffff0
6: e8 fc ff ff ff call 7 <main+0x7> ; get address of errno in EAX
b: c7 00 00 00 00 00 mov DWORD PTR [eax],0x0 ; store 0 in errno
11: b8 00 00 00 00 mov eax,0x0
16: 89 ec mov esp,ebp
18: 5d pop ebp
19: c3 ret
yes, as it is explained in the errno man page and the other replies, errno is a thread local variable.
However, there is a silly detail which could be easily forgotten. Programs should save and restore the errno on any signal handler executing a system call. This is because the signal will be handled by one of the process threads which could overwrite its value.
Therefore, the signal handlers should save and restore errno. Something like:
void sig_alarm(int signo)
{
int errno_save;
errno_save = errno;
//whatever with a system call
errno = errno_save;
}
This is from <sys/errno.h>
on my Mac:
#include <sys/cdefs.h>
__BEGIN_DECLS
extern int * __error(void);
#define errno (*__error())
__END_DECLS
So errno
is now a function __error()
. The function is implemented so as to be thread-safe.
On many Unix systems, compiling with -D_REENTRANT
ensures that errno
is thread-safe.
For example:
#if defined(_REENTRANT) || _POSIX_C_SOURCE - 0 >= 199506L
extern int *___errno();
#define errno (*(___errno()))
#else
extern int errno;
/* ANSI C++ requires that errno be a macro */
#if __cplusplus >= 199711L
#define errno errno
#endif
#endif /* defined(_REENTRANT) */
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With