diff options
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | include/private/pthread_support.h | 2 | ||||
-rw-r--r-- | misc.c | 3 | ||||
-rw-r--r-- | pthread_support.c | 53 |
4 files changed, 71 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 45ab6932..ddb24663 100644 --- a/configure.ac +++ b/configure.ac @@ -658,6 +658,19 @@ case "$host" in *) AC_MSG_RESULT(no) ;; esac +dnl Check for specific glibc functions and definitions that we need to for +dnl the glibc 2.19 workaround. +HAVE_LIBC_VERSION_H=no +HAVE_GNU_GET_LIBC_VERSION=no +case "${host}" in + *-linux*) + AC_CHECK_HEADER([gnu/libc-version.h], HAVE_LIBC_VERSION_H=yes) + AC_CHECK_FUNC([gnu_get_libc_version], HAVE_GNU_GET_LIBC_VERSION=yes) + ;; +esac +AC_SUBST(HAVE_LIBC_VERSION_H) +AC_SUBST(HAVE_GNU_GET_LIBC_VERSION) + dnl Include defines that have become de facto standard. dnl ALL_INTERIOR_POINTERS and NO_EXECUTE_PERMISSION can be overridden dnl in the startup code. diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h index 525a9aac..017f1941 100644 --- a/include/private/pthread_support.h +++ b/include/private/pthread_support.h @@ -148,6 +148,8 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread( struct GC_stack_base *sb, void *arg); GC_INNER_PTHRSTART void GC_thread_exit_proc(void *); +GC_INNER void GC_setup_mark_lock(void); + #endif /* GC_PTHREADS && !GC_WIN32_THREADS */ #endif /* GC_PTHREAD_SUPPORT_H */ @@ -888,6 +888,9 @@ GC_API void GC_CALL GC_init(void) /* else */ InitializeCriticalSection (&GC_allocate_ml); } # endif /* GC_WIN32_THREADS */ +# if (defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)) + GC_setup_mark_lock(); +# endif /* GC_PTHREADS */ # if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS) InitializeCriticalSection(&GC_write_cs); # endif diff --git a/pthread_support.c b/pthread_support.c index 0689be45..45ab3513 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -95,6 +95,10 @@ typedef unsigned int sem_t; #endif /* GC_DGUX386_THREADS */ +#ifdef HAVE_LIBC_VERSION_H +# include <gnu/libc-version.h> +#endif + /* Undefine macros used to redirect pthread primitives. */ # undef pthread_create # ifndef GC_NO_PTHREAD_SIGMASK @@ -1979,12 +1983,61 @@ GC_INNER void GC_lock(void) /* defined. */ static pthread_mutex_t mark_mutex = {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}}; +#elif defined(HAVE_GNU_GET_LIBC_VERSION) && defined(HAVE_LIBC_VERSION_H) + static pthread_mutex_t mark_mutex; #else static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER; #endif static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER; +GC_INNER void GC_setup_mark_lock(void) +{ +#if defined(HAVE_GNU_GET_LIBC_VERSION) && defined(HAVE_LIBC_VERSION_H) + pthread_mutexattr_t attr; + char *version_str = NULL; + char *strtok_save; + char *version_part; + char *version_str; + + if (0 != pthread_mutexattr_init(&attr)) { + goto error; + } + + /* + ** Check for version 2.19 or greater. + */ + version_str = strdup(gnu_get_libc_version()); + version_part = strtok_r(version_str, ".", &strtok_save); + if ((NULL != version_part) && (2 <= atoi(version_part))) { + version_part = strtok_r(NULL, ".", &strtok_save); + if ((NULL != version_part) && (19 <= atoi(version_part))) { + /* + * Disable lock elision on this version of glibc. + */ + if (0 != pthread_mutexattr_settype(&attr, + PTHREAD_MUTEX_ERRORCHECK)) + { + goto error; + } + } + } + + if (0 != pthread_mutex_init(&mark_mutex, &attr)) { + goto error; + } + pthread_mutexattr_destroy(&attr); + if (NULL != version_str) { + free(version_str); + } + return; + +error: + perror("Error setting up marker mutex"); + exit(1); +#endif /* HAVE_GNU_GET_LIBC_VERSION && HAVE_LIBC_VERSION_H */ +} + GC_INNER void GC_acquire_mark_lock(void) { # ifdef NUMERIC_THREAD_ID_UNIQUE |