Fix a TSAN-detected race condition in TLRefCount.
Summary: See RefCountTest.cpp for a newly added test. When one thread is decrementing a local refcount and another thread is decrementing a global refcount, and the global decrement results in global zero, the second thread can reasonably expect to be able to safely destroy the refcount object. However, a memory ordering issue in LocalRefCount::collect() causes TSAN to detect a write-delete race condition on the inUpdate_ variable (though that variable is not the cause of the issue). This diff changes collect() to use memory_order_acquire so that upon reading false, collect() may exit while assuming that all memory accesses in update() are complete. This way, any memory accesses (such as a read of refCount_.state_ in update()) happen before a delete of the whole TLRefCount like so: - A memory access in update() is sequenced before the release store of false into inUpdate_ at the SCOPE_EXIT of the function, - which synchronizes with the acquire load at the end of collect() - which is sequenced before the deletion that can only happen after collect() Without this diff, the second relationship above is broken and TSAN complains. I also updated the comment on top of inUpdate_ to better reflect the purpose. I couldn't understand the original comment (which seems to suggest it's related to refcount *correctness* rather than a write-delete race), but maybe I missed something there. Reviewed By: yfeldblum Differential Revision: D22805717 fbshipit-source-id: 34cf72676760526ba457f939e307ed03dc722528
Showing
Please register or sign in to comment