diff options
Diffstat (limited to 'source/l/gc/noelision.patch')
-rw-r--r-- | source/l/gc/noelision.patch | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/source/l/gc/noelision.patch b/source/l/gc/noelision.patch new file mode 100644 index 00000000..0e1515ea --- /dev/null +++ b/source/l/gc/noelision.patch @@ -0,0 +1,127 @@ +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 <gnu/libc-version.h> /* 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 <gnu/libc-version.h> /* 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 <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 (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())); |