Hello! I’m exploring the runtime source code now, and I can’t figure out why std::atomic is needed in WeakReferenceclass. The comment at the top of the file states:
// Thread-safety:
//
// Reading a weak reference must be thread-safe with respect to:
// * concurrent readers
// * concurrent weak reference zeroing due to deallocation of the
// pointed-to object
// * concurrent ObjC readers or zeroing (for non-native weak storage)
//
// Reading a weak reference is NOT thread-safe with respect to:
// * concurrent writes to the weak variable other than zeroing
// * concurrent destruction of the weak variable
//
// Writing a weak reference must be thread-safe with respect to:
// * concurrent weak reference zeroing due to deallocation of the
// pointed-to object
// * concurrent ObjC zeroing (for non-native weak storage)
//
// Writing a weak reference is NOT thread-safe with respect to:
// * concurrent reads
// * concurrent writes other than zeroing
Here's my understanding:
Essentially thread-safe access should be preserved for reading and reading, reading and zeroing, writing and zeroing (I'm omitting the ObjC case here, because nonnativeValue is not wrapped in atomic at all). But zeroing of reference due to its deallocation does not seem to affect WeakReferenceBits in any way. It just deallocates an object, putting it into the "Freed" state, but side table remains alive, and nativeValue bits point to the same object, so it doesn't seem like this can introduce any races on this variable. Concurrent reads are usually safe on their own.
I searched through the class implementation for store calls, and found them in two groups of methods: nativeCopyInitFromBits, nativeInit, nativeDestroy and nativeAssign, which all seem to be write methods, so should not require synchronization. nativeTakeStrong, nativeTakeInit and unknownTakeStrong have pretty straightforward implementations, but I wasn't able to come up with some code snippet which emits any of them.
So, my question is: what I am misunderstanding? Is synchronization of nativeValue actually needed for safe deallocation, or for the -Take- calls? How can I make the compiler emit the -Take- calls?
Thanks in advance.