-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Make lazy properties in UserToolchain thread safe #9356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Make lazy properties in UserToolchain thread safe #9356
Conversation
b9374ff to
753bcfc
Compare
`runtimeLibraryPaths`, `swiftCompilerVersion` and `targetInfo` were all marked as lazy on the UserToolchain class which could lead to race conditions if callers on multiple threads attempted to initialize them simultaneously. Use an `NSRecursiveLock` to guard access while initialization occurs, preventing crashes.
753bcfc to
274f115
Compare
|
@swift-ci please test |
| public let librarySearchPaths: [AbsolutePath] | ||
|
|
||
| /// Lock for thread-safe access to lazy properties (recursive to handle property dependencies) | ||
| private let lazyPropertiesLock = NSRecursiveLock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directly using NSLock/NSRecursiveLock is not the recommended pattern in modern Swift, instead you'll want to use an abstraction like Swift Build's LockedValue. In SwiftPM you can use ThreadSafeBox from TSCBasic.
If you want to use a single lock for multiple values to avoid a proliferation of fine-grained locks, you can define a struct to hold the values, and then guard access to the overall struct through the wrapper, rather than using a separate lock for each value.
Later, once we can increase our deployment target to macOS 15, we can replace LockedValue/ThreadSafeBox with Mutex from the Swift Standard Library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I figured these could be replaced with Mutex once we're ready to adopt but didn't know about ThreadSafeBox's used in SwiftPM. I've updated the implementation accordingly.
|
@swift-ci please test |
runtimeLibraryPaths,swiftCompilerVersionandtargetInfowere all marked as lazy on the UserToolchain class which could lead to race conditions if callers on multiple threads attempted to initialize them simultaneously.Use an
NSLockto guard access while initialization occurs, preventing crashes.