Is errno thread-safe?
Solution 1
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.
Solution 2
Yes
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 ())); }
$
Solution 3
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
Solution 4
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;
}
Solution 5
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.
Related videos on Youtube
Comments
-
Vinit Dhatrak about 4 years
In
errno.h
, this variable is declared asextern int errno;
so my question is, is it safe to checkerrno
value after some calls or use perror() in multi-threaded code. Is this a thread safe variable? If not, then whats the alternative ?I am using linux with gcc on x86 architecture.
-
jww almost 6 yearsPossible duplicate of Is there a way to use errno safely in a multi-threaded application?
-
-
Paul Tomblin over 14 yearsReally? When did they do that? When I was doing C programming, trusting errno was a big problem.
-
Vinit Dhatrak over 14 yearsok but in errno.h file, its still simple extern int variable. I am confused.
-
Charles Salvia over 14 years@vinit: errno is actually defined in bits/errno.h. Read the comments in the include file. It says: "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."
-
Vinit Dhatrak over 14 yearsCool, so how can I declare that macro instead of a variable ?
-
Charles Salvia over 14 years@vinit, it's already declared for you. You don't need to do anything. The
extern int errno
variable declaration is wrapped in an#ifndef errno
condition, which will be false because errno is already defined as a macro in bits/errno.h. -
Vinit Dhatrak over 14 yearsI mean is it some compile time option or I will have to declare it in my source code?
-
Charles Salvia over 14 yearsIf you are using Linux 2.6, you don't need to do anything. Just start programming. :-)
-
Vinit Dhatrak over 14 years@Timo, Yeah u r right, please refer to discussion on other answer and lets know if anything is missing.
-
Vinit Dhatrak over 14 yearshmmm .. but errno macro is defined only if
defined _LIBC_REENTRANT
is true. So I guess, when we compile code withlpthread
, only then this macro is getting enabled. Correct me if I am wrong here. -
Vinit Dhatrak over 14 yearsI guess you dont have to compile code explicitly with
-D_REENTRANT
. Please refer to discussion on other answer for same question. -
Jonathan Leffler over 14 years@Vinit: it depends on your platform - on Linux, you may be correct; on Solaris, you would be correct only if you have set _POSIX_C_SOURCE to 199506 or a later version - probably by using
-D_XOPEN_SOURCE=500
or-D_XOPEN_SOURCE=600
. Not everyone bothers to ensure that the POSIX environment is specified - and then-D_REENTRANT
can save your bacon. But you still have to be careful - on each platform - to ensure you get the desired behaviour. -
nos over 12 years@vinit dhatrak There should be
# if !defined _LIBC || defined _LIBC_REENTRANT
, _LIBC is not defined when compiling normal programs. Anyway, run echo#include <errno.h>' | gcc -E -dM -xc -
and look at the difference with and without -pthread. errno is#define errno (*__errno_location ())
in both cases. -
Exectron almost 11 yearsforbidden→forgotten I presume. Can you provide a reference for this system call save/restore detail?
-
marcmagransdeabril almost 11 yearsHi Craig, thanks for the info about the typo, now is corrected. Regarding the other issue, I am not sure if I understand correctly what you are asking for. Whatever call that modifies errno in the signal handler could interfere with the errno being used by the same thread that was interrupted (e.g. using strtol inside sig_alarm). right?
-
Deduplicator almost 10 yearsConsider adding an extract from the C11 standard (not earlier),
7.5 Errors <errno.h>
: It's guaranteed thread-safe there too. -
Cloud over 9 yearsIs there a piece of documentation that indicates what standard (ie: C99, ANSI, etc) or at least which compilers (ie: GCC version and onward) that support this feature, and whether or not it is a default? Thank you.
-
Jonathan Leffler over 9 yearsYou can look at the C11 standard, or at POSIX 2008 (2013) for errno. The C11 standard says: ... and
errno
which expands to a modifiable lvalue (201) that has typeint
and thread local storage duration, the value of which is set to a positive error number by several library functions. If a macro definition is suppressed in order to access an actual object, or a program defines an identifier with the nameerrno
, the behavior is undefined. [...continued...] -
Jonathan Leffler over 9 years[...continuation...] Footnote 201 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()
). The main text continues: The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function. POSIX uses the C99 standard which did not recognize threads. [...also continued...] -
Jonathan Leffler over 9 years[...and again...] So, the standards say nothing about needing
-D_REENTRANT
, but POSIX 2008 requires#define _POSIX_C_SOURCE 200809L
before the first system#include
. If you don't do that, or your system does not support POSIX 2008 but an older version, you have to adjust things accordingly. And, occasionally, you have to resort to per-platform tweaks to get the required result. -
Bayou about 4 yearsAlthough looking it up in a man page (or on SO) is faster, I like you've made time to verify it. +1.
-
user786 almost 3 yearsHow to change this to keep errno global shared for all threads. Is it possible. If I like to do changes in kernel do implement system call and dig little bit deeper. May be keep something like errno can u please tell? Is it result from some interrupt in linux
-
user786 almost 3 yearsI like mutex on shared errno or semaphore