Sí, es seguro para subprocesos. En Linux, la variable global errno es específica del subproceso. POSIX requiere que errno sea seguro para subprocesos.
Consulte http://www.unix.org/whitepapers/reentrant.html
En POSIX.1, errno se define como una variable global externa. Pero esta definición es inaceptable en un entorno de subprocesos múltiples, porque su uso puede generar resultados no deterministas. El problema es que dos o más subprocesos pueden encontrar errores, lo que hace que se establezca el mismo errno. En estas circunstancias, un subproceso podría terminar comprobando el errno después de que otro subproceso ya lo haya actualizado.
Para eludir el no determinismo resultante, POSIX.1c redefine serrno como un servicio que puede acceder al número de error por subproceso de la siguiente manera (ISO/IEC 9945:1-1996, §2.4):
Algunas funciones pueden proporcionar el número de error en una variable a la que se accede mediante el símbolo errno. El símbolo errno se define al incluir el encabezado, como lo especifica el estándar C... Para cada subproceso de un proceso, el valor de errno no se verá afectado por las llamadas a funciones o las asignaciones a errno por parte de otros subprocesos.
Consulte también http://linux.die.net/man/3/errno
errno es subproceso local; configurarlo en un subproceso no afecta su valor en ningún otro subproceso.
Sí
Errno ya no es una variable simple, es algo complejo detrás de escena, específicamente para que sea seguro para subprocesos.
Ver $ 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.
Podemos verificar dos veces:
$ cat > test.c
#include <errno.h>
f() { g(errno); }
$ cc -E test.c | grep ^f
f() { g((*__errno_location ())); }
$
En errno.h, esta variable se declara como extern int errno;
Esto es lo que dice el estándar C:
La macro errno
no necesita ser el identificador de un objeto. Podría expandirse a un valor l modificable resultante de una llamada de función (por ejemplo, *errno()
).
Generalmente, errno
es una macro que llama a una función que devuelve la dirección del número de error para el hilo actual, luego lo elimina.
Esto es lo que tengo en Linux, en /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
Al final, genera este tipo de código:
> 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