QThreadPipe & QEvent: use a simpler atomic operation

This causes modern compilers (i.e., not MSVC) to emit a single
bit-test-and-set instruction instead of a cmpxchg. It's still an atomic
operation, so it's not that much faster (if at all), but it has simpler
encoding.

Previous:
000000000026bca0 <QEventDispatcherUNIX::wakeUp()>:
  26bca0:       mov    0x8(%rdi),%rdx
  26bca4:       xor    %eax,%eax
  26bca6:       mov    $0x1,%ecx
  26bcab:       lock cmpxchg %ecx,0x98(%rdx)
  26bcb3:       jne    26bcc5 <QEventDispatcherUNIX::wakeUp()+0x25>
  26bcb5:       mov    0x90(%rdx),%edi
  26bcbb:       mov    $0x1,%esi
  26bcc0:       jmp    c01d0 <eventfd_write@plt>
  26bcc5:       ret

Now:
  26b3a0:       mov    0x8(%rdi),%rax
  26b3a4:       lock btsl $0x0,0x98(%rax)
  26b3ad:       jae    26b3b0 <QEventDispatcherUNIX::wakeUp()+0x10>
  26b3af:       ret
  26b3b0:       mov    0x90(%rax),%edi
  26b3b6:       mov    $0x1,%esi
  26b3bb:       jmp    c11d0 <eventfd_write@plt>

Change-Id: I53335f845a1345299031fffd176fa8ac1de3ad13
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Thiago Macieira 2023-07-07 11:16:00 -07:00
parent 41f4139306
commit 4a43149d7b
2 changed files with 4 additions and 3 deletions

View File

@ -433,8 +433,9 @@ struct QBasicAtomicBitField {
QBasicAtomicInteger<uint> &entry = data[which / BitsPerInt];
const uint old = entry.loadRelaxed();
const uint bit = 1U << (which % BitsPerInt);
return !(old & bit) // wasn't taken
&& entry.testAndSetRelaxed(old, old | bit); // still wasn't taken
if (old & bit)
return false; // already taken
return (entry.fetchAndOrRelaxed(bit) & bit) == 0;
// don't update 'next' here - it's unlikely that it will need
// to be updated, in the general case, and having 'next'

View File

@ -123,7 +123,7 @@ pollfd QThreadPipe::prepare() const
void QThreadPipe::wakeUp()
{
if (wakeUps.testAndSetAcquire(0, 1)) {
if ((wakeUps.fetchAndOrAcquire(1) & 1) == 0) {
#if QT_CONFIG(eventfd)
eventfd_write(fds[0], 1);
return;