diff options
author | Stefan Liebler <stli@linux.vnet.ibm.com> | 2016-12-20 15:12:48 +0100 |
---|---|---|
committer | Stefan Liebler <stli@linux.vnet.ibm.com> | 2016-12-20 15:12:48 +0100 |
commit | dd037fb3df286b7c2d0b0c6f8d02a2dd8a8e8a08 (patch) | |
tree | 6a2cf84e658ddd3271b2a93c61c83aac4070e1d0 /sysdeps/unix/sysv/linux/s390/elision-unlock.c | |
parent | 53c5c3d5ac238901c13f28a73ba05b0678094e80 (diff) | |
download | glibc-dd037fb3df286b7c2d0b0c6f8d02a2dd8a8e8a08.tar.gz glibc-dd037fb3df286b7c2d0b0c6f8d02a2dd8a8e8a08.tar.xz glibc-dd037fb3df286b7c2d0b0c6f8d02a2dd8a8e8a08.zip |
S390: Optimize lock-elision by decrementing adapt_count at unlock.
This patch decrements the adapt_count while unlocking the futex instead of before aquiring the futex as it is done on power, too. Furthermore a transaction is only started if the futex is currently free. This check is done after starting the transaction, too. If the futex is not free and the transaction nesting depth is one, we can simply end the started transaction instead of aborting it. The implementation of this check was faulty as it always ended the started transaction. By using the fallback path, the the outermost transaction was aborted. Now the outermost transaction is aborted directly. This patch also adds some commentary and aligns the code in elision-trylock.c to the code in elision-lock.c as possible. ChangeLog: * sysdeps/unix/sysv/linux/s390/lowlevellock.h (__lll_unlock_elision, lll_unlock_elision): Add adapt_count argument. * sysdeps/unix/sysv/linux/s390/elision-lock.c: (__lll_lock_elision): Decrement adapt_count while unlocking instead of before locking. * sysdeps/unix/sysv/linux/s390/elision-trylock.c (__lll_trylock_elision): Likewise. * sysdeps/unix/sysv/linux/s390/elision-unlock.c: (__lll_unlock_elision): Likewise.
Diffstat (limited to 'sysdeps/unix/sysv/linux/s390/elision-unlock.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/s390/elision-unlock.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/sysdeps/unix/sysv/linux/s390/elision-unlock.c b/sysdeps/unix/sysv/linux/s390/elision-unlock.c index 0b1ade9e5f..e68d970799 100644 --- a/sysdeps/unix/sysv/linux/s390/elision-unlock.c +++ b/sysdeps/unix/sysv/linux/s390/elision-unlock.c @@ -21,16 +21,37 @@ #include <htm.h> int -__lll_unlock_elision(int *futex, int private) +__lll_unlock_elision(int *futex, short *adapt_count, int private) { /* If the lock is free, we elided the lock earlier. This does not necessarily mean that we are in a transaction, because the user code may - have closed the transaction, but that is impossible to detect reliably. */ - if (*futex == 0) + have closed the transaction, but that is impossible to detect reliably. + Relaxed MO access to futex is sufficient as we only need a hint, if we + started a transaction or acquired the futex in e.g. elision-lock.c. */ + if (atomic_load_relaxed (futex) == 0) { __libc_tend (); } else - lll_unlock ((*futex), private); + { + /* Update the adapt_count while unlocking before completing the critical + section. adapt_count is accessed concurrently outside of a + transaction or an aquired lock e.g. in elision-lock.c so we need to use + atomic accesses. However, the value of adapt_count is just a hint, so + relaxed MO accesses are sufficient. + If adapt_count would be decremented while locking, multiple + CPUs trying to lock the locked mutex will decrement adapt_count to + zero and another CPU will try to start a transaction, which will be + immediately aborted as the mutex is locked. + If adapt_count would be decremented while unlocking after completing + the critical section, possible waiters will be waked up before + decrementing the adapt_count. Those waked up waiters could have + destroyed and freed this mutex! */ + short adapt_count_val = atomic_load_relaxed (adapt_count); + if (adapt_count_val > 0) + atomic_store_relaxed (adapt_count, adapt_count_val - 1); + + lll_unlock ((*futex), private); + } return 0; } |