locks: make trylock routines check for 'unowned' value

Since fcmpset can fail without lock contention e.g. on arm, it was possible
to get spurious failures when the caller was expecting the primitive to succeed.

Reported by:	mmel
This commit is contained in:
Mateusz Guzik 2017-02-19 16:28:46 +00:00
parent 30545786bb
commit b247fd395d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=313944
3 changed files with 27 additions and 12 deletions

View File

@ -402,16 +402,21 @@ _mtx_trylock_flags_(volatile uintptr_t *c, int opts, const char *file, int line)
rval = 1;
recursed = false;
v = MTX_UNOWNED;
if (!_mtx_obtain_lock_fetch(m, &v, tid)) {
for (;;) {
if (_mtx_obtain_lock_fetch(m, &v, tid))
break;
if (v == MTX_UNOWNED)
continue;
if (v == tid &&
((m->lock_object.lo_flags & LO_RECURSABLE) != 0 ||
(opts & MTX_RECURSE) != 0)) {
m->mtx_recurse++;
atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
recursed = true;
} else {
rval = 0;
m->mtx_recurse++;
atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
recursed = true;
break;
}
rval = 0;
break;
}
opts &= ~MTX_RECURSE;

View File

@ -314,13 +314,18 @@ __rw_try_wlock(volatile uintptr_t *c, const char *file, int line)
rval = 1;
recursed = false;
v = RW_UNLOCKED;
if (!atomic_fcmpset_acq_ptr(&rw->rw_lock, &v, tid)) {
for (;;) {
if (atomic_fcmpset_acq_ptr(&rw->rw_lock, &v, tid))
break;
if (v == RW_UNLOCKED)
continue;
if (v == tid && (rw->lock_object.lo_flags & LO_RECURSABLE)) {
rw->rw_recurse++;
atomic_set_ptr(&rw->rw_lock, RW_LOCK_WRITER_RECURSED);
} else {
rval = 0;
break;
}
rval = 0;
break;
}
LOCK_LOG_TRY("WLOCK", &rw->lock_object, 0, rval, file, line);

View File

@ -341,13 +341,18 @@ sx_try_xlock_(struct sx *sx, const char *file, int line)
rval = 1;
recursed = false;
x = SX_LOCK_UNLOCKED;
if (!atomic_fcmpset_acq_ptr(&sx->sx_lock, &x, tid)) {
for (;;) {
if (atomic_fcmpset_acq_ptr(&sx->sx_lock, &x, tid))
break;
if (x == SX_LOCK_UNLOCKED)
continue;
if (x == tid && (sx->lock_object.lo_flags & LO_RECURSABLE)) {
sx->sx_recurse++;
atomic_set_ptr(&sx->sx_lock, SX_LOCK_RECURSED);
} else {
rval = 0;
break;
}
rval = 0;
break;
}
LOCK_LOG_TRY("XLOCK", &sx->lock_object, 0, rval, file, line);