aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2014-05-28 12:15:10 +0200
committerMartin Willi <martin@revosec.ch>2014-06-04 15:53:00 +0200
commiteb94f585954bf9f1ea0abc16e8d1413aaf265ac4 (patch)
tree78a651985fe7a1959afa72dfd137fdd10e906e5e
parent4189cd2f03d963c8ed31a21050201b2731eda4c5 (diff)
downloadstrongswan-eb94f585954bf9f1ea0abc16e8d1413aaf265ac4.tar.bz2
strongswan-eb94f585954bf9f1ea0abc16e8d1413aaf265ac4.tar.xz
strerror: Don't directly depend on pthread
-rw-r--r--src/libstrongswan/utils/utils.c2
-rw-r--r--src/libstrongswan/utils/utils/strerror.c122
-rw-r--r--src/libstrongswan/utils/utils/strerror.h10
3 files changed, 98 insertions, 36 deletions
diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c
index 81eb2acec..8ed0a25dd 100644
--- a/src/libstrongswan/utils/utils.c
+++ b/src/libstrongswan/utils/utils.c
@@ -55,6 +55,7 @@ void utils_init()
#ifdef WIN32
windows_init();
#endif /* WIN32 */
+ strerror_init();
}
/**
@@ -65,6 +66,7 @@ void utils_deinit()
#ifdef WIN32
windows_deinit();
#endif /* WIN32 */
+ strerror_deinit();
}
/**
diff --git a/src/libstrongswan/utils/utils/strerror.c b/src/libstrongswan/utils/utils/strerror.c
index 95e463f5f..d35bbec68 100644
--- a/src/libstrongswan/utils/utils/strerror.c
+++ b/src/libstrongswan/utils/utils/strerror.c
@@ -15,7 +15,10 @@
#include <stdlib.h>
#include <string.h>
-#include <pthread.h>
+
+#include <library.h>
+#include <threading/thread_value.h>
+#include <threading/spinlock.h>
#include "strerror.h"
@@ -25,22 +28,16 @@
#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
+ * Thread specific strerror buffer, as char*
*/
-static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT;
+static thread_value_t *strerror_buf;
+#ifndef HAVE_STRERROR_R
/**
- * Create the key used for the thread-specific error buffer
+ * Lock to access strerror() safely
*/
-static void create_strerror_buf_key()
-{
- pthread_key_create(&strerror_buf_key, free);
-}
+static spinlock_t *strerror_lock;
+#endif /* HAVE_STRERROR_R */
/**
* Retrieve the error buffer assigned to the current thread (or create it)
@@ -48,50 +45,103 @@ static void create_strerror_buf_key()
static inline char *get_strerror_buf()
{
char *buf;
+ bool old = FALSE;
- pthread_once(&strerror_buf_key_once, create_strerror_buf_key);
- buf = pthread_getspecific(strerror_buf_key);
+ if (!strerror_buf)
+ {
+ return NULL;
+ }
+
+ buf = strerror_buf->get(strerror_buf);
if (!buf)
{
+ if (lib->leak_detective)
+ {
+ old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
+ }
buf = malloc(STRERROR_BUF_LEN);
- pthread_setspecific(strerror_buf_key, buf);
+ strerror_buf->set(strerror_buf, buf);
+ if (lib->leak_detective)
+ {
+ lib->leak_detective->set_state(lib->leak_detective, old);
+ }
}
return buf;
}
-#ifdef HAVE_STRERROR_R
+/**
+ * Use real strerror() below
+ */
+#undef strerror
+
/*
* Described in header.
*/
const char *strerror_safe(int errnum)
{
- char *buf = get_strerror_buf(), *msg;
+ char *buf, *msg;
-#ifdef STRERROR_R_CHAR_P
+ buf = get_strerror_buf();
+ if (!buf)
+ {
+ /* library not initialized? fallback */
+ return strerror(errnum);
+ }
+#ifdef HAVE_STRERROR_R
+# 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
+# else
/* int version returns 0 on success */
msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf;
-#endif
+# endif
+#else /* HAVE_STRERROR_R */
+ /* use a lock to ensure calling strerror(3) is thread-safe */
+ strerror_lock->lock(strerror_lock);
+ msg = strncpy(buf, strerror(errnum), STRERROR_BUF_LEN);
+ strerror_lock->unlock(strerror_lock);
+ buf[STRERROR_BUF_LEN - 1] = '\0';
+#endif /* HAVE_STRERROR_R */
return msg;
}
-#else /* HAVE_STRERROR_R */
-/* we actually wan't to call strerror(3) below */
-#undef strerror
-/*
- * Described in header.
+
+/**
+ * free() with disabled leak detective
*/
-const char *strerror_safe(int errnum)
+static void free_no_ld(void *buf)
{
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- char *buf = get_strerror_buf();
+ bool old = FALSE;
- /* 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;
+ if (lib->leak_detective)
+ {
+ old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
+ }
+ free(buf);
+ if (lib->leak_detective)
+ {
+ lib->leak_detective->set_state(lib->leak_detective, old);
+ }
+}
+
+/**
+ * See header
+ */
+void strerror_init()
+{
+ strerror_buf = thread_value_create(free_no_ld);
+#ifndef HAVE_STRERROR_R
+ strerror_lock = spinlock_create();
+#endif
+}
+
+/**
+ * See header
+ */
+void strerror_deinit()
+{
+ strerror_buf->destroy(strerror_buf);
+ strerror_buf = NULL;
+#ifndef HAVE_STRERROR_R
+ strerror_lock->destroy(strerror_lock);
+#endif
}
-#endif /* HAVE_STRERROR_R */
diff --git a/src/libstrongswan/utils/utils/strerror.h b/src/libstrongswan/utils/utils/strerror.h
index 2cb76f12e..e1b063842 100644
--- a/src/libstrongswan/utils/utils/strerror.h
+++ b/src/libstrongswan/utils/utils/strerror.h
@@ -33,6 +33,16 @@
const char *strerror_safe(int errnum);
/**
+ * Initialize strerror_safe()
+ */
+void strerror_init();
+
+/**
+ * Deinitialize strerror_safe()
+ */
+void strerror_deinit();
+
+/**
* Replace usages of strerror(3) with thread-safe variant.
*/
#define strerror(errnum) strerror_safe(errnum)