Skip to content

Commit fe6a930

Browse files
authored
Use os_unfair_lock instead of NSLock on Darwin (realm#4330)
1 parent 8bcf871 commit fe6a930

1 file changed

Lines changed: 50 additions & 25 deletions

File tree

Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#if canImport(Darwin)
2+
import Darwin
3+
#endif
14
import Foundation
25
import SourceKittenFramework
36
import SwiftParser
@@ -66,19 +69,19 @@ private var assertHandlers = [FileCacheKey: AssertHandler]()
6669
private var assertHandlerCache = Cache({ file in assertHandlers[file.cacheKey] })
6770

6871
private struct RebuildQueue {
69-
private let lock = NSLock()
72+
private let lock = PlatformLock()
7073
private var queue = [Structure]()
7174

7275
mutating func append(_ structure: Structure) {
73-
lock.lock()
74-
defer { lock.unlock() }
75-
queue.append(structure)
76+
lock.doLocked {
77+
queue.append(structure)
78+
}
7679
}
7780

7881
mutating func clear() {
79-
lock.lock()
80-
defer { lock.unlock() }
81-
queue.removeAll(keepingCapacity: false)
82+
lock.doLocked {
83+
queue.removeAll(keepingCapacity: false)
84+
}
8285
}
8386
}
8487

@@ -87,44 +90,38 @@ private var queueForRebuild = RebuildQueue()
8790
private class Cache<T> {
8891
private var values = [FileCacheKey: T]()
8992
private let factory: (SwiftLintFile) -> T
90-
private let lock = NSLock()
93+
private let lock = PlatformLock()
9194

9295
fileprivate init(_ factory: @escaping (SwiftLintFile) -> T) {
9396
self.factory = factory
9497
}
9598

9699
fileprivate func get(_ file: SwiftLintFile) -> T {
97100
let key = file.cacheKey
98-
lock.lock()
99-
defer { lock.unlock() }
100-
if let cachedValue = values[key] {
101-
return cachedValue
101+
return lock.doLocked {
102+
if let cachedValue = values[key] {
103+
return cachedValue
104+
}
105+
let value = factory(file)
106+
values[key] = value
107+
return value
102108
}
103-
let value = factory(file)
104-
values[key] = value
105-
return value
106109
}
107110

108111
fileprivate func invalidate(_ file: SwiftLintFile) {
109-
doLocked { values.removeValue(forKey: file.cacheKey) }
112+
lock.doLocked { values.removeValue(forKey: file.cacheKey) }
110113
}
111114

112115
fileprivate func clear() {
113-
doLocked { values.removeAll(keepingCapacity: false) }
116+
lock.doLocked { values.removeAll(keepingCapacity: false) }
114117
}
115118

116119
fileprivate func set(key: FileCacheKey, value: T) {
117-
doLocked { values[key] = value }
120+
lock.doLocked { values[key] = value }
118121
}
119122

120123
fileprivate func unset(key: FileCacheKey) {
121-
doLocked { values.removeValue(forKey: key) }
122-
}
123-
124-
private func doLocked(block: () -> Void) {
125-
lock.lock()
126-
block()
127-
lock.unlock()
124+
lock.doLocked { values.removeValue(forKey: key) }
128125
}
129126
}
130127

@@ -266,3 +263,31 @@ extension SwiftLintFile {
266263
commandsCache.clear()
267264
}
268265
}
266+
267+
private final class PlatformLock {
268+
#if canImport(Darwin)
269+
private let primitiveLock: UnsafeMutablePointer<os_unfair_lock>
270+
#else
271+
private let primitiveLock = NSLock()
272+
#endif
273+
274+
init() {
275+
#if canImport(Darwin)
276+
primitiveLock = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
277+
primitiveLock.initialize(to: os_unfair_lock())
278+
#endif
279+
}
280+
281+
@discardableResult
282+
func doLocked<U>(_ closure: () -> U) -> U {
283+
#if canImport(Darwin)
284+
os_unfair_lock_lock(primitiveLock)
285+
defer { os_unfair_lock_unlock(primitiveLock) }
286+
return closure()
287+
#else
288+
primitiveLock.lock()
289+
defer { primitiveLock.unlock() }
290+
return closure()
291+
#endif
292+
}
293+
}

0 commit comments

Comments
 (0)