Thread-safe wrapper around strerror(3)/strerror_r(3) added

This commit is contained in:
Tobias Brunner 2012-06-27 18:42:25 +02:00
parent 0f018a7324
commit 2a59527659
3 changed files with 93 additions and 4 deletions

View File

@ -301,6 +301,7 @@ dnl ===========================================
AC_HEADER_STDBOOL
AC_FUNC_ALLOCA
AC_FUNC_STRERROR_R
dnl libraries needed on some platforms but not on others
dnl ====================================================

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Tobias Brunner
* Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@ -25,6 +25,7 @@
#include <limits.h>
#include <dirent.h>
#include <time.h>
#include <pthread.h>
#include "enum.h"
#include "debug.h"
@ -194,6 +195,83 @@ bool mkdir_p(const char *path, mode_t mode)
return TRUE;
}
/**
* The size of the thread-specific error buffer
*/
#define STRERROR_BUF_LEN 256
/**
* Key to store thread-specific error buffer
*/
static pthread_key_t strerror_buf_key;
/**
* Only initialize the key above once
*/
static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT;
/**
* Create the key used for the thread-specific error buffer
*/
static void create_strerror_buf_key()
{
pthread_key_create(&strerror_buf_key, free);
}
/**
* Retrieve the error buffer assigned to the current thread (or create it)
*/
static inline char *get_strerror_buf()
{
char *buf;
pthread_once(&strerror_buf_key_once, create_strerror_buf_key);
buf = pthread_getspecific(strerror_buf_key);
if (!buf)
{
buf = malloc(STRERROR_BUF_LEN);
pthread_setspecific(strerror_buf_key, buf);
}
return buf;
}
#ifdef HAVE_STRERROR_R
/*
* Described in header.
*/
const char *safe_strerror(int errnum)
{
char *buf = get_strerror_buf(), *msg;
#ifdef STRERROR_R_CHAR_P
/* char* version which may or may not return the original buffer */
msg = strerror_r(errnum, buf, STRERROR_BUF_LEN);
#else
/* int version returns 0 on success */
msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf;
#endif
return msg;
}
#else /* HAVE_STRERROR_R */
/*
* Described in header.
*/
const char *safe_strerror(int errnum)
{
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
char *buf = get_strerror_buf();
/* use a mutex to ensure calling strerror(3) is thread-safe */
pthread_mutex_lock(&mutex);
strncpy(buf, strerror(errnum), STRERROR_BUF_LEN);
pthread_mutex_unlock(&mutex);
buf[STRERROR_BUF_LEN - 1] = '\0';
return buf;
}
#endif /* HAVE_STRERROR_R */
#ifndef HAVE_CLOSEFROM
/**
* Described in header.
@ -315,7 +393,6 @@ void nop()
}
#ifndef HAVE_GCC_ATOMIC_OPERATIONS
#include <pthread.h>
/**
* We use a single mutex for all refcount variables.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2011 Tobias Brunner
* Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@ -410,6 +410,18 @@ char *translate(char *str, const char *from, const char *to);
*/
bool mkdir_p(const char *path, mode_t mode);
/**
* Thread-safe wrapper around strerror and strerror_r.
*
* This is required because the first is not thread-safe (on some platforms)
* and the second uses two different signatures (POSIX/GNU) and is impractical
* to use anyway.
*
* @param errnum error code (i.e. errno)
* @return error message
*/
const char *safe_strerror(int errnum);
#ifndef HAVE_CLOSEFROM
/**
* Close open file descriptors greater than or equal to lowfd.
@ -628,7 +640,6 @@ bool cas_bool(bool *ptr, bool oldval, bool newval);
*/
bool cas_ptr(void **ptr, void *oldval, void *newval);
#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
/**