diff --git c/include/private/gc_priv.h w/include/private/gc_priv.h index 0ad92fc..b877fac 100644 --- c/include/private/gc_priv.h +++ w/include/private/gc_priv.h @@ -2368,6 +2368,7 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str, /* GC_notify_all_builder() is called when GC_fl_builder_count */ /* reaches 0. */ + GC_INNER void GC_setup_mark_lock(void); GC_INNER void GC_acquire_mark_lock(void); GC_INNER void GC_release_mark_lock(void); GC_INNER void GC_notify_all_builder(void); diff --git c/include/private/gcconfig.h w/include/private/gcconfig.h index c753cc2..b5ed075 100644 --- c/include/private/gcconfig.h +++ w/include/private/gcconfig.h @@ -1357,6 +1357,11 @@ # define PREFETCH_FOR_WRITE(x) \ __asm__ __volatile__ ("prefetchw %0" : : "m"(*(char *)(x))) # endif +# if defined(__GLIBC__) + /* Workaround lock elision implementation for some glibc. */ +# define GLIBC_2_19_TSX_BUG +# include /* for gnu_get_libc_version() */ +# endif # endif # ifdef CYGWIN32 # define OS_TYPE "CYGWIN32" @@ -2257,6 +2262,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 /* for gnu_get_libc_version() */ +# endif # endif # ifdef DARWIN # define OS_TYPE "DARWIN" diff --git c/include/private/pthread_support.h w/include/private/pthread_support.h index 525a9aa..017f194 100644 --- c/include/private/pthread_support.h +++ w/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 c/misc.c w/misc.c index df434a1..3aca41d 100644 --- c/misc.c +++ w/misc.c @@ -875,6 +875,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 c/pthread_support.c w/pthread_support.c index c00b93d..8a7c50b 100644 --- c/pthread_support.c +++ w/pthread_support.c @@ -1979,6 +1979,55 @@ GC_INNER void GC_lock(void) static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER; +#ifdef GLIBC_2_19_TSX_BUG + /* Parse string like [.[]] 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 (major < 0 || (char *)pverstr == endp || (unsigned)major != value) { + /* Parse error */ + return -1; + } + 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 major; + } +#endif /* GLIBC_2_19_TSX_BUG */ + +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_NORMAL)) { + 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) { GC_ASSERT(GC_mark_lock_holder != NUMERIC_THREAD_ID(pthread_self()));