Avoid mixing atomic futex changes and QAtomic
Either the mix of futex and atomic, or the mix of 32-bit futex and 64-bit atomic doesn't work. In any case, the existing code leads to bad behavior. Fixes: QTBUG-92188 Change-Id: Icc6ba28d6e2465c373d00e84f4da2b92c037e797 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> (cherry picked from commit 2d9cc639a4a7a5e97979a6034364bd67dfa10c23) Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
562187fc55
commit
7b3635e013
@ -358,47 +358,31 @@ void QSemaphore::release(int n)
|
|||||||
quintptr prevValue = u.fetchAndAddRelease(nn);
|
quintptr prevValue = u.fetchAndAddRelease(nn);
|
||||||
if (futexNeedsWake(prevValue)) {
|
if (futexNeedsWake(prevValue)) {
|
||||||
#ifdef FUTEX_OP
|
#ifdef FUTEX_OP
|
||||||
if (!futexHasWaiterCount) {
|
if (futexHasWaiterCount) {
|
||||||
/*
|
|
||||||
On 32-bit systems, all waiters are waiting on the same address,
|
|
||||||
so we'll wake them all and ask the kernel to clear the high bit.
|
|
||||||
|
|
||||||
atomic {
|
|
||||||
int oldval = u;
|
|
||||||
u = oldval & ~(1 << 31);
|
|
||||||
futexWake(u, INT_MAX);
|
|
||||||
if (oldval == 0) // impossible condition
|
|
||||||
futexWake(u, INT_MAX);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
quint32 op = FUTEX_OP_ANDN | FUTEX_OP_OPARG_SHIFT;
|
|
||||||
quint32 oparg = 31;
|
|
||||||
quint32 cmp = FUTEX_OP_CMP_EQ;
|
|
||||||
quint32 cmparg = 0;
|
|
||||||
futexWakeOp(u, INT_MAX, INT_MAX, u, FUTEX_OP(op, oparg, cmp, cmparg));
|
|
||||||
} else {
|
|
||||||
/*
|
/*
|
||||||
On 64-bit systems, the single-token waiters wait on the low half
|
On 64-bit systems, the single-token waiters wait on the low half
|
||||||
and the multi-token waiters wait on the upper half. So we ask
|
and the multi-token waiters wait on the upper half. So we ask
|
||||||
the kernel to wake up n single-token waiters and all multi-token
|
the kernel to wake up n single-token waiters and all multi-token
|
||||||
waiters (if any), then clear the multi-token wait bit.
|
waiters (if any), and clear the multi-token wait bit.
|
||||||
|
|
||||||
atomic {
|
atomic {
|
||||||
int oldval = *upper;
|
int oldval = *upper;
|
||||||
*upper = oldval & ~(1 << 31);
|
*upper = oldval | 0;
|
||||||
futexWake(lower, n);
|
futexWake(lower, n);
|
||||||
if (oldval < 0) // sign bit set
|
if (oldval != 0) // always true
|
||||||
futexWake(upper, INT_MAX);
|
futexWake(upper, INT_MAX);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
quint32 op = FUTEX_OP_ANDN | FUTEX_OP_OPARG_SHIFT;
|
quint32 op = FUTEX_OP_OR;
|
||||||
quint32 oparg = 31;
|
quint32 oparg = 0;
|
||||||
quint32 cmp = FUTEX_OP_CMP_LT;
|
quint32 cmp = FUTEX_OP_CMP_NE;
|
||||||
quint32 cmparg = 0;
|
quint32 cmparg = 0;
|
||||||
|
u.fetchAndAndRelease(futexNeedsWakeAllBit - 1);
|
||||||
futexWakeOp(*futexLow32(&u), n, INT_MAX, *futexHigh32(&u), FUTEX_OP(op, oparg, cmp, cmparg));
|
futexWakeOp(*futexLow32(&u), n, INT_MAX, *futexHigh32(&u), FUTEX_OP(op, oparg, cmp, cmparg));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#endif
|
||||||
// Unset the bit and wake everyone. There are two possibibilies
|
// Unset the bit and wake everyone. There are two possibilities
|
||||||
// under which a thread can set the bit between the AND and the
|
// under which a thread can set the bit between the AND and the
|
||||||
// futexWake:
|
// futexWake:
|
||||||
// 1) it did see the new counter value, but it wasn't enough for
|
// 1) it did see the new counter value, but it wasn't enough for
|
||||||
@ -406,8 +390,12 @@ void QSemaphore::release(int n)
|
|||||||
// 2) it did not see the new counter value, in which case its
|
// 2) it did not see the new counter value, in which case its
|
||||||
// futexWait will fail.
|
// futexWait will fail.
|
||||||
u.fetchAndAndRelease(futexNeedsWakeAllBit - 1);
|
u.fetchAndAndRelease(futexNeedsWakeAllBit - 1);
|
||||||
|
if (futexHasWaiterCount) {
|
||||||
|
futexWakeAll(*futexLow32(&u));
|
||||||
|
futexWakeAll(*futexHigh32(&u));
|
||||||
|
} else {
|
||||||
futexWakeAll(u);
|
futexWakeAll(u);
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user