array: Add fallback for qsort_r using thread-local value

Cygwin for example does not support qsort_r.
This commit is contained in:
Tobias Brunner 2014-01-27 13:41:21 +01:00
parent 190a278854
commit b3613c49a2
4 changed files with 50 additions and 3 deletions

View 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)

View File

@ -21,6 +21,10 @@
#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
}

View 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_ @}*/

View 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();