array: Add fallback for qsort_r using thread-local value
authorTobias Brunner <tobias@strongswan.org>
Mon, 27 Jan 2014 12:41:21 +0000 (13:41 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 12 Feb 2014 13:34:33 +0000 (14:34 +0100)
Cygwin for example does not support qsort_r.

configure.ac
src/libstrongswan/collections/array.c
src/libstrongswan/collections/array.h
src/libstrongswan/library.c

index 649f181..76981e7 100644 (file)
@@ -528,7 +528,7 @@ AC_CHECK_FUNC(
                ])
                CFLAGS="$save_CFLAGS"
        ],
-       [AC_MSG_FAILURE([qsort_r not found])]
+       []
 )
 
 AC_CHECK_FUNCS(prctl mallinfo getpass closefrom getpwnam_r getgrnam_r getpwuid_r)
index ed0d12e..642bbb3 100644 (file)
 
 #include "array.h"
 
+#ifndef HAVE_QSORT_R
+#include <threading/thread_value.h>
+#endif
+
 /**
  * Data is an allocated block, with potentially unused head and tail:
  *
@@ -49,6 +53,11 @@ struct array_t {
        void *data;
 };
 
+#ifndef HAVE_QSORT_R
+       /* store data to replicate qsort_r in thread local storage */
+       static thread_value_t *sort_data;
+#endif
+
 /** maximum number of unused head/tail elements before cleanup */
 #define ARRAY_MAX_UNUSED 32
 
@@ -382,11 +391,17 @@ typedef struct {
 
 #ifdef HAVE_QSORT_R_GNU
 static int compare_elements(const void *a, const void *b, void *arg)
-#else /* HAVE_QSORT_R_BSD */
+#elif  HAVE_QSORT_R_BSD
 static int compare_elements(void *arg, const void *a, const void *b)
+#else /* !HAVE_QSORT_R */
+static int compare_elements(const void *a, const void *b)
 #endif
 {
+#ifdef HAVE_QSORT_R
        sort_data_t *data = (sort_data_t*)arg;
+#else
+       sort_data_t *data = sort_data->get(sort_data);
+#endif
 
        if (data->array->esize)
        {
@@ -412,9 +427,12 @@ void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*),
 #ifdef HAVE_QSORT_R_GNU
                qsort_r(start, array->count, get_size(array, 1), compare_elements,
                                &data);
-#else /* HAVE_QSORT_R_BSD */
+#elif  HAVE_QSORT_R_BSD
                qsort_r(start, array->count, get_size(array, 1), &data,
                                compare_elements);
+#else /* !HAVE_QSORT_R */
+               sort_data->set(sort_data, &data);
+               qsort(start, array->count, get_size(array, 1), compare_elements);
 #endif
        }
 }
@@ -531,3 +549,17 @@ void array_destroy_offset(array_t *array, size_t offset)
        array_invoke_offset(array, offset);
        array_destroy(array);
 }
+
+void arrays_init()
+{
+#ifndef HAVE_QSORT_R
+       sort_data =  thread_value_create(NULL);
+#endif
+}
+
+void arrays_deinit()
+{
+#ifndef HAVE_QSORT_R
+       sort_data->destroy(sort_data);
+#endif
+}
index c6b6fcc..ce702eb 100644 (file)
@@ -251,4 +251,16 @@ void array_destroy_function(array_t *array, array_callback_t cb, void *user);
  */
 void array_destroy_offset(array_t *array, size_t offset);
 
+
+/**
+ * Required on some platforms to initialize thread local value to implement
+ * array_sort().
+ */
+void arrays_init();
+
+/**
+ * Destroys the thread local value if required.
+ */
+void arrays_deinit();
+
 #endif /** ARRAY_H_ @}*/
index 0df0c42..8472c30 100644 (file)
@@ -22,6 +22,7 @@
 #include <threading/thread.h>
 #include <utils/identification.h>
 #include <networking/host.h>
+#include <collections/array.h>
 #include <collections/hashtable.h>
 #include <utils/backtrace.h>
 #include <selectors/traffic_selector.h>
@@ -142,6 +143,7 @@ void library_deinit()
                lib->leak_detective->destroy(lib->leak_detective);
        }
 
+       arrays_deinit();
        threads_deinit();
        backtrace_deinit();
 
@@ -259,6 +261,7 @@ bool library_init(char *settings, const char *namespace)
 
        backtrace_init();
        threads_init();
+       arrays_init();
 
 #ifdef LEAK_DETECTIVE
        lib->leak_detective = leak_detective_create();