ptg10805159
450 Thread Control Chapter 12
extern char **environ;
static void
thread_init(void)
{
pthread_key_create(&key, free);
}
char *
getenv(const char *name)
{
int i, len;
char *envbuf;
pthread_once(&init_done, thread_init);
pthread_mutex_lock(&env_mutex);
envbuf = (char *)pthread_getspecific(key);
if (envbuf == NULL) {
envbuf = malloc(MAXSTRINGSZ);
if (envbuf == NULL) {
pthread_mutex_unlock(&env_mutex);
return(NULL);
}
pthread_setspecific(key, envbuf);
}
len = strlen(name);
for (i = 0; environ[i] != NULL; i++) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == ’=’)) {
strncpy(envbuf, &environ[i][len+1], MAXSTRINGSZ-1);
pthread_mutex_unlock(&env_mutex);
return(envbuf);
}
}
pthread_mutex_unlock(&env_mutex);
return(NULL);
}
Figure 12.13 Athread-safe, compatible version ofgetenv
We usepthread_onceto ensurethat only one key is created for the thread-specific
data we will use. Ifpthread_getspecificreturns a null pointer, we need to allocate
the memory buffer and associate it with the key.Otherwise, we use the memory buffer
returned bypthread_getspecific.For the destructor function, we usefreeto free
the memory previously allocated bymalloc.The destructor function will be called
with the value of the thread-specific data only if the value is non-null.
Note that although this version ofgetenvis thread-safe, it is not async-signal safe.
Even if we made the mutex recursive, we could not make it reentrant with respect to
signal handlers because it callsmalloc,which itself is not async-signal safe.