]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
strerror: Don't directly depend on pthread
authorMartin Willi <martin@revosec.ch>
Wed, 28 May 2014 10:15:10 +0000 (12:15 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Jun 2014 13:53:00 +0000 (15:53 +0200)
src/libstrongswan/utils/utils.c
src/libstrongswan/utils/utils/strerror.c
src/libstrongswan/utils/utils/strerror.h

index 81eb2acec72ecdd0a49eb5859152980d9eac120a..8ed0a25dd71a4d4468b1607efad33342c7415de2 100644 (file)
@@ -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();
 }
 
 /**
index 95e463f5fe37eada4fe0f0e07e08478e441e1129..d35bbec6881d9860487a90922442cb0cad498df7 100644 (file)
 
 #include <stdlib.h>
 #include <string.h>
-#include <pthread.h>
+
+#include <library.h>
+#include <threading/thread_value.h>
+#include <threading/spinlock.h>
 
 #include "strerror.h"
 
 #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 */
index 2cb76f12e1b609fe7d167ccba633018fc94feb6f..e1b0638422b3c6214ffa2f6b84d58c4556999989 100644 (file)
  */
 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.
  */