Add fiber safety to crystal/once #15370
Draft
+239
−131
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Removes the global
Mutex
(previously only used when thepreview_mt
flag is defined) that would prevent concurrent initializers to run in parallel, while still being able to detect reentrancy.It works by keeping a list of pending operations (one per
flag
pointer) protected by a global lock that doesn't block other initializers from running.Using a linked-list of stack allocated structs may sound inefficient compared to a
Hash
but there should usually not be many concurrent / parallel / nested lazy initializations that following a few pointers would be significant compared to calculating a hash and (re)allocating memory.This isn't very important for the initialization of class vars and constants (happens sequentially at the start of the program, before we even start threads) but we plan to reuse the feature to implement #14905 where the lazy initialization can kick in at any time.
Follow up to #15369 and #15371
CREDITS: @BlobCodes wrote the initial implementation in master...BlobCodes:crystal:perf/crystal-once-v2. I mostly removed the fences (SpinLock already deals with memory order), made it compatible with both the enum or bool variants, where the enum allows to skip over checking the operations when processing —maybe not very significant?
I shall read his code much more carefully now 🙇