[cfe-dev] Who is working on/has worked on Capability analysis (-Wthread-safety)?

Aaron Puchert via cfe-dev cfe-dev at lists.llvm.org
Fri Nov 5 16:12:30 PDT 2021


Am 05.11.21 um 23:30 schrieb Randell Jesup:
>
> The downside of using a rwlock is performance and fairness; c++ 
> doesn't guarantee any specific fairness to rwlocks, and they have 
> lower performance/higher complexity than normal locks/mutexes.   In 
> particular, an implementation could let readers starve writers... 
> though if the same thread holds a read lock, can it obtain a write 
> lock?  Only I think in rwlocks that allow upgrades.  Otherwise it must 
> release the read lock, grab the write lock, then release it and get 
> the read lock back.
>
> The other alternatives are to lock exclusively around each access 
> (including on the writing thread), or ignore static analysis warnings 
> if we're on the writing thread, or annotate with an assertion that 
> quiets the warnings, such as AssertOnWritingThread(), which has 
> ASSERT_EXCLUSIVE_LOCK/ASSERT_CAPABILITY (perhaps only in DEBUG mode).
>
Yes, true read/write locks might not work for you. But as I wrote, a 
capability doesn't have to be an actual mutex, it's just some kind of 
mechanism that regulates read/write accesses. If you could wrap your 
existing mechanism into a class that gives the main thread perpetual 
read access (perhaps via ASSERT_SHARED_CAPABILITY, as you suggested) and 
write access on acquisition, and the other threads read access on 
acquisition, that's fine. It needs different entry points (because we're 
doing static analysis), but that's it.

As an unrelated example, I work in a code base where we have 
"speculative locks" that work with hardware transactional memory. They 
actually allow multiple threads write access at the same time. But 
that's no problem for the analysis, because exclusivity (or perhaps 
rather the avoidance of races/conflicts) is the capability's job. The 
analysis only checks that the capability is acquired for the access.

> Writing a MaybeMutexAutoLock class actually works fairly well for this 
> case, and avoids Maybe<>/std::optional, and lets us avoid the extra 
> bool for all the MutexAutoLocks (which appear ~50-100x+ the frequency 
> of MaybeMutexAutoLock).
>
That's good to hear! For what it's worth, we've made pretty good 
experiences with more powerful lock scopes (they allow unlocking, 
relocking, promotion and demotion). Sometimes for example there are 
loops where the lock has to be temporarily released. Since we're using 
exceptions, we can't use an RAII unlocker. (And we probably wouldn't 
want that because of possibly unnecessary relocking on scope exits.) So 
we just call scope.Unlock(), then later scope.Lock(), and the lock will 
be released by the destructor if it's still held, but not if it isn't.

Aaron



More information about the cfe-dev mailing list