Skip to content

Commit 602ba99

Browse files
committed
Add NSLock.withLock(_:) method.
Fixes swiftlang#4735. Xcode 14 introduced the `NSLocking.withLock(_:)` method to the Darwin implementation of Foundation. This commit adds the new method to the open-source implementation. (Note: The [documentation](https://developer.apple.com/documentation/foundation/nslocking/4059821-withlock) incorrectly specifies the availability of the method as iOS 16+, etc. but it is actually available on all OS versions because it is marked [`@_alwaysEmitIntoClient`](https://github.com/apple/swift/blob/main/docs/ReferenceGuides/UnderscoredAttributes.md#_alwaysemitintoclient). The documentation bug is tracked by [FB11968310](https://feedbackassistant.apple.com/feedback/11968310).) I copied the implementation from `Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Modules/Foundation.swiftmodule/arm64e-apple-ios.swiftinterface`. # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # # On branch main # Your branch is up to date with 'origin/main'. # # Changes to be committed: # modified: Sources/Foundation/NSLock.swift # modified: Tests/Foundation/Tests/TestNSLock.swift # # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # # Date: Sat Apr 22 22:07:40 2023 -0700 # # On branch main # Your branch is ahead of 'origin/main' by 1 commit. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: Sources/Foundation/NSLock.swift # modified: Tests/Foundation/Tests/TestNSLock.swift # # Please enter the commit message for your changes. Lines starting # with '#' will be kept; you may remove them yourself if you want to. # An empty message aborts the commit. # # Date: Sat Apr 22 22:07:40 2023 -0700 # # On branch main # Your branch is ahead of 'origin/main' by 1 commit. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: Sources/Foundation/NSLock.swift # modified: Tests/Foundation/Tests/TestNSLock.swift #
1 parent 8ffea5d commit 602ba99

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

Sources/Foundation/NSLock.swift

+13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ public protocol NSLocking {
2222
func unlock()
2323
}
2424

25+
extension NSLocking {
26+
@_alwaysEmitIntoClient
27+
@_disfavoredOverload
28+
public func withLock<R>(_ body: () throws -> R) rethrows -> R {
29+
self.lock()
30+
defer {
31+
self.unlock()
32+
}
33+
34+
return try body()
35+
}
36+
}
37+
2538
#if os(Windows)
2639
private typealias _MutexPointer = UnsafeMutablePointer<SRWLOCK>
2740
private typealias _RecursiveMutexPointer = UnsafeMutablePointer<CRITICAL_SECTION>

Tests/Foundation/Tests/TestNSLock.swift

+30
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class TestNSLock: XCTestCase {
1414
("test_lockWait", test_lockWait),
1515
("test_threadsAndLocks", test_threadsAndLocks),
1616
("test_recursiveLock", test_recursiveLock),
17+
("test_withLock", test_withLock),
1718

1819
]
1920
}
@@ -187,4 +188,33 @@ class TestNSLock: XCTestCase {
187188

188189
threadCompletedCondition.unlock()
189190
}
191+
192+
func test_withLock() {
193+
let lock = NSLock()
194+
195+
var counter = 0
196+
let counterIncrementPerThread = 10_000
197+
198+
let threadCount = 10
199+
200+
let threadCompletedExpectation = expectation(description: "Expected threads to complete.")
201+
threadCompletedExpectation.expectedFulfillmentCount = threadCount
202+
203+
for _ in 0..<threadCount {
204+
let thread = Thread {
205+
for _ in 0..<counterIncrementPerThread {
206+
lock.withLock {
207+
counter += 1
208+
}
209+
}
210+
211+
threadCompletedExpectation.fulfill()
212+
}
213+
thread.start()
214+
}
215+
216+
wait(for: [threadCompletedExpectation], timeout: 10)
217+
218+
XCTAssertEqual(counter, counterIncrementPerThread * threadCount)
219+
}
190220
}

0 commit comments

Comments
 (0)