diff options
author | Torvald Riegel <triegel@redhat.com> | 2016-12-24 00:40:46 +0100 |
---|---|---|
committer | Torvald Riegel <triegel@redhat.com> | 2017-01-13 23:12:32 +0100 |
commit | 8f9450a0b7a9e78267e8ae1ab1000ebca08e473e (patch) | |
tree | bca2a0f01266faddbb985b5e3751b64f068fa565 /nptl/pthread_mutex_timedlock.c | |
parent | 8e31cafb268938729a1314806a924d73fb1991c5 (diff) | |
download | glibc-8f9450a0b7a9e78267e8ae1ab1000ebca08e473e.tar.gz glibc-8f9450a0b7a9e78267e8ae1ab1000ebca08e473e.tar.xz glibc-8f9450a0b7a9e78267e8ae1ab1000ebca08e473e.zip |
Add compiler barriers around modifications of the robust mutex list.
Any changes to the per-thread list of robust mutexes currently acquired as well as the pending-operations entry are not simply sequential code but basically concurrent with any actions taken by the kernel when it tries to clean up after a crash. This is not quite like multi-thread concurrency but more like signal-handler concurrency. This patch fixes latent bugs by adding compiler barriers where necessary so that it is ensured that the kernel crash handling sees consistent data. This is meant to be easy to backport, so we do not use C11-style signal fences yet. * nptl/descr.h (ENQUEUE_MUTEX_BOTH, DEQUEUE_MUTEX): Add compiler barriers and comments. * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Likewise. * nptl/pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise. * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise.
Diffstat (limited to 'nptl/pthread_mutex_timedlock.c')
-rw-r--r-- | nptl/pthread_mutex_timedlock.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index ddd46fe414..a4beb7b0dc 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -140,6 +140,9 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, &mutex->__data.__list.__next); + /* We need to set op_pending before starting the operation. Also + see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); oldval = mutex->__data.__lock; /* This is set to FUTEX_WAITERS iff we might have shared the @@ -177,7 +180,12 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, /* But it is inconsistent unless marked otherwise. */ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Note that we deliberately exit here. If we fall @@ -193,6 +201,8 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, int kind = PTHREAD_MUTEX_TYPE (mutex); if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) { + /* We do not need to ensure ordering wrt another memory + access. Also see comments at ENQUEUE_MUTEX. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EDEADLK; @@ -200,6 +210,8 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) { + /* We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); @@ -294,12 +306,19 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, mutex->__data.__count = 0; int private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex); lll_unlock (mutex->__data.__lock, private); + /* FIXME This violates the mutex destruction requirements. See + __pthread_mutex_unlock_full. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return ENOTRECOVERABLE; } mutex->__data.__count = 1; + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); break; @@ -320,10 +339,15 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; if (robust) - /* Note: robust PI futexes are signaled by setting bit 0. */ - THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, - (void *) (((uintptr_t) &mutex->__data.__list.__next) - | 1)); + { + /* Note: robust PI futexes are signaled by setting bit 0. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + (void *) (((uintptr_t) &mutex->__data.__list.__next) + | 1)); + /* We need to set op_pending before starting the operation. Also + see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); + } oldval = mutex->__data.__lock; @@ -332,12 +356,16 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, { if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) { + /* We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EDEADLK; } if (kind == PTHREAD_MUTEX_RECURSIVE_NP) { + /* We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Just bump the counter. */ @@ -424,7 +452,12 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, /* But it is inconsistent unless marked otherwise. */ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX_PI (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Note that we deliberately exit here. If we fall @@ -447,6 +480,8 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, PTHREAD_ROBUST_MUTEX_PSHARED (mutex)), 0, 0); + /* To the kernel, this will be visible after the kernel has + acquired the mutex in the syscall. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return ENOTRECOVERABLE; } @@ -454,7 +489,12 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, mutex->__data.__count = 1; if (robust) { + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX_PI (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); } } |