From d056668f4f4e0c2286354329b30d73d208d65c5e Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 16 Apr 2014 18:42:36 -0500 Subject: [PATCH] Add autoconf checks for pthreads; fix #340 --- config/m4/find-func-no-libs.m4 | 8 ++++ config/m4/find-func-no-libs2.m4 | 62 ++++++++++++++++++++++++++++ config/m4/find-func.m4 | 9 +++++ config/m4/misc.m4 | 3 ++ configure.ac | 18 +++++++++ jv_alloc.c | 72 ++++++++++++++++++++++++--------- setup.sh | 4 +- 7 files changed, 155 insertions(+), 21 deletions(-) create mode 100644 config/m4/find-func-no-libs.m4 create mode 100644 config/m4/find-func-no-libs2.m4 create mode 100644 config/m4/find-func.m4 create mode 100644 config/m4/misc.m4 diff --git a/config/m4/find-func-no-libs.m4 b/config/m4/find-func-no-libs.m4 new file mode 100644 index 00000000..f47cd6e6 --- /dev/null +++ b/config/m4/find-func-no-libs.m4 @@ -0,0 +1,8 @@ +dnl Shamelessly stolen from Heimdal +dnl +dnl Look for function in any of the specified libraries +dnl + +dnl AC_FIND_FUNC_NO_LIBS(func, libraries, includes, arguments, extra libs, extra args) +AC_DEFUN([AC_FIND_FUNC_NO_LIBS], [ +AC_FIND_FUNC_NO_LIBS2([$1], ["" $2], [$3], [$4], [$5], [$6])]) diff --git a/config/m4/find-func-no-libs2.m4 b/config/m4/find-func-no-libs2.m4 new file mode 100644 index 00000000..ecb61400 --- /dev/null +++ b/config/m4/find-func-no-libs2.m4 @@ -0,0 +1,62 @@ +dnl Shamelessly stolen from Heimdal +dnl +dnl Look for function in any of the specified libraries +dnl + +dnl AC_FIND_FUNC_NO_LIBS2(func, libraries, includes, arguments, extra libs, extra args) +AC_DEFUN([AC_FIND_FUNC_NO_LIBS2], [ + +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(ac_cv_funclib_$1, +[ +if eval "test \"\$ac_cv_func_$1\" != yes" ; then + ac_save_LIBS="$LIBS" + for ac_lib in $2; do + case "$ac_lib" in + "") ;; + yes) ac_lib="" ;; + no) continue ;; + -l*) ;; + *) ac_lib="-l$ac_lib" ;; + esac + LIBS="$6 $ac_lib $5 $ac_save_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[$3]],[[$1($4)]])],[eval "if test -n \"$ac_lib\";then ac_cv_funclib_$1=$ac_lib; else ac_cv_funclib_$1=yes; fi";break]) + done + eval "ac_cv_funclib_$1=\${ac_cv_funclib_$1-no}" + LIBS="$ac_save_LIBS" +fi +]) + +eval "ac_res=\$ac_cv_funclib_$1" + +if false; then + AC_CHECK_FUNCS($1) +dnl AC_CHECK_LIBS($2, foo) +fi +# $1 +eval "ac_tr_func=HAVE_[]upcase($1)" +eval "ac_tr_lib=HAVE_LIB[]upcase($ac_res | sed -e 's/-l//')" +eval "LIB_$1=$ac_res" + +case "$ac_res" in + yes) + eval "ac_cv_func_$1=yes" + eval "LIB_$1=" + AC_DEFINE_UNQUOTED($ac_tr_func) + AC_MSG_RESULT([yes]) + ;; + no) + eval "ac_cv_func_$1=no" + eval "LIB_$1=" + AC_MSG_RESULT([no]) + ;; + *) + eval "ac_cv_func_$1=yes" + eval "ac_cv_lib_`echo "$ac_res" | sed 's/-l//'`=yes" + AC_DEFINE_UNQUOTED($ac_tr_func) + AC_DEFINE_UNQUOTED($ac_tr_lib) + AC_MSG_RESULT([yes, in $ac_res]) + ;; +esac +AC_SUBST(LIB_$1) +]) diff --git a/config/m4/find-func.m4 b/config/m4/find-func.m4 new file mode 100644 index 00000000..a4b0290f --- /dev/null +++ b/config/m4/find-func.m4 @@ -0,0 +1,9 @@ +dnl Shamelessly stolen from Heimdal +dnl +dnl AC_FIND_FUNC(func, libraries, includes, arguments) +AC_DEFUN([AC_FIND_FUNC], [ +AC_FIND_FUNC_NO_LIBS([$1], [$2], [$3], [$4]) +if test -n "$LIB_$1"; then + LIBS="$LIB_$1 $LIBS" +fi +]) diff --git a/config/m4/misc.m4 b/config/m4/misc.m4 new file mode 100644 index 00000000..3dd16bd9 --- /dev/null +++ b/config/m4/misc.m4 @@ -0,0 +1,3 @@ + +dnl Shamelessly stolen from Heimdal +AC_DEFUN([upcase],[`echo $1 | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`])dnl diff --git a/configure.ac b/configure.ac index 41b6e504..d3028f60 100644 --- a/configure.ac +++ b/configure.ac @@ -78,6 +78,24 @@ EOF ]) AM_CONDITIONAL([ENABLE_DOCS], [test "x$enable_docs" != xno]) + +AC_FIND_FUNC([pthread_key_create], [pthread], [#include ], [NULL, NULL]) +AC_FIND_FUNC([pthread_once], [pthread], [#include ], [NULL, NULL]) +AC_FIND_FUNC([atexit], [pthread], [#include ], [NULL]) + +dnl Thread local storage +have___thread=no +AC_MSG_CHECKING(for thread-local storage) +AC_LINK_IFELSE([AC_LANG_SOURCE([ +static __thread int x ; +int main () { x = 123; return x; } +])], have___thread=yes) +if test $have___thread = yes; then + AC_DEFINE([HAVE___THREAD],1,[Define to 1 if the system supports __thread]) +fi +AC_MSG_RESULT($have___thread) + + AC_SUBST([BUNDLER], ["$bundle_cmd"]) AC_CONFIG_MACRO_DIR([config/m4]) diff --git a/jv_alloc.c b/jv_alloc.c index 03e9a7ce..50ca7acf 100644 --- a/jv_alloc.c +++ b/jv_alloc.c @@ -7,13 +7,27 @@ struct nomem_handler { void *data; }; -#ifndef USE_PTHREAD_KEY -#ifdef _MSC_VER -static __declspec(thread) struct nomem_handler nomem_handler; -#else -static __thread struct nomem_handler nomem_handler; -#endif +#if !defined(HAVE_PTHREAD_KEY_CREATE) || \ + !defined(HAVE_PTHREAD_ONCE) || \ + !defined(HAVE_ATEXIT) +/* Try thread-local storage? */ + +#ifdef _MSC_VER +/* Visual C++: yes */ +static __declspec(thread) struct nomem_handler nomem_handler; +#define USE_TLS +#else +#ifdef HAVE___THREAD +/* GCC and friends: yes */ +static __thread struct nomem_handler nomem_handler; +#define USE_TLS +#endif /* HAVE___THREAD */ +#endif /* _MSC_VER */ + +#endif /* !HAVE_PTHREAD_KEY_CREATE */ + +#ifdef USE_TLS void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { nomem_handler.handler = handler; } @@ -25,44 +39,60 @@ static void memory_exhausted() { fprintf(stderr, "error: cannot allocate memory\n"); abort(); } -#else +#else /* USE_TLS */ + #ifdef HAVE_PTHREAD_KEY_CREATE #include pthread_key_t nomem_handler_key; pthread_once_t mem_once = PTHREAD_ONCE_INIT; +static void tsd_fini(void) { + struct nomem_handler *nomem_handler; + nomem_handler = pthread_getspecific(nomem_handler_key); + if (nomem_handler) { + (void) pthread_setspecific(nomem_handler_key, NULL); + free(nomem_handler); + } +} + static void tsd_init(void) { if (pthread_key_create(&nomem_handler_key, NULL) != 0) { fprintf(stderr, "error: cannot create thread specific key"); abort(); } + if (atexit(tsd_fini) != 0) { + fprintf(stderr, "error: cannot set an exit handler"); + abort(); + } + struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler)); + if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) { + fprintf(stderr, "error: cannot set thread specific data"); + abort(); + } } void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { pthread_once(&mem_once, tsd_init); // cannot fail - struct nomem_handler *nomem_handler = calloc(1, sizeof (nomem_handler)); + struct nomem_handler *nomem_handler; + + nomem_handler = pthread_getspecific(nomem_handler_key); if (nomem_handler == NULL) { handler(data); fprintf(stderr, "error: cannot allocate memory\n"); abort(); } - nomem_handler.handler = handler; - nomem_handler.data = data; - if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) { - handler(data); - fprintf(stderr, "error: cannot set thread specific data"); - abort(); - } + nomem_handler->handler = handler; + nomem_handler->data = data; } static void memory_exhausted() { - jv_nomem_handler_f handler; + struct nomem_handler *nomem_handler; pthread_once(&mem_once, tsd_init); - handler = pthread_getspecific(nomem_handler_key); - if (handler) - handler(); // Maybe handler() will longjmp() to safety + nomem_handler = pthread_getspecific(nomem_handler_key); + if (nomem_handler) + nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety // Or not fprintf(stderr, "error: cannot allocate memory\n"); abort(); @@ -70,6 +100,8 @@ static void memory_exhausted() { #else +/* No thread-local storage of any kind that we know how to handle */ + static struct nomem_handler nomem_handler; void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { nomem_handler.handler = handler; @@ -82,7 +114,7 @@ static void memory_exhausted() { } #endif /* HAVE_PTHREAD_KEY_CREATE */ -#endif /* !USE_PTHREAD_KEY */ +#endif /* USE_TLS */ void* jv_mem_alloc(size_t sz) { diff --git a/setup.sh b/setup.sh index 63dc899d..c458f120 100755 --- a/setup.sh +++ b/setup.sh @@ -9,7 +9,9 @@ if [ "clean" == "$1" ]; then make distclean || echo "continuing..." - rm -rf tmp autom4te.cache config + find config/m4 -type f \( -name libtool\* -o -name lt\* \) | xargs rm -f + find config -name m4 -prune -o -type f -print | xargs rm -f + rm -rf tmp autom4te.cache rm -f INSTALL Makefile.in aclocal.m4 configure config.h.in ChangeLog rm -f jv_utf8_tables.gen.h lexer.c lexer.h parser.c parser.h elif [ "superclean" == "$1" ]; then