Skip to content

Commit 325197c

Browse files
committed
Remove the last usage of DispatchSemaphore in favor of native concurrency primitives
This avoids spinning up one thread to synchronize access to cached build systems.
1 parent 40dcb7c commit 325197c

File tree

3 files changed

+31
-46
lines changed

3 files changed

+31
-46
lines changed

Sources/SWBBuildSystem/BuildOperation.swift

+29-31
Original file line numberDiff line numberDiff line change
@@ -432,20 +432,6 @@ package final class BuildOperation: BuildSystemOperation {
432432

433433
let dbPath = persistent ? buildDescription.buildDatabasePath : Path("")
434434

435-
func saveBuildDebuggingData(from sourcePath: Path, to filename: String, type: String, debuggingDataPath: Path?) {
436-
guard let debuggingDataPath else {
437-
return
438-
}
439-
do {
440-
try fs.createDirectory(debuggingDataPath, recursive: true)
441-
let savedPath = debuggingDataPath.join(filename)
442-
try fs.copy(sourcePath, to: savedPath)
443-
self.buildOutputDelegate.note("build debugging is enabled, \(type): '\(savedPath.str)'")
444-
} catch {
445-
self.buildOutputDelegate.warning("unable to preserve \(type) for post-mortem debugging: \(error)")
446-
}
447-
}
448-
449435
// Enable build debugging, if requested.
450436
let traceFile: Path?
451437
let debuggingDataPath: Path?
@@ -501,6 +487,33 @@ package final class BuildOperation: BuildSystemOperation {
501487
self.buildOutputDelegate.error("unable to retrieve additional environment variables via the EnvironmentExtensionPoint.")
502488
}
503489

490+
// If we use a cached build system, be sure to release it on build completion.
491+
if userPreferences.enableBuildSystemCaching {
492+
// Get the build system to use, keyed by the directory containing the (sole) database.
493+
let entry = cachedBuildSystems.getOrInsert(buildDescription.buildDatabasePath.dirname, { SystemCacheEntry() })
494+
return await entry.lock.withLock { [buildEnvironment] _ in
495+
await _build(cacheEntry: entry, dbPath: dbPath, traceFile: traceFile, debuggingDataPath: debuggingDataPath, buildEnvironment: buildEnvironment)
496+
}
497+
} else {
498+
return await _build(cacheEntry: nil, dbPath: dbPath, traceFile: traceFile, debuggingDataPath: debuggingDataPath, buildEnvironment: buildEnvironment)
499+
}
500+
}
501+
502+
private func saveBuildDebuggingData(from sourcePath: Path, to filename: String, type: String, debuggingDataPath: Path?) {
503+
guard let debuggingDataPath else {
504+
return
505+
}
506+
do {
507+
try fs.createDirectory(debuggingDataPath, recursive: true)
508+
let savedPath = debuggingDataPath.join(filename)
509+
try fs.copy(sourcePath, to: savedPath)
510+
self.buildOutputDelegate.note("build debugging is enabled, \(type): '\(savedPath.str)'")
511+
} catch {
512+
self.buildOutputDelegate.warning("unable to preserve \(type) for post-mortem debugging: \(error)")
513+
}
514+
}
515+
516+
private func _build(cacheEntry entry: SystemCacheEntry?, dbPath: Path, traceFile: Path?, debuggingDataPath: Path?, buildEnvironment: [String: String]) async -> BuildOperationEnded.Status {
504517
let algorithm: BuildSystem.SchedulerAlgorithm = {
505518
if let algorithmString = UserDefaults.schedulerAlgorithm {
506519
if let algorithm = BuildSystem.SchedulerAlgorithm(rawValue: algorithmString) {
@@ -517,13 +530,7 @@ package final class BuildOperation: BuildSystemOperation {
517530
// Create the low-level build system.
518531
let adaptor: OperationSystemAdaptor
519532
let system: BuildSystem
520-
521-
// If we use a cached build system, be sure to release it on build completion.
522-
var cacheEntry: SystemCacheEntry? = nil
523-
defer {
524-
cacheEntry?.lock.signal()
525-
}
526-
533+
527534
let llbQoS: SWBLLBuild.BuildSystem.QualityOfService?
528535
switch request.qos {
529536
case .default: llbQoS = .default
@@ -533,16 +540,7 @@ package final class BuildOperation: BuildSystemOperation {
533540
default: llbQoS = nil
534541
}
535542

536-
if userPreferences.enableBuildSystemCaching {
537-
// Get the build system to use, keyed by the directory containing the (sole) database.
538-
let key = buildDescription.buildDatabasePath.dirname
539-
let entry = cachedBuildSystems.getOrInsert(key) { SystemCacheEntry() }
540-
cacheEntry = entry
541-
542-
// Wait for exclusive lock on this cache entry to prevent concurrent
543-
// use/free of accompanying objects.
544-
await entry.lock.wait()
545-
543+
if let entry {
546544
// If the entry is valid, reuse it.
547545
if let cachedAdaptor = entry.adaptor, entry.environment == buildEnvironment, entry.buildDescription! === buildDescription, entry.llbQoS == llbQoS {
548546
adaptor = cachedAdaptor

Sources/SWBBuildSystem/BuildSystemCache.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ extension HeavyCache: BuildSystemCache where Key == Path, Value == SystemCacheEn
2626

2727
package final class SystemCacheEntry: CacheableValue {
2828
/// Lock that must be held by the active operation using this cache entry.
29-
let lock = SWBDispatchSemaphore(value: 1)
29+
let lock = AsyncLockedValue(())
3030

3131
/// The environment in use.
3232
var environment: [String: String]? = nil

Sources/SWBUtil/SWBDispatch.swift

+1-14
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ extension SWBDispatchData: RandomAccessCollection {
124124
}
125125

126126
/// Thin wrapper for `DispatchSemaphore` to isolate it from the rest of the codebase and help migration away from it.
127-
public final class SWBDispatchSemaphore: Sendable {
127+
internal final class SWBDispatchSemaphore: Sendable {
128128
private let semaphore: DispatchSemaphore
129129

130130
public init(value: Int) {
@@ -141,19 +141,6 @@ public final class SWBDispatchSemaphore: Sendable {
141141
semaphore.wait()
142142
}
143143
}
144-
145-
/// Waits for the semaphore.
146-
///
147-
/// - note: This spawns a background thread to wait for the semaphore in order to avoid blocking the caller.
148-
public func wait() async {
149-
await withCheckedContinuation { continuation in
150-
let semaphore = self.semaphore
151-
Thread.detachNewThread {
152-
semaphore.wait()
153-
continuation.resume()
154-
}
155-
}
156-
}
157144
}
158145

159146
/// Thin wrapper for `DispatchGroup` to isolate it from the rest of the codebase and help migration away from it.

0 commit comments

Comments
 (0)