summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac13
-rw-r--r--include/private/pthread_support.h2
-rw-r--r--misc.c3
-rw-r--r--pthread_support.c53
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 */
diff --git a/misc.c b/misc.c
index e76aaafc..e27c77c2 100644
--- a/misc.c
+++ b/misc.c
@@ -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