Is errno thread-safe?

51,157

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.

Share:
51,157

Related videos on Youtube

Vinit Dhatrak
Author by

Vinit Dhatrak

Programmer :)

Updated on February 12, 2020

Comments

  • Vinit Dhatrak
    Vinit Dhatrak about 4 years

    In errno.h, this variable is declared as extern int errno; so my question is, is it safe to check errno 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.

  • Paul Tomblin
    Paul Tomblin over 14 years
    Really? When did they do that? When I was doing C programming, trusting errno was a big problem.
  • Vinit Dhatrak
    Vinit Dhatrak over 14 years
    ok but in errno.h file, its still simple extern int variable. I am confused.
  • Charles Salvia
    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
    Vinit Dhatrak over 14 years
    Cool, so how can I declare that macro instead of a variable ?
  • Charles Salvia
    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
    Vinit Dhatrak over 14 years
    I mean is it some compile time option or I will have to declare it in my source code?
  • Charles Salvia
    Charles Salvia over 14 years
    If you are using Linux 2.6, you don't need to do anything. Just start programming. :-)
  • Vinit Dhatrak
    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
    Vinit Dhatrak over 14 years
    hmmm .. but errno macro is defined only if defined _LIBC_REENTRANT is true. So I guess, when we compile code with lpthread, only then this macro is getting enabled. Correct me if I am wrong here.
  • Vinit Dhatrak
    Vinit Dhatrak over 14 years
    I guess you dont have to compile code explicitly with -D_REENTRANT. Please refer to discussion on other answer for same question.
  • Jonathan Leffler
    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
    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
    Exectron almost 11 years
    forbidden→forgotten I presume. Can you provide a reference for this system call save/restore detail?
  • marcmagransdeabril
    marcmagransdeabril almost 11 years
    Hi 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
    Deduplicator almost 10 years
    Consider adding an extract from the C11 standard (not earlier), 7.5 Errors <errno.h>: It's guaranteed thread-safe there too.
  • Cloud
    Cloud over 9 years
    Is 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
    Jonathan Leffler over 9 years
    You 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 type int 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 name errno, the behavior is undefined. [...continued...]
  • Jonathan Leffler
    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
    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
    Bayou about 4 years
    Although looking it up in a man page (or on SO) is faster, I like you've made time to verify it. +1.
  • user786
    user786 almost 3 years
    How 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
    user786 almost 3 years
    I like mutex on shared errno or semaphore