Skip to content

Commit 6e798dc

Browse files
authored
Change from Lock wrapper inside TSCBasic to NSLock (#5575)
* Migrate Lock wrapper from TSCBasic to SwiftPM Basics as NSLock extention * update call sites
1 parent 7a6466b commit 6e798dc

29 files changed

+70
-45
lines changed

Sources/Basics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_library(Basics
2323
JSON+Extensions.swift
2424
JSONDecoder+Extensions.swift
2525
Netrc.swift
26+
NSLock+Extensions.swift
2627
Observability.swift
2728
Sandbox.swift
2829
String+Extensions.swift

Sources/Basics/ConcurrencyHelpers.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Dispatch
14+
import class Foundation.NSLock
1415
import class Foundation.ProcessInfo
15-
import TSCBasic
16-
17-
public typealias Lock = TSCBasic.Lock
16+
import enum TSCBasic.ProcessEnv
17+
import func TSCBasic.tsc_await
1818

1919
/// Thread-safe dictionary like structure
2020
public final class ThreadSafeKeyValueStore<Key, Value> where Key: Hashable {
2121
private var underlying: [Key: Value]
22-
private let lock = Lock()
22+
private let lock = NSLock()
2323

2424
public init(_ seed: [Key: Value] = [:]) {
2525
self.underlying = seed
@@ -100,7 +100,7 @@ public final class ThreadSafeKeyValueStore<Key, Value> where Key: Hashable {
100100
/// Thread-safe array like structure
101101
public final class ThreadSafeArrayStore<Value> {
102102
private var underlying: [Value]
103-
private let lock = Lock()
103+
private let lock = NSLock()
104104

105105
public init(_ seed: [Value] = []) {
106106
self.underlying = seed
@@ -172,7 +172,7 @@ public final class ThreadSafeArrayStore<Value> {
172172
@dynamicMemberLookup
173173
public final class ThreadSafeBox<Value> {
174174
private var underlying: Value?
175-
private let lock = Lock()
175+
private let lock = NSLock()
176176

177177
public init() {}
178178

Sources/Basics/HTTPClient.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import struct Foundation.Data
1515
import struct Foundation.Date
1616
import class Foundation.JSONDecoder
1717
import class Foundation.NSError
18+
import class Foundation.NSLock
1819
import class Foundation.OperationQueue
1920
import struct Foundation.URL
2021
import struct Foundation.UUID
@@ -56,7 +57,7 @@ public struct HTTPClient: Cancellable {
5657
private var outstandingRequests = ThreadSafeKeyValueStore<UUID, (url: URL, completion: CompletionHandler, progress: ProgressHandler?, queue: DispatchQueue)>()
5758

5859
// static to share across instances of the http client
59-
private static var hostsErrorsLock = Lock()
60+
private static var hostsErrorsLock = NSLock()
6061
private static var hostsErrors = [String: [Date]]()
6162

6263
public init(configuration: HTTPClientConfiguration = .init(), handler: Handler? = nil) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import class Foundation.NSLock
12+
13+
extension NSLock {
14+
/// Execute the given block while holding the lock.
15+
public func withLock<T> (_ body: () throws -> T) rethrows -> T {
16+
lock()
17+
defer { unlock() }
18+
return try body()
19+
}
20+
}

Sources/Basics/SQLiteBackedCache.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public final class SQLiteBackedCache<Value: Codable>: Closable {
2525
public let configuration: SQLiteBackedCacheConfiguration
2626

2727
private var state = State.idle
28-
private let stateLock = Lock()
28+
private let stateLock = NSLock()
2929

3030
private let jsonEncoder: JSONEncoder
3131
private let jsonDecoder: JSONDecoder

Sources/Commands/SwiftTestTool.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import ArgumentParser
1414
import Basics
1515
import Build
1616
import Dispatch
17+
import class Foundation.NSLock
1718
import class Foundation.ProcessInfo
1819
import PackageGraph
1920
import PackageModel
@@ -769,7 +770,7 @@ final class ParallelTestRunner {
769770
observabilityScope: self.observabilityScope
770771
)
771772
var output = ""
772-
let outputLock = Lock()
773+
let outputLock = NSLock()
773774
let start = DispatchTime.now()
774775
let success = testRunner.test(outputHandler: { _output in outputLock.withLock{ output += _output }})
775776
let duration = start.distance(to: .now())

Sources/PackageCollections/Storage/SQLitePackageCollectionsStorage.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Dispatch
1515
import struct Foundation.Data
1616
import class Foundation.JSONDecoder
1717
import class Foundation.JSONEncoder
18+
import class Foundation.NSLock
1819
import struct Foundation.URL
1920
import PackageModel
2021
import TSCBasic
@@ -36,22 +37,22 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
3637
private let decoder: JSONDecoder
3738

3839
private var state = State.idle
39-
private let stateLock = Lock()
40+
private let stateLock = NSLock()
4041

4142
private let cache = ThreadSafeKeyValueStore<Model.CollectionIdentifier, Model.Collection>()
4243

43-
// Lock helps prevent concurrency errors with transaction statements during e.g. `refreshCollections`,
44+
// NSLock helps prevent concurrency errors with transaction statements during e.g. `refreshCollections`,
4445
// since only one transaction is allowed per SQLite connection. We need transactions to speed up bulk updates.
4546
// TODO: we could potentially optimize this with db connection pool
46-
private let ftsLock = Lock()
47+
private let ftsLock = NSLock()
4748
// FTS not supported on some platforms; the code falls back to "slow path" in that case
4849
// marked internal for testing
4950
internal let useSearchIndices = ThreadSafeBox<Bool>()
5051

5152
// Targets have in-memory trie in addition to SQLite FTS as optimization
5253
private let targetTrie = Trie<CollectionPackage>()
5354
private var targetTrieReady: Bool?
54-
private let populateTargetTrieLock = Lock()
55+
private let populateTargetTrieLock = NSLock()
5556

5657
init(location: SQLite.Location? = nil, configuration: Configuration = .init(), observabilityScope: ObservabilityScope) {
5758
self.location = location ?? .path(localFileSystem.swiftPMCacheDirectory.appending(components: "package-collection.db"))

Sources/PackageCollections/Storage/Trie.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
import TSCBasic
14-
13+
import class Foundation.NSLock
1514
import PackageModel
1615

1716
struct Trie<Document: Hashable> {
1817
private typealias Node = TrieNode<Character, Document>
1918

2019
private let root: Node
21-
private let lock = Lock()
20+
private let lock = NSLock()
2221

2322
init() {
2423
self.root = Node()
@@ -183,11 +182,11 @@ private final class TrieNode<T: Hashable, Document: Hashable> {
183182

184183
/// The children of this node identified by their corresponding value.
185184
private var _children = [T: TrieNode<T, Document>]()
186-
private let childrenLock = Lock()
185+
private let childrenLock = NSLock()
187186

188187
/// If the path to this node forms a valid word, these are the documents where the word can be found.
189188
private var _documents = Set<Document>()
190-
private let documentsLock = Lock()
189+
private let documentsLock = NSLock()
191190

192191
var isLeaf: Bool {
193192
self.childrenLock.withLock {

Sources/PackageGraph/DependencyMirrors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public final class DependencyMirrors: Equatable {
1919
private var index: [String: String]
2020
private var reverseIndex: [String: [String]]
2121
private var visited: OrderedCollections.OrderedSet<String>
22-
private let lock = Lock()
22+
private let lock = NSLock()
2323

2424
public var mapping: [String: String] {
2525
self.lock.withLock {

Sources/PackageGraph/Pubgrub/PubgrubDependencyResolver.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import Basics
1414
import Dispatch
15+
import class Foundation.NSLock
1516
import OrderedCollections
1617
import PackageModel
1718
import TSCBasic
@@ -39,7 +40,7 @@ public struct PubgrubDependencyResolver {
3940
/// The current best guess for a solution satisfying all requirements.
4041
public private(set) var solution: PartialSolution
4142

42-
private let lock = Lock()
43+
private let lock = NSLock()
4344

4445
init(root: DependencyResolutionNode,
4546
overriddenPackages: [PackageReference: (version: BoundVersion, products: ProductFilter)] = [:],

Sources/SPMTestSupport/InMemoryGitRepository.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public final class InMemoryGitRepository {
6767
/// The file system in which this repository should be installed.
6868
private let fs: InMemoryFileSystem
6969

70-
private let lock = Lock()
70+
private let lock = NSLock()
7171

7272
/// Create a new repository at the given path and filesystem.
7373
public init(path: AbsolutePath, fs: InMemoryFileSystem) {

Sources/SPMTestSupport/MockPackageFingerprintStorage.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212

1313
import Basics
1414
import Dispatch
15+
import class Foundation.NSLock
1516
import PackageFingerprint
1617
import PackageModel
17-
import TSCBasic
1818

1919
public class MockPackageFingerprintStorage: PackageFingerprintStorage {
2020
private var packageFingerprints: [PackageIdentity: [Version: [Fingerprint.Kind: Fingerprint]]]
21-
private let lock = Lock()
21+
private let lock = NSLock()
2222

2323
public init(_ packageFingerprints: [PackageIdentity: [Version: [Fingerprint.Kind: Fingerprint]]] = [:]) {
2424
self.packageFingerprints = packageFingerprints

Sources/SPMTestSupport/MockRegistry.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class MockRegistry {
3131
private var packageVersions = [PackageIdentity: [String: InMemoryRegistryPackageSource]]()
3232
private var packagesSourceControlURLs = [PackageIdentity: [URL]]()
3333
private var sourceControlURLs = [URL: PackageIdentity]()
34-
private let packagesLock = Lock()
34+
private let packagesLock = NSLock()
3535

3636
public init(
3737
filesystem: FileSystem,

Sources/SPMTestSupport/MockWorkspace.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ public final class MockWorkspace {
777777
}
778778

779779
public final class MockWorkspaceDelegate: WorkspaceDelegate {
780-
private let lock = Lock()
780+
private let lock = NSLock()
781781
private var _events = [String]()
782782
private var _manifest: Manifest?
783783
private var _manifestLoadingDiagnostics: [Basics.Diagnostic]?

Sources/SPMTestSupport/Observability.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Basics
14-
import struct TSCBasic.Lock
1514
import struct TSCBasic.StringError
1615
import func XCTest.XCTFail
1716
import func XCTest.XCTAssertEqual

Sources/SourceControl/GitRepository.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import Basics
1414
import Dispatch
15+
import class Foundation.NSLock
1516
import TSCBasic
1617

1718
import enum TSCUtility.Git
@@ -331,7 +332,7 @@ public final class GitRepository: Repository, WorkingCheckout {
331332
private let git: GitShellHelper
332333

333334
// lock top protect concurrent modifications to the repository
334-
private let lock = Lock()
335+
private let lock = NSLock()
335336

336337
/// If this repo is a work tree repo (checkout) as opposed to a bare repo.
337338
private let isWorkingRepo: Bool

Sources/Workspace/DefaultPluginScriptRunner.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable {
413413

414414
// Set up a pipe for receiving messages from the plugin on its stdout.
415415
let stdoutPipe = Pipe()
416-
let stdoutLock = Lock()
416+
let stdoutLock = NSLock()
417417
stdoutPipe.fileHandleForReading.readabilityHandler = { fileHandle in
418418
// Receive the next message and pass it on to the delegate.
419419
stdoutLock.withLock {
@@ -448,7 +448,7 @@ public struct DefaultPluginScriptRunner: PluginScriptRunner, Cancellable {
448448

449449
// Set up a pipe for receiving free-form text output from the plugin on its stderr.
450450
let stderrPipe = Pipe()
451-
let stderrLock = Lock()
451+
let stderrLock = NSLock()
452452
var stderrData = Data()
453453
let stderrHandler = { (data: Data) in
454454
// Pass on any available data to the delegate.

Sources/Workspace/ResolvedFileWatcher.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import class Foundation.NSLock
1314
import PackageModel
1415
import PackageGraph
1516
import TSCBasic
@@ -22,7 +23,7 @@ import class TSCUtility.FSWatch
2223
final class ResolvedFileWatcher {
2324
private var fswatch: FSWatch!
2425
private var existingValue: ByteString?
25-
private let valueLock: Lock = Lock()
26+
private let valueLock = NSLock()
2627
private let resolvedFile: AbsolutePath
2728

2829
public func updateValue() {

Sources/Workspace/SourceControlPackageContainer.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import Basics
1414
import Dispatch
15+
import class Foundation.NSLock
1516
import PackageFingerprint
1617
import PackageGraph
1718
import PackageLoading
@@ -63,7 +64,7 @@ internal final class SourceControlPackageContainer: PackageContainer, CustomStri
6364

6465
/// The cached dependency information.
6566
private var dependenciesCache = [String: [ProductFilter: (Manifest, [Constraint])]] ()
66-
private var dependenciesCacheLock = Lock()
67+
private var dependenciesCacheLock = NSLock()
6768

6869
private var knownVersionsCache = ThreadSafeBox<[Version: String]>()
6970
private var manifestsCache = ThreadSafeKeyValueStore<String, Manifest>()

Sources/Workspace/Workspace+Configuration.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ extension Workspace.Configuration {
379379
private let fileSystem: FileSystem
380380

381381
private var _mirrors: DependencyMirrors
382-
private let lock = Lock()
382+
private let lock = NSLock()
383383

384384
/// The mirrors in this configuration
385385
public var mirrors: DependencyMirrors {
@@ -565,7 +565,7 @@ extension Workspace.Configuration {
565565
private let fileSystem: FileSystem
566566

567567
private var _configuration = RegistryConfiguration()
568-
private let lock = Lock()
568+
private let lock = NSLock()
569569

570570
/// The registry configuration
571571
public var configuration: RegistryConfiguration {

Sources/Workspace/Workspace.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ extension Workspace {
11751175
observabilityScope: ObservabilityScope,
11761176
completion: @escaping(Result<[AbsolutePath: Manifest], Error>) -> Void
11771177
) {
1178-
let lock = Lock()
1178+
let lock = NSLock()
11791179
let sync = DispatchGroup()
11801180
var rootManifests = [AbsolutePath: Manifest]()
11811181
Set(packages).forEach { package in

Tests/BasicsTests/CancellatorTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ fileprivate struct Worker {
395395
class ProcessStartedSemaphore {
396396
let term: String
397397
let underlying = DispatchSemaphore(value: 0)
398-
let lock = Lock()
398+
let lock = NSLock()
399399
var trapped = false
400400
var output = ""
401401

Tests/BasicsTests/ConcurrencyHelpersTests.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
@testable import Basics
14-
import TSCBasic
1514
import TSCTestSupport
1615
import XCTest
1716

@@ -23,7 +22,7 @@ final class ConcurrencyHelpersTest: XCTestCase {
2322
let sync = DispatchGroup()
2423

2524
var expected = [Int: Int]()
26-
let lock = Lock()
25+
let lock = NSLock()
2726

2827
let cache = ThreadSafeKeyValueStore<Int, Int>()
2928
for index in 0 ..< 1000 {
@@ -58,7 +57,7 @@ final class ConcurrencyHelpersTest: XCTestCase {
5857
let sync = DispatchGroup()
5958

6059
var expected = [Int]()
61-
let lock = Lock()
60+
let lock = NSLock()
6261

6362
let cache = ThreadSafeArrayStore<Int>()
6463
for _ in 0 ..< 1000 {
@@ -88,7 +87,7 @@ final class ConcurrencyHelpersTest: XCTestCase {
8887
let sync = DispatchGroup()
8988

9089
var winner: Int?
91-
let lock = Lock()
90+
let lock = NSLock()
9291

9392
let serial = DispatchQueue(label: "testThreadSafeBoxSerial")
9493

0 commit comments

Comments
 (0)