diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2014-07-19 12:52:54 +0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2014-07-19 12:57:44 +0400 |
commit | 757af8aa17ed107ff2915f93967087835c0100dc (patch) | |
tree | 1c1d03fc41d5ace840ee31ce21aa0b2b3a42614f | |
parent | 3c22928504e6a0d306d39a60686e963bcd04ede4 (diff) | |
download | bdwgc-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.ac | 13 | ||||
-rw-r--r-- | include/private/gcconfig.h | 5 | ||||
-rw-r--r-- | misc.c | 4 | ||||
-rw-r--r-- | pthread_support.c | 90 |
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" @@ -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) |