summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2014-07-19 12:52:54 +0400
committerIvan Maidanski <ivmai@mail.ru>2014-07-19 12:57:44 +0400
commit757af8aa17ed107ff2915f93967087835c0100dc (patch)
tree1c1d03fc41d5ace840ee31ce21aa0b2b3a42614f
parent3c22928504e6a0d306d39a60686e963bcd04ede4 (diff)
downloadbdwgc-fix_tsx_bug.tar.gz
Fix and code refactoring of lock elision workaround (Linux/x64)fix_tsx_bug
* configure.ac (HAVE_LIBC_VERSION_H, HAVE_GNU_GET_LIBC_VERSION): Remove (revert change in previous commit). * include/private/gcconfig.h (GLIBC_2_19_TSX_BUG): New macro defined for Linux/x86_64 (if Glibc used) to workaround a bug in Glibc lock elision implementation. * pthread_support.c: Move include of gnu/libc-version.h to gcconfig.h (used to check whether lock elision workaround needed). * misc.c (GC_init): Reformat code. * pthread_support.c (mark_mutex): Initialize (to PTHREAD_MUTEX_INITIALIZER) even lock elision workaround is needed (revert change in previous commit). * pthread_support.c (parse_version): New static function (defined only if GLIBC_2_19_TSX_BUG). * pthread_support.c (GC_setup_mark_lock): Use parse_version to check target Glibc version properly; do not reinitialize mutex unless workaround needed; call ABORT (with the appropriate message) in case of a failure in pthread_mutexattr_init/settype, pthread_mutex_init.
-rw-r--r--configure.ac13
-rw-r--r--include/private/gcconfig.h5
-rw-r--r--misc.c4
-rw-r--r--pthread_support.c90
4 files changed, 50 insertions, 62 deletions
diff --git a/configure.ac b/configure.ac
index 6853e973..76679498 100644
--- a/configure.ac
+++ b/configure.ac
@@ -646,19 +646,6 @@ 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/gcconfig.h b/include/private/gcconfig.h
index c753cc2b..d667d36e 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -2257,6 +2257,11 @@
/* FIXME: This seems to be fixed in GLibc v2.14. */
# define GETCONTEXT_FPU_EXCMASK_BUG
# endif
+# if defined(__GLIBC__)
+ /* Workaround lock elision implementation for some glibc. */
+# define GLIBC_2_19_TSX_BUG
+# include <gnu/libc-version.h> /* for gnu_get_libc_version() */
+# endif
# endif
# ifdef DARWIN
# define OS_TYPE "DARWIN"
diff --git a/misc.c b/misc.c
index dccf5f37..3aca41db 100644
--- a/misc.c
+++ b/misc.c
@@ -875,8 +875,8 @@ 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();
+# 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);
diff --git a/pthread_support.c b/pthread_support.c
index 56fc94b6..bc87fe43 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -95,10 +95,6 @@
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
@@ -1977,59 +1973,59 @@ 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;
- }
- }
- }
+#ifdef GLIBC_2_19_TSX_BUG
+ /* Parse string like <major>[.<minor>[<tail>]] and return major value. */
+ static int parse_version(int *pminor, const char *pverstr) {
+ char *endp;
+ unsigned long value = strtoul(pverstr, &endp, 10);
+ int major = (int)value;
- if (0 != pthread_mutex_init(&mark_mutex, &attr)) {
- goto error;
+ if (major < 0 || (char *)pverstr == endp || (unsigned)major != value) {
+ /* Parse error */
+ return -1;
}
- pthread_mutexattr_destroy(&attr);
- if (NULL != version_str) {
- free(version_str);
+ if (*endp != '.') {
+ /* No minor part. */
+ *pminor = -1;
+ } else {
+ value = strtoul(endp + 1, &endp, 10);
+ *pminor = (int)value;
+ if (*pminor < 0 || (unsigned)(*pminor) != value) {
+ return -1;
+ }
}
- return;
+ return major;
+ }
+#endif /* GLIBC_2_19_TSX_BUG */
-error:
- perror("Error setting up marker mutex");
- exit(1);
-#endif /* HAVE_GNU_GET_LIBC_VERSION && HAVE_LIBC_VERSION_H */
+GC_INNER void GC_setup_mark_lock(void)
+{
+# ifdef GLIBC_2_19_TSX_BUG
+ pthread_mutexattr_t mattr;
+ int glibc_minor = -1;
+ int glibc_major = parse_version(&glibc_minor, gnu_get_libc_version());
+
+ if (glibc_major > 2 || (glibc_major == 2 && glibc_minor >= 19)) {
+ /* TODO: disable this workaround for glibc with fixed TSX */
+ /* This disables lock elision to workaround a bug in glibc 2.19+ */
+ if (0 != pthread_mutexattr_init(&mattr)) {
+ ABORT("pthread_mutexattr_init failed");
+ }
+ if (0 != pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK)) {
+ ABORT("pthread_mutexattr_settype failed");
+ }
+ if (0 != pthread_mutex_init(&mark_mutex, &mattr)) {
+ ABORT("pthread_mutex_init failed");
+ }
+ pthread_mutexattr_destroy(&mattr);
+ }
+# endif
}
GC_INNER void GC_acquire_mark_lock(void)