@@ -553,8 +553,19 @@ public class InMemoryFileSystem: FileSystem {
553553 /// tests.
554554 private let lock = Lock ( )
555555
556- /// Exclusive file system lock vended to clients through `withLock()`.
556+ private var lockFiles = Dictionary < AbsolutePath , WeakReference < DispatchQueue > > ( )
557+ /// Used to access lockFiles in a thread safe manner.
557558 private let lockFilesLock = Lock ( )
559+
560+ /// Exclusive file system lock vended to clients through `withLock()`.
561+ // Used to ensure that DispatchQueues are releassed when they are no longer in use.
562+ private struct WeakReference < Value: AnyObject > {
563+ weak var reference : Value ?
564+
565+ init ( _ value: Value ? ) {
566+ self . reference = value
567+ }
568+ }
558569
559570 public init ( ) {
560571 root = Node ( . directory( DirectoryContents ( ) ) )
@@ -895,8 +906,27 @@ public class InMemoryFileSystem: FileSystem {
895906 }
896907
897908 public func withLock< T> ( on path: AbsolutePath , type: FileLock . LockType = . exclusive, _ body: ( ) throws -> T ) throws -> T {
898- // FIXME: Lock individual files once resolving symlinks is thread-safe.
899- return try lockFilesLock. withLock ( body)
909+ let fileQueue : DispatchQueue = try lockFilesLock. withLock {
910+
911+ let resolvedPath : AbsolutePath
912+
913+ // FIXME: resolving symlinks is not yet thread safe
914+ if case let . symlink( destination) = try getNode ( path) ? . contents {
915+ resolvedPath = AbsolutePath ( destination, relativeTo: path. parentDirectory)
916+ } else {
917+ resolvedPath = path
918+ }
919+
920+ if let queueReference = lockFiles [ resolvedPath] , let queue = queueReference. reference {
921+ return queue
922+ } else {
923+ let queue = DispatchQueue ( label: " org.swift.swiftpm.in-memory-file-system.file-queue " , attributes: . concurrent)
924+ lockFiles [ resolvedPath] = WeakReference ( queue)
925+ return queue
926+ }
927+ }
928+
929+ return try fileQueue. sync ( flags: type == . exclusive ? . barrier : . init( ) , execute: body)
900930 }
901931}
902932
0 commit comments