@@ -552,9 +552,20 @@ public class InMemoryFileSystem: FileSystem {
552552 /// reality, the only practical use for InMemoryFileSystem is for unit
553553 /// tests.
554554 private let lock = Lock ( )
555+ /// A map that keeps weak references to all locked files.
556+ private var lockFiles = Dictionary < AbsolutePath , WeakReference < DispatchQueue > > ( )
557+ /// Used to access lockFiles in a thread safe manner.
558+ private let lockFilesLock = Lock ( )
555559
556560 /// Exclusive file system lock vended to clients through `withLock()`.
557- private let lockFilesLock = Lock ( )
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,25 @@ 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 resolvedPath : AbsolutePath = try lock. withLock {
910+ if case let . symlink( destination) = try getNode ( path) ? . contents {
911+ return AbsolutePath ( destination, relativeTo: path. parentDirectory)
912+ } else {
913+ return path
914+ }
915+ }
916+
917+ let fileQueue : DispatchQueue = lockFilesLock. withLock {
918+ if let queueReference = lockFiles [ resolvedPath] , let queue = queueReference. reference {
919+ return queue
920+ } else {
921+ let queue = DispatchQueue ( label: " org.swift.swiftpm.in-memory-file-system.file-queue " , attributes: . concurrent)
922+ lockFiles [ resolvedPath] = WeakReference ( queue)
923+ return queue
924+ }
925+ }
926+
927+ return try fileQueue. sync ( flags: type == . exclusive ? . barrier : . init( ) , execute: body)
900928 }
901929}
902930
0 commit comments