Skip to content

atomic.cpp: Spinlock powering shared_ptr atomics can lead to priority inversion #370

@BillyONeal

Description

@BillyONeal

Describe the bug
shared_ptr's atomic functions (e.g. std::atomic_store) are powered by an external lock present in our separately compiled machinery, _Lock_shared_ptr_spin_lock and _Unlock_shared_ptr_spin_lock. This was written to use a plain spin lock with no mitigation to go to sleep if spinning is taking too long, nor is there any mitigation for memory bandwidth consumption.

STL/stl/src/atomic.cpp

Lines 13 to 34 in aa0a7a3

// SPIN LOCK FOR shared_ptr ATOMIC OPERATIONS
volatile long _Shared_ptr_flag;
_CRTIMP2_PURE void __cdecl _Lock_shared_ptr_spin_lock() { // spin until _Shared_ptr_flag successfully set
#ifdef _M_ARM
while (_InterlockedExchange_acq(&_Shared_ptr_flag, 1)) {
__yield();
}
#else // _M_ARM
while (_interlockedbittestandset(&_Shared_ptr_flag, 0)) { // set bit 0
}
#endif // _M_ARM
}
_CRTIMP2_PURE void __cdecl _Unlock_shared_ptr_spin_lock() { // release previously obtained lock
#ifdef _M_ARM
__dmb(_ARM_BARRIER_ISH);
__iso_volatile_store32((volatile int*) &_Shared_ptr_flag, 0);
#else // _M_ARM
_interlockedbittestandreset(&_Shared_ptr_flag, 0); // reset bit 0
#endif // _M_ARM
}

In single threaded scenarios this is particularly bad when a low priority thread currently holds the spinlock, and a high priority thread spins "effectively forever".

In an ABI breaking release, it would be nice to reuse the low order bit of the reference count control block pointer in the shared_ptr; but even without an ABI breaking release we could do better by replacing the spinlock entirely with something like SRWLOCK on Vista and later, implementing exponential backoff, or relying on C++20 std::atomic waiting features once we have those implemented.

Also tracked by Developer Community as DevCom-716238 and Microsoft-internal VSO-975564.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!performanceMust go faster

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions