diff options
author | Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> | 2015-12-28 12:24:43 -0200 |
---|---|---|
committer | Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> | 2016-01-08 17:47:33 -0200 |
commit | 42bf1c897170ff951c7fd0ee9da25f97ff787396 (patch) | |
tree | 3e69cd2d5201944482407b86b4854fe75ab34f12 | |
parent | bc49a7afd38c1bd00f0ad9fd6592a5959d5ba72e (diff) | |
download | glibc-42bf1c897170ff951c7fd0ee9da25f97ff787396.tar glibc-42bf1c897170ff951c7fd0ee9da25f97ff787396.tar.gz glibc-42bf1c897170ff951c7fd0ee9da25f97ff787396.tar.bz2 glibc-42bf1c897170ff951c7fd0ee9da25f97ff787396.zip |
powerpc: Enforce compiler barriers on hardware transactions
Work around a GCC behavior with hardware transactional memory built-ins.
GCC doesn't treat the PowerPC transactional built-ins as compiler
barriers, moving instructions past the transaction boundaries and
altering their atomicity.
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | sysdeps/powerpc/nptl/elide.h | 8 | ||||
-rw-r--r-- | sysdeps/powerpc/sysdep.h | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/elision-lock.c | 4 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/elision-trylock.c | 6 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/elision-unlock.c | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/htm.h | 39 |
7 files changed, 58 insertions, 15 deletions
@@ -1,3 +1,15 @@ +2016-01-08 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/htm.h (__libc_tbegin, + __libc_tabort, __libc_tend): New wrappers that enforce compiler + barriers to their respective compiler built-ins. + * sysdeps/powerpc/nptl/elide.h (__get_new_count, ELIDE_LOCK, + ELIDE_TRYLOCK, __elide_unlock): Use the new wrappers. + * sysdeps/powerpc/sysdep.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/elision-lock.c: Likewise. + * sysdeps/unix/sysv/linux/powerpc/elision-trylock.c: Likewise. + * sysdeps/unix/sysv/linux/powerpc/elision-unlock.c: Likewise. + 2016-01-08 Marko Myllynen <myllynen@redhat.com> * scripts/config.guess: Revert previous shebang change. diff --git a/sysdeps/powerpc/nptl/elide.h b/sysdeps/powerpc/nptl/elide.h index c737464901..77bd82ecba 100644 --- a/sysdeps/powerpc/nptl/elide.h +++ b/sysdeps/powerpc/nptl/elide.h @@ -68,14 +68,14 @@ __get_new_count (uint8_t *adapt_count, int attempt) else \ for (int i = __elision_aconf.try_tbegin; i > 0; i--) \ { \ - if (__builtin_tbegin (0)) \ + if (__libc_tbegin (0)) \ { \ if (is_lock_free) \ { \ ret = 1; \ break; \ } \ - __builtin_tabort (_ABORT_LOCK_BUSY); \ + __libc_tabort (_ABORT_LOCK_BUSY); \ } \ else \ if (!__get_new_count (&adapt_count,i)) \ @@ -90,7 +90,7 @@ __get_new_count (uint8_t *adapt_count, int attempt) if (__elision_aconf.try_tbegin > 0) \ { \ if (write) \ - __builtin_tabort (_ABORT_NESTED_TRYLOCK); \ + __libc_tabort (_ABORT_NESTED_TRYLOCK); \ ret = ELIDE_LOCK (adapt_count, is_lock_free); \ } \ ret; \ @@ -102,7 +102,7 @@ __elide_unlock (int is_lock_free) { if (is_lock_free) { - __builtin_tend (0); + __libc_tend (0); return true; } return false; diff --git a/sysdeps/powerpc/sysdep.h b/sysdeps/powerpc/sysdep.h index def54f08a2..800623af37 100644 --- a/sysdeps/powerpc/sysdep.h +++ b/sysdeps/powerpc/sysdep.h @@ -180,7 +180,7 @@ # define ABORT_TRANSACTION \ ({ \ if (THREAD_GET_TM_CAPABLE ()) \ - __builtin_tabort (_ABORT_SYSCALL); \ + __libc_tabort (_ABORT_SYSCALL); \ }) #else # define ABORT_TRANSACTION diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c index 830d2ccfe1..dd1e4c3b17 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c @@ -52,12 +52,12 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) for (int i = aconf.try_tbegin; i > 0; i--) { - if (__builtin_tbegin (0)) + if (__libc_tbegin (0)) { if (*lock == 0) return 0; /* Lock was busy. Fall back to normal locking. */ - __builtin_tabort (_ABORT_LOCK_BUSY); + __libc_tabort (_ABORT_LOCK_BUSY); } else { diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c index 9263f1d1b8..0807a6a432 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c @@ -31,7 +31,7 @@ int __lll_trylock_elision (int *futex, short *adapt_count) { /* Implement POSIX semantics by forbiding nesting elided trylocks. */ - __builtin_tabort (_ABORT_NESTED_TRYLOCK); + __libc_tabort (_ABORT_NESTED_TRYLOCK); /* Only try a transaction if it's worth it. */ if (*adapt_count > 0) @@ -39,14 +39,14 @@ __lll_trylock_elision (int *futex, short *adapt_count) goto use_lock; } - if (__builtin_tbegin (0)) + if (__libc_tbegin (0)) { if (*futex == 0) return 0; /* Lock was busy. This is never a nested transaction. End it, and set the adapt count. */ - __builtin_tend (0); + __libc_tend (0); if (aconf.skip_lock_busy > 0) *adapt_count = aconf.skip_lock_busy; diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c index 2561b1dca2..43c5a67df2 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c @@ -25,7 +25,7 @@ __lll_unlock_elision (int *lock, short *adapt_count, int pshared) { /* When the lock was free we're in a transaction. */ if (*lock == 0) - __builtin_tend (0); + __libc_tend (0); else { lll_unlock ((*lock), pshared); diff --git a/sysdeps/unix/sysv/linux/powerpc/htm.h b/sysdeps/unix/sysv/linux/powerpc/htm.h index b18b47ee67..16b2237fcc 100644 --- a/sysdeps/unix/sysv/linux/powerpc/htm.h +++ b/sysdeps/unix/sysv/linux/powerpc/htm.h @@ -118,13 +118,44 @@ __ret; \ }) -#define __builtin_tbegin(tdb) _tbegin () -#define __builtin_tend(nested) _tend () -#define __builtin_tabort(abortcode) _tabort (abortcode) -#define __builtin_get_texasru() _texasru () +#define __libc_tbegin(tdb) _tbegin () +#define __libc_tend(nested) _tend () +#define __libc_tabort(abortcode) _tabort (abortcode) +#define __builtin_get_texasru() _texasru () #else # include <htmintrin.h> + +# ifdef __TM_FENCE__ + /* New GCC behavior. */ +# define __libc_tbegin(R) __builtin_tbegin (R); +# define __libc_tend(R) __builtin_tend (R); +# define __libc_tabort(R) __builtin_tabort (R); +# else + /* Workaround an old GCC behavior. Earlier releases of GCC 4.9 and 5.0, + didn't use to treat __builtin_tbegin, __builtin_tend and + __builtin_tabort as compiler barriers, moving instructions into and + out the transaction. + Remove this when glibc drops support for GCC 5.0. */ +# define __libc_tbegin(R) \ + ({ __asm__ volatile("" ::: "memory"); \ + unsigned int __ret = __builtin_tbegin (R); \ + __asm__ volatile("" ::: "memory"); \ + __ret; \ + }) +# define __libc_tabort(R) \ + ({ __asm__ volatile("" ::: "memory"); \ + unsigned int __ret = __builtin_tabort (R); \ + __asm__ volatile("" ::: "memory"); \ + __ret; \ + }) +# define __libc_tend(R) \ + ({ __asm__ volatile("" ::: "memory"); \ + unsigned int __ret = __builtin_tend (R); \ + __asm__ volatile("" ::: "memory"); \ + __ret; \ + }) +# endif /* __TM_FENCE__ */ #endif /* __HTM__ */ #endif /* __ASSEMBLER__ */ |