1

I'm trying to understand how glibc initializes errno without the preprocessor substituting the errno symbol.

I first tried to implement a simple version myself based on csu/errno-loc.c and csu/errno.c:

myerrno.h

#ifndef MYERRNO_H
#define MYERRNO_H

extern int *myerrno_location(void);
#define myerrno (*myerrno_location())

#endif

myerrno.c

#include "myerrno.h"

static int myerrno = 0;

int *myerrno_location(void){
    return &myerrno;
}

However, when I try to compile I receive the following error messages:

myerrno.c:3:1: error: function ‘myerrno_location’ is initialized like a variable
myerrno.c:3:12: error: static declaration of ‘myerrno_location’ follows non-static declaration
myerrno.h:4:13: note: previous declaration of ‘myerrno_location’ was here

I can tell that the preprocessor is substituting (*myerrno_location(void)) when it encounters myerrno on line 3 -- and naturally this is expected behavior.

I don't understand why this isn't a problem for glibc. How do thread-safe implementations of errno get around this preprocessor substitution issue without renaming the static errno variable?

Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114
  • is this thread helpful ? http://stackoverflow.com/questions/1694164/is-errno-thread-safe – DRC Aug 02 '13 at 21:06
  • In threaded code, there isn't a single location for an `errno` variable; there is one variable per thread, and the function hidden behind the macro is responsible for returning a pointer to the relevant thread-specific variable. – Jonathan Leffler Aug 02 '13 at 21:13
  • @JonathanLeffler Are static variables are shared between threads? – Vilhelm Gray Aug 02 '13 at 21:26
  • 1
    Yes (static variables in general are shared between threads). But in a threaded environment, the memory location designated by `errno` is no longer (simply) a static variable; it becomes a thread-local variable — each thread is given its own memory location which 'is' that thread's '`errno`'. – Jonathan Leffler Aug 02 '13 at 21:30
  • @JonathanLeffler I can't find a reference to this in the C99 standard -- unfortunately, I suspect the C99 standard makes no guarantees regarding threads. Is this just the de facto behavior of thread libraries? – Vilhelm Gray Aug 05 '13 at 13:16
  • 1
    C99 doesn't know what a thread is — you'd have to refer to POSIX to find the definition. C11 does make promises/requirements (ISO/IEC 9899:2011 §7.5 **Errors ``**: `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._ – Jonathan Leffler Aug 05 '13 at 13:59
  • And footnote 201 is: _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 POSIX definition is at [`errno`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html) and looks compatible with the C11 definition to me. – Jonathan Leffler Aug 05 '13 at 14:01

1 Answers1

3

Fixing your issue is as easy as changing the name of your static variable.

static int myerrno_variable = 0;

int *myerrno_location(void){
    return &myerrno_variable;
}

Notice that your version is still not thread safe since all threads are accessing the same myerrno_variable. A real implementation would return a thread specific memory location. In GCC, there is an extension that provides the __thread storage class. C.11 provides its own version of that called thread_local, but it is only available if thread support is provided by the implementation (which can be checked by looking if __STDC_NO_THREADS__ is defined or not).

static __thread int myerrno_variable_gcc;      /* if using GCC */
static thread_local int my_errno_variable_c11; /* if __STD_NO_THREADS__ isn't defined */

On a POSIX system without a thread local feature, an implementation could use pthread_getspecific() to get a pointer to thread specific data that was allocated for each thread, and set with pthread_setspecific(). See the manual for more information.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • So **glibc** is able to use the same name since it uses the GCC extension `__thread`, while most other implementations simply rename the variable? – Vilhelm Gray Aug 02 '13 at 21:24
  • @VilhelmGray: Most implementations probably have a similar extension, since the feature has been added to the C.11 standard. However, even if it were not the case, POSIX still provides a mechanism to allocate thread specific storage. – jxh Aug 02 '13 at 21:26
  • @VilhelmGray: Oh, **glibc** probably fixes it the same way I told you to fix it. It wouldn't use the same name for the variable and the macro like that. The `__thread` extension allows each thread to have their own private variable that the thread can refer to by the same name. – jxh Aug 02 '13 at 21:36
  • I'm having difficulty understanding the purpose of `__thread` and `thread_local`. If each thread normally has a unique memory location for the same static variable symbol, is the purpose of `__thread` and `thread_local` purely to enable naming a macro and variable the same name? If not, does that mean that in pure C99, there's no standards-guaranteed way for each thread to use a unique memory location for the same variable symbol, without resorting to compiler extensions such as `__thread`? – Vilhelm Gray Aug 05 '13 at 12:47
  • Why do you say each thread normally has a unique memory location for the same static variable symbol? – jxh Aug 05 '13 at 16:38
  • Perhaps I'm misunderstanding Jonathan Leffler's comment on my question (`...in a threaded environment, the memory location designated by errno is no longer (simply) a static variable; it becomes a thread-local variable...`). So normally threads *do* use the same memory locations for static variables, and `errno` is unique due to **glibc's** use of `__thread`? – Vilhelm Gray Aug 05 '13 at 17:14
  • 1
    You misunderstood. @JonathanLeffler was telling you how `errno` specifically behaves in a multi-threaded environment, not how static variables behave in general. The C library implementation has to achieve that behavior. One way is for the implementation to use `__thread` or some equivalent feature. – jxh Aug 05 '13 at 18:55
  • Ah, I see where I went wrong now. To solidify my understanding, is `__thread` then the reason the preprocessor macro doesn't substitute `return &errno` with `return &(*(errno_location))` when defining the `errno_location` function? – Vilhelm Gray Aug 05 '13 at 20:00
  • 2
    If the library implementation declares `errno` with `__thread`, there is no need for a macro. The macro version of `errno` which actually calls a function predates the presence of a `__thread` feature. – jxh Aug 05 '13 at 20:07
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/34874/discussion-between-vilhelm-gray-and-jxh) – Vilhelm Gray Aug 05 '13 at 20:25