Skip to content

Commit b2be3d5

Browse files
committed
Fcs/module reader: process queue when trying to get fcs write lock
1 parent e0321a3 commit b2be3d5

File tree

6 files changed

+43
-29
lines changed

6 files changed

+43
-29
lines changed

ReSharper.FSharp/src/FSharp.Common/src/Checker/FcsProjectProvider.fs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
8787

8888
/// Used to synchronize project model changes with FSharpItemsContainer
8989
let projectMarkModules = Dictionary<IPsiModule, IProjectMark>()
90+
9091
let outputPathToPsiModule = Dictionary<VirtualFileSystemPath, IPsiModule>()
9192

9293
/// Bool value forces FCS invalidation even when project options are not changed.
@@ -190,8 +191,8 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
190191
let createReferencedModule psiModule =
191192
ReferencedModule.create modulePathProvider psiModule
192193

193-
let createFcsProjectWithoutReferences psiModule: FcsProject =
194-
use lock = FcsReadWriteLock.WriteCookie.Create()
194+
let createFcsProjectWithoutReferences (psiModule: IPsiModule): FcsProject =
195+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
195196
let fcsProject = fcsProjectBuilder.BuildFcsProject(psiModule, psiModule.ContainingProjectModule.As())
196197
fcsProjectsWithoutReferences[psiModule] <- fcsProject
197198
projectsPsiModules.Add(psiModule.ContainingProjectModule, psiModule) |> ignore
@@ -319,7 +320,7 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
319320

320321
match getModuleProject psiModule with
321322
| FSharpProject project ->
322-
use lock = FcsReadWriteLock.WriteCookie.Create()
323+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
323324
let fcsProject = createFcsProject project psiModule
324325
Some fcsProject
325326

@@ -398,7 +399,7 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
398399
recentlyDeletedProjects.Remove(moduleId) |> ignore
399400

400401
let processDirtyFcsProjects () =
401-
use lock = FcsReadWriteLock.WriteCookie.Create()
402+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
402403
if dirtyModules.IsEmpty() && recentlyDeletedProjects.IsEmpty() then () else
403404

404405
logger.Trace("Start invalidating dirty modules")
@@ -450,7 +451,7 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
450451
member x.FcsProjectInvalidated = fcsProjectInvalidated
451452

452453
member private this.ProcessFSharpProjectLoaded(projectMark: IProjectMark) =
453-
use lock = FcsReadWriteLock.WriteCookie.Create()
454+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
454455

455456
tryGetValue projectMark projectsProjectMarks
456457
|> Option.iter invalidateProject
@@ -459,7 +460,7 @@ type FcsProjectProvider(lifetime: Lifetime, solution: ISolution, changeManager:
459460
let change = obj.ChangeMap.GetChange<ProjectModelChange>(solution)
460461
if isNull change || change.IsClosingSolution then () else
461462

462-
use lock = FcsReadWriteLock.WriteCookie.Create()
463+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
463464
match change with
464465
| :? ProjectReferenceChange as referenceChange ->
465466
invalidateProject referenceChange.ProjectToModuleReference.OwnerModule

ReSharper.FSharp/src/FSharp.Common/src/Checker/FcsReadWriteLock.fs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,41 @@ module JetBrains.ReSharper.Plugins.FSharp.Checker.FcsReadWriteLock
33

44
open System
55
open System.Threading
6+
open JetBrains.Application.Threading
67
open JetBrains.Diagnostics
8+
open JetBrains.ReSharper.Plugins.FSharp
79
open JetBrains.Util.Concurrency
810

9-
let private locks = ReentrantWriterPreferenceReadWriteLock()
11+
let private fcsLocks = ReentrantWriterPreferenceReadWriteLock()
1012

1113
let assertReadAccess () =
12-
Assertion.Assert(locks.IsReadLockAcquired(Thread.CurrentThread), "FcsReadWriteLock.assertReadAccess")
14+
Assertion.Assert(fcsLocks.IsReadLockAcquired(Thread.CurrentThread), "FcsReadWriteLock.assertReadAccess")
1315

1416
let assertWriteAccess () =
15-
Assertion.Assert(locks.IsWriteLockAcquired(Thread.CurrentThread), "FcsReadWriteLock.assertWriteAccess")
17+
Assertion.Assert(fcsLocks.IsWriteLockAcquired(Thread.CurrentThread), "FcsReadWriteLock.assertWriteAccess")
1618

1719

1820
[<Struct>]
1921
type ReadCookie =
2022
interface IDisposable with
21-
member this.Dispose() = locks.ReadLock.Release()
23+
member this.Dispose() = fcsLocks.ReadLock.Release()
2224

2325
static member Create(): IDisposable =
24-
locks.ReadLock.Acquire()
26+
fcsLocks.ReadLock.Acquire()
2527
new ReadCookie()
2628

2729
[<Struct>]
2830
type WriteCookie =
2931
interface IDisposable with
30-
member this.Dispose() = locks.WriteLock.Release()
32+
member this.Dispose() = fcsLocks.WriteLock.Release()
33+
34+
static member Create(locks: IShellLocks): IDisposable =
35+
let mutable acquired = false
36+
37+
while not acquired do
38+
if fcsLocks.WriteLock.TryAcquire(0) then
39+
acquired <- true
40+
elif locks.IsReadAccessAllowed() then
41+
FSharpAsyncUtil.ProcessEnqueuedReadRequests()
3142

32-
static member Create(): IDisposable =
33-
locks.WriteLock.Acquire()
3443
new WriteCookie()

ReSharper.FSharp/src/FSharp.Common/src/Shim/AssemblyReader/AssemblyReaderShim.fs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ open System.Collections.Concurrent
44
open System.Collections.Generic
55
open System.Text
66
open FSharp.Compiler.AbstractIL.ILBinaryReader
7+
open JetBrains.Application.Threading
78
open JetBrains.Application.changes
89
open JetBrains.DataFlow
910
open JetBrains.Lifetimes
@@ -70,7 +71,7 @@ module AssemblyReaderShim =
7071
type AssemblyReaderShim(lifetime: Lifetime, changeManager: ChangeManager, psiModules: IPsiModules,
7172
cache: FcsModuleReaderCommonCache, assemblyInfoShim: AssemblyInfoShim, checkerService: FcsCheckerService,
7273
fsOptionsProvider: FSharpOptionsProvider, symbolCache: ISymbolCache, solution: ISolution,
73-
logger: ILogger) as this =
74+
locks: IShellLocks, logger: ILogger) as this =
7475
inherit AssemblyReaderShimBase(lifetime, changeManager)
7576

7677
// todo: add experimental setting if/when available
@@ -234,7 +235,7 @@ type AssemblyReaderShim(lifetime: Lifetime, changeManager: ChangeManager, psiMod
234235
let markDirty (typePart: TypePart) =
235236
if not (isEnabled ()) then () else
236237

237-
use lock = FcsReadWriteLock.WriteCookie.Create()
238+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
238239

239240
let typeElement = typePart.TypeElement
240241
let psiModule = typeElement.Module
@@ -320,12 +321,12 @@ type AssemblyReaderShim(lifetime: Lifetime, changeManager: ChangeManager, psiMod
320321
member this.IsEnabled = isEnabled ()
321322

322323
member this.GetModuleReader(psiModule) =
323-
use lock = FcsReadWriteLock.WriteCookie.Create()
324+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
324325
invalidateDirty ()
325326
getOrCreateReaderFromModule psiModule
326327

327328
member this.InvalidateDirty() =
328-
use lock = FcsReadWriteLock.WriteCookie.Create()
329+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
329330
invalidateDirty ()
330331

331332
member this.InvalidateDirty(psiModule) =
@@ -402,7 +403,7 @@ type AssemblyReaderShim(lifetime: Lifetime, changeManager: ChangeManager, psiMod
402403
assemblyReadersByPath.ContainsKey(path)
403404

404405
member this.InvalidateAll(reason) =
405-
use lock = FcsReadWriteLock.WriteCookie.Create()
406+
use lock = FcsReadWriteLock.WriteCookie.Create(locks)
406407
invalidateAllReason <- Some reason
407408

408409
member this.HasDirtyTypes =

ReSharper.FSharp/src/FSharp.Psi/src/Resolve/FcsResolvedSymbolsCache.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using FSharp.Compiler.Symbols;
66
using JetBrains.Annotations;
77
using JetBrains.Application.Progress;
8+
using JetBrains.Application.Threading;
89
using JetBrains.Diagnostics;
910
using JetBrains.DocumentManagers.impl;
1011
using JetBrains.Lifetimes;
@@ -24,6 +25,7 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Resolve
2425
[SolutionComponent]
2526
public class FcsResolvedSymbolsCache : IPsiSourceFileCache, IFcsResolvedSymbolsCache
2627
{
28+
private readonly IShellLocks myLocks;
2729
public IPsiModules PsiModules { get; }
2830
public FcsCheckerService CheckerService { get; }
2931
public IFcsProjectProvider FcsProjectProvider { get; }
@@ -37,8 +39,9 @@ public class FcsResolvedSymbolsCache : IPsiSourceFileCache, IFcsResolvedSymbolsC
3739

3840
public FcsResolvedSymbolsCache(Lifetime lifetime, FcsCheckerService checkerService, IPsiModules psiModules,
3941
IFcsProjectProvider fcsProjectProvider, AssemblyReaderShim assemblyReaderShim,
40-
FSharpScriptPsiModulesProvider scriptPsiModulesProvider)
42+
FSharpScriptPsiModulesProvider scriptPsiModulesProvider, IShellLocks locks)
4143
{
44+
myLocks = locks;
4245
PsiModules = psiModules;
4346
CheckerService = checkerService;
4447
FcsProjectProvider = fcsProjectProvider;
@@ -59,7 +62,7 @@ private void Invalidate(Tuple<IPsiModule, FcsProject> project)
5962

6063
public void Invalidate(IPsiModule psiModule)
6164
{
62-
using var _ = FcsReadWriteLock.WriteCookie.Create();
65+
using var _ = FcsReadWriteLock.WriteCookie.Create(myLocks);
6366
{
6467
InvalidateReferencingModules(psiModule);
6568
if (PsiModulesCaches.TryGetValue(psiModule, out var symbols) && symbols.FcsProject is { } fcsProject)
@@ -101,7 +104,7 @@ protected virtual void Invalidate(IPsiSourceFile sourceFile)
101104

102105
public void MarkAsDirty(IPsiSourceFile sourceFile)
103106
{
104-
using var _ = FcsReadWriteLock.WriteCookie.Create();
107+
using var _ = FcsReadWriteLock.WriteCookie.Create(myLocks);
105108
{
106109
if (IsApplicable(sourceFile))
107110
myDirtyFiles.Add(sourceFile);
@@ -135,7 +138,7 @@ public void Merge(IPsiSourceFile sourceFile, object builtPart)
135138

136139
public void Drop(IPsiSourceFile sourceFile)
137140
{
138-
using var _ = FcsReadWriteLock.WriteCookie.Create();
141+
using var _ = FcsReadWriteLock.WriteCookie.Create(myLocks);
139142
{
140143
if (PsiModulesCaches.IsEmpty())
141144
return;
@@ -172,7 +175,7 @@ private void InvalidateDirty()
172175

173176
public void SyncUpdate(bool underTransaction)
174177
{
175-
using var _ = FcsReadWriteLock.WriteCookie.Create();
178+
using var _ = FcsReadWriteLock.WriteCookie.Create(myLocks);
176179
InvalidateDirty();
177180
}
178181

@@ -200,7 +203,7 @@ private FcsModuleResolvedSymbols GetModuleResolvedSymbols(IPsiSourceFile sourceF
200203
if (psiModule.IsMiscFilesProjectModule() && !(psiModule is SandboxPsiModule))
201204
return FcsModuleResolvedSymbols.Empty;
202205

203-
using var _ = FcsReadWriteLock.WriteCookie.Create();
206+
using var _ = FcsReadWriteLock.WriteCookie.Create(myLocks);
204207
{
205208
FcsProjectProvider.InvalidateDirty();
206209

ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Daemon/AssemblyReaderTest.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ open NUnit.Framework
2020

2121
[<SolutionComponent>]
2222
type TestAssemblyReaderShim(lifetime, changeManager, psiModules, cache, assemblyInfoShim, checkerService,
23-
fsOptionsProvider, symbolCache, solution, logger) =
23+
fsOptionsProvider, symbolCache, solution, locks, logger) =
2424
inherit AssemblyReaderShim(lifetime, changeManager, psiModules, cache, assemblyInfoShim, checkerService,
25-
fsOptionsProvider, symbolCache, solution, logger)
25+
fsOptionsProvider, symbolCache, solution, locks, logger)
2626

2727
let mutable projectPath = VirtualFileSystemPath.GetEmptyPathFor(InteractionContext.SolutionContext)
2828
let mutable projectPsiModule = null

ReSharper.FSharp/test/src/FSharp.Tests.Common/src/Common.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ type FSharpExperimentalFeatureAttribute(feature: ExperimentalFeature) =
128128

129129

130130
[<SolutionComponent>]
131-
type TestFSharpResolvedSymbolsCache(lifetime, checkerService, psiModules, fcsProjectProvider, assemblyReaderShim, scriptModuleProvider) =
132-
inherit FcsResolvedSymbolsCache(lifetime, checkerService, psiModules, fcsProjectProvider, assemblyReaderShim, scriptModuleProvider)
131+
type TestFSharpResolvedSymbolsCache(lifetime, checkerService, psiModules, fcsProjectProvider, assemblyReaderShim, scriptModuleProvider, locks) =
132+
inherit FcsResolvedSymbolsCache(lifetime, checkerService, psiModules, fcsProjectProvider, assemblyReaderShim, scriptModuleProvider, locks)
133133

134134
override x.Invalidate _ =
135135
x.PsiModulesCaches.Clear()

0 commit comments

Comments
 (0)