Question

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?

Était-ce utile?

La solution

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top