views:

917

answers:

6

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.

+8  A: 

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.

Charles Salvia
Really? When did they do that? When I was doing C programming, trusting errno was a big problem.
Paul Tomblin
They changed it with the updated POSIX standard
Charles Salvia
Man, that would have saved a lot of hassle back in my day.
Paul Tomblin
ok but in errno.h file, its still simple extern int variable. I am confused.
vinit dhatrak
@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."
Charles Salvia
Cool, so how can I declare that macro instead of a variable ?
vinit dhatrak
@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.
Charles Salvia
I mean is it some compile time option or I will have to declare it in my source code?
vinit dhatrak
If you are using Linux 2.6, you don't need to do anything. Just start programming. :-)
Charles Salvia
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
I should have collected bets first.
DigitalRoss
+4  A: 

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.


So let's double-check:

$ cat > test.c
#include <errno.h>
f() { g(errno); }
$ cc -E test.c | grep ^f
f() { g((*__errno_location ())); }
$
DigitalRoss
@DigitalRoss thank you for your reply, please have a look at other answer's comments for further discussions.
vinit dhatrak
+2  A: 

I think the answer is "it depends". Thread-safe C runtime libraries usually implement errno as a function call (macro expanding to a function) if you're building threaded code with the correct flags.

Timo Geusch
@Timo, Yeah u r right, please refer to discussion on other answer and lets know if anything is missing.
vinit dhatrak
A: 

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) */
Jonathan Leffler
I guess you dont have to compile code explicitly with `-D_REENTRANT`. Please refer to discussion on other answer for same question.
vinit dhatrak
@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.
Jonathan Leffler
A: 

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 bethread-safe.

vy32
+1  A: 

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
Bastien Léonard