Skip to content

Commit 6bce19f

Browse files
committed
full compatibility with OSAllocatedUnfairLock
1 parent 1b6f355 commit 6bce19f

File tree

6 files changed

+222
-33
lines changed

6 files changed

+222
-33
lines changed

.github/workflows/build.yml

+19-16
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ on:
66
workflow_dispatch:
77

88
jobs:
9-
xcode_15_2:
9+
xcode_16:
1010
runs-on: macos-14
11-
env:
12-
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
1311
steps:
1412
- name: Checkout
1513
uses: actions/checkout@v4
14+
- name: 🔍 Xcode Select
15+
run: |
16+
XCODE_PATH=`mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode' && kMDItemVersion = '16.*'" -onlyin /Applications | head -1`
17+
echo "DEVELOPER_DIR=$XCODE_PATH/Contents/Developer" >> $GITHUB_ENV
1618
- name: Version
1719
run: swift --version
1820
- name: Build
@@ -27,10 +29,10 @@ jobs:
2729
token: ${{ secrets.CODECOV_TOKEN }}
2830
files: ./coverage_report.lcov
2931

30-
xcode_14_3_1:
31-
runs-on: macos-13
32+
xcode_15_4:
33+
runs-on: macos-14
3234
env:
33-
DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer
35+
DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
3436
steps:
3537
- name: Checkout
3638
uses: actions/checkout@v4
@@ -41,9 +43,10 @@ jobs:
4143
- name: Test
4244
run: swift test
4345

44-
linux_swift_5_10:
45-
runs-on: ubuntu-latest
46-
container: swift:5.8
46+
xcode_15_2:
47+
runs-on: macos-14
48+
env:
49+
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
4750
steps:
4851
- name: Checkout
4952
uses: actions/checkout@v4
@@ -52,11 +55,11 @@ jobs:
5255
- name: Build
5356
run: swift build --build-tests
5457
- name: Test
55-
run: swift test --skip-build
58+
run: swift test
5659

57-
linux_swift_5_9:
60+
linux_swift_6_0:
5861
runs-on: ubuntu-latest
59-
container: swift:5.8
62+
container: swiftlang/swift:nightly-6.0-jammy
6063
steps:
6164
- name: Checkout
6265
uses: actions/checkout@v4
@@ -67,9 +70,9 @@ jobs:
6770
- name: Test
6871
run: swift test --skip-build
6972

70-
linux_swift_5_8:
73+
linux_swift_5_10:
7174
runs-on: ubuntu-latest
72-
container: swift:5.8
75+
container: swift:5.10
7376
steps:
7477
- name: Checkout
7578
uses: actions/checkout@v4
@@ -80,9 +83,9 @@ jobs:
8083
- name: Test
8184
run: swift test --skip-build
8285

83-
linux_swift_5_7:
86+
linux_swift_5_9:
8487
runs-on: ubuntu-latest
85-
container: swift:5.7
88+
container: swift:5.9
8689
steps:
8790
- name: Checkout
8891
uses: actions/checkout@v4

Package.swift

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.7
1+
// swift-tools-version:6.0
22

33
import PackageDescription
44

@@ -16,12 +16,23 @@ let package = Package(
1616
targets: [
1717
.target(
1818
name: "AllocatedLock",
19-
path: "Sources"
19+
path: "Sources",
20+
swiftSettings: .upcomingFeatures
2021
),
2122
.testTarget(
2223
name: "AllocatedLockTests",
2324
dependencies: ["AllocatedLock"],
24-
path: "Tests"
25+
path: "Tests",
26+
swiftSettings: .upcomingFeatures
2527
)
2628
]
2729
)
30+
31+
extension Array where Element == SwiftSetting {
32+
33+
static var upcomingFeatures: [SwiftSetting] {
34+
[
35+
.swiftLanguageMode(.v6)
36+
]
37+
}
38+
}

Package@swift-5.8.swift renamed to Package@swift-5.9.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.8
1+
// swift-tools-version:5.9
22

33
import PackageDescription
44

Sources/AllocatedLock.swift

+79-6
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@
2929
// SOFTWARE.
3030
//
3131

32-
// Backports the Swift interface around os_unfair_lock_t available in recent Darwin platforms
33-
//
32+
// Backports the Swift interface around OSAllocatedUnfairLock available in recent Darwin platforms
3433
public struct AllocatedLock<State>: @unchecked Sendable {
3534

3635
@usableFromInline
3736
let storage: Storage
3837

39-
public init(initialState: State) {
38+
public init(uncheckedState initialState: State) {
39+
self.storage = Storage(initialState: initialState)
40+
}
41+
42+
public init(initialState: State) where State: Sendable {
4043
self.storage = Storage(initialState: initialState)
4144
}
4245

@@ -46,6 +49,28 @@ public struct AllocatedLock<State>: @unchecked Sendable {
4649
defer { storage.unlock() }
4750
return try body(&storage.state)
4851
}
52+
53+
@inlinable
54+
public func withLockIfAvailable<R>(_ body: @Sendable (inout State) throws -> R) rethrows -> R? where R: Sendable {
55+
guard storage.tryLock() else { return nil }
56+
defer { storage.unlock() }
57+
return try body(&storage.state)
58+
}
59+
60+
@inlinable
61+
public func withLockIfAvailableUnchecked<R>(_ body: (inout State) throws -> R) rethrows -> R? {
62+
guard storage.tryLock() else { return nil }
63+
defer { storage.unlock() }
64+
return try body(&storage.state)
65+
}
66+
67+
@inlinable
68+
public func withLockUnchecked<R>(_ body: (inout State) throws -> R) rethrows -> R {
69+
storage.lock()
70+
defer { storage.unlock() }
71+
return try body(&storage.state)
72+
}
73+
4974
}
5075

5176
public extension AllocatedLock where State == Void {
@@ -59,6 +84,11 @@ public extension AllocatedLock where State == Void {
5984
storage.lock()
6085
}
6186

87+
@inlinable @available(*, noasync)
88+
func lockIfAvailable() -> Bool {
89+
storage.tryLock()
90+
}
91+
6292
@inlinable @available(*, noasync)
6393
func unlock() {
6494
storage.unlock()
@@ -70,6 +100,27 @@ public extension AllocatedLock where State == Void {
70100
defer { storage.unlock() }
71101
return try body()
72102
}
103+
104+
@inlinable
105+
func withLockIfAvailable<R>(_ body: @Sendable () throws -> R) rethrows -> R? where R: Sendable {
106+
guard storage.tryLock() else { return nil }
107+
defer { storage.unlock() }
108+
return try body()
109+
}
110+
111+
@inlinable
112+
func withLockIfAvailableUnchecked<R>(_ body: () throws -> R) rethrows -> R? {
113+
guard storage.tryLock() else { return nil }
114+
defer { storage.unlock() }
115+
return try body()
116+
}
117+
118+
@inlinable
119+
func withLockUnchecked<R>(_ body: () throws -> R) rethrows -> R {
120+
storage.lock()
121+
defer { storage.unlock() }
122+
return try body()
123+
}
73124
}
74125

75126
#if canImport(Darwin)
@@ -78,6 +129,7 @@ import struct os.os_unfair_lock_t
78129
import struct os.os_unfair_lock
79130
import func os.os_unfair_lock_lock
80131
import func os.os_unfair_lock_unlock
132+
import func os.os_unfair_lock_trylock
81133

82134
extension AllocatedLock {
83135
@usableFromInline
@@ -103,6 +155,11 @@ extension AllocatedLock {
103155
os_unfair_lock_unlock(_lock)
104156
}
105157

158+
@usableFromInline
159+
func tryLock() -> Bool {
160+
os_unfair_lock_trylock(_lock)
161+
}
162+
106163
deinit {
107164
self._lock.deinitialize(count: 1)
108165
self._lock.deallocate()
@@ -112,7 +169,7 @@ extension AllocatedLock {
112169

113170
#elseif canImport(Glibc)
114171

115-
@_implementationOnly import Glibc
172+
import Glibc
116173

117174
extension AllocatedLock {
118175
@usableFromInline
@@ -143,6 +200,11 @@ extension AllocatedLock {
143200
precondition(err == 0, "pthread_mutex_unlock error: \(err)")
144201
}
145202

203+
@usableFromInline
204+
func tryLock() -> Bool {
205+
pthread_mutex_trylock(_lock) == 0
206+
}
207+
146208
deinit {
147209
let err = pthread_mutex_destroy(self._lock)
148210
precondition(err == 0, "pthread_mutex_destroy error: \(err)")
@@ -153,8 +215,8 @@ extension AllocatedLock {
153215

154216
#elseif canImport(WinSDK)
155217

156-
@_implementationOnly import ucrt
157-
@_implementationOnly import WinSDK
218+
import ucrt
219+
import WinSDK
158220

159221
extension AllocatedLock {
160222
@usableFromInline
@@ -179,6 +241,17 @@ extension AllocatedLock {
179241
func unlock() {
180242
ReleaseSRWLockExclusive(_lock)
181243
}
244+
245+
@usableFromInline
246+
func tryLock() -> Bool {
247+
TryAcquireSRWLockExclusive(_lock)
248+
}
249+
250+
@usableFromInline
251+
func tryLock() -> Bool {
252+
os_unfair_lock_trylock(_lock)
253+
}
254+
182255
}
183256
}
184257

0 commit comments

Comments
 (0)