Skip to content

Commit f9cf27e

Browse files
committed
[PubGrub] Fix a potential deadlock when prefetching
The prefetching logic had a bug which sometimes leads to deadlock if prefetched container queries start calling the completion block while the main resolution logic is trying to fetch a new container that is NOT in the prefetching list (because it's new dependency). The main reason for this is that the container provider is using a serial queue for callbacks (which is questionable) but it's better to not make any assumptions about the provider and never run potentially blocking code in the compleition handler. Unfortunately, this is proving hard to unit test because this depends on network speed/latency etc. <rdar://problem/58644686>
1 parent 11ae0a7 commit f9cf27e

File tree

1 file changed

+11
-8
lines changed

1 file changed

+11
-8
lines changed

Sources/PackageGraph/Pubgrub.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import struct TSCUtility.Version
1212
import TSCBasic
1313
import struct PackageModel.PackageReference
14+
import Dispatch
1415

1516
/// A term represents a statement about a package that may be true or false.
1617
public struct Term: Equatable, Hashable {
@@ -1845,15 +1846,17 @@ private final class ContainerProvider {
18451846
_prefetchingContainers.insert(identifier)
18461847

18471848
provider.getContainer(for: identifier, skipUpdate: skipUpdate) { container in
1848-
self.fetchCondition.whileLocked {
1849-
// Update the structures and signal any thread waiting
1850-
// on prefetching to finish.
1851-
let pubGrubContainer = container.map {
1852-
PubGrubPackageContainer($0, pinsMap: self.pinsMap)
1849+
DispatchQueue.global().async {
1850+
self.fetchCondition.whileLocked {
1851+
// Update the structures and signal any thread waiting
1852+
// on prefetching to finish.
1853+
let pubGrubContainer = container.map {
1854+
PubGrubPackageContainer($0, pinsMap: self.pinsMap)
1855+
}
1856+
self._fetchedContainers[identifier] = pubGrubContainer
1857+
self._prefetchingContainers.remove(identifier)
1858+
self.fetchCondition.signal()
18531859
}
1854-
self._fetchedContainers[identifier] = pubGrubContainer
1855-
self._prefetchingContainers.remove(identifier)
1856-
self.fetchCondition.signal()
18571860
}
18581861
}
18591862
}

0 commit comments

Comments
 (0)