On Sat, Feb 02, 2019 at 11:14:27AM +0100, Thomas Gleixner wrote: > On Sat, 2 Feb 2019, Heiko Carstens wrote: > So after the unlock @timestamp 337.215675 the kernel does not deal with > that futex at all until the failed lock attempt where it rightfully rejects > the attempt due to the alleged owner being gone. > > So this looks more like user space doing something stupid... > > As we talked about the missing barriers before, I just looked at > pthread_mutex_trylock() and that does still: > > if (robust) > { > ENQUEUE_MUTEX_PI (mutex); > THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); > } > > So it's missing the barriers which pthread_mutex_lock() has. Grasping for > straws obviously.... Excellent! Taking a look into the disassembly of nptl/pthread_mutex_trylock.o reveals this part: 140: a5 1b 00 01 oill %r1,1 144: e5 48 a0 f0 00 00 mvghi 240(%r10),0 <--- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); 14a: e3 10 a0 e0 00 24 stg %r1,224(%r10) <--- last THREAD_SETMEM of ENQUEUE_MUTEX_PI I added a barrier between those two and now the code looks like this: 140: a5 1b 00 01 oill %r1,1 144: e3 10 a0 e0 00 24 stg %r1,224(%r10) 14a: e5 48 a0 f0 00 00 mvghi 240(%r10),0 Looks like this was a one instruction race... I'll try to reproduce with the patch below (sprinkling compiler barriers just like the other files have). diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index 7de61f4f68..3b093cb09c 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -116,8 +116,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) mutex->__data.__count = 1; /* 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 exist here. If we fall @@ -177,7 +181,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) } while ((oldval & FUTEX_OWNER_DIED) != 0); + /* 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); mutex->__data.__owner = id; @@ -279,7 +288,11 @@ __pthread_mutex_trylock (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); + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Note that we deliberately exit here. If we fall @@ -308,7 +321,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) 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); }