From eb8d0cff55aa523b7715b28838b90a38f72337b3 Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Thu, 22 Dec 2016 00:23:39 -0800 Subject: [PATCH] Fix threading for register for idle time (#2073) * Make ProjectSystem.RegisterForIdleTime threadsafe * Better --- simpler fix --- .../FSharp.ProjectSystem.FSharp/Project.fs | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs b/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs index 4ab96ae538e..732758bac64 100644 --- a/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs +++ b/vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs @@ -190,23 +190,29 @@ namespace rec Microsoft.VisualStudio.FSharp.ProjectSystem // FSI-LINKAGE-POINT: unsited init do Microsoft.VisualStudio.FSharp.Interactive.Hooks.fsiConsoleWindowPackageCtorUnsited (this :> Package) - let mutable mgr : IOleComponentManager = null + // Get the ComponentManager one time at the start + let mgr : IOleComponentManager = this.GetService(typeof) :?> IOleComponentManager + let mutable componentID = 0u - let locker = obj() + let thisLock = obj() member this.RegisterForIdleTime() = - mgr <- this.GetService(typeof) :?> IOleComponentManager - if componentID = 0u && not (isNull mgr) then - let crinfo = Array.zeroCreate(1) - let mutable crinfo0 = crinfo.[0] - crinfo0.cbSize <- Marshal.SizeOf(typeof) |> uint32 - crinfo0.grfcrf <- uint32 (_OLECRF.olecrfNeedIdleTime ||| _OLECRF.olecrfNeedPeriodicIdleTime) - crinfo0.grfcadvf <- uint32 (_OLECADVF.olecadvfModal ||| _OLECADVF.olecadvfRedrawOff ||| _OLECADVF.olecadvfWarningsOff) - crinfo0.uIdleTimeInterval <- 1000u - crinfo.[0] <- crinfo0 - mgr.FRegisterComponent(this, crinfo, &componentID) |> ignore - + + if not (isNull mgr) && componentID = 0u then + lock (thisLock) (fun _ -> + if componentID = 0u then + let crinfo = Array.zeroCreate(1) + let mutable crinfo0 = crinfo.[0] + crinfo0.cbSize <- Marshal.SizeOf(typeof) |> uint32 + crinfo0.grfcrf <- uint32 (_OLECRF.olecrfNeedIdleTime ||| _OLECRF.olecrfNeedPeriodicIdleTime) + crinfo0.grfcadvf <- uint32 (_OLECADVF.olecadvfModal ||| _OLECADVF.olecadvfRedrawOff ||| _OLECADVF.olecadvfWarningsOff) + crinfo0.uIdleTimeInterval <- 1000u + crinfo.[0] <- crinfo0 + + mgr.FRegisterComponent(this, crinfo, &componentID) |> ignore + ) + /// This method loads a localized string based on the specified resource. /// Resource to load @@ -358,11 +364,12 @@ namespace rec Microsoft.VisualStudio.FSharp.ProjectSystem VSConstants.S_OK override this.Dispose(disposing) = - try - lock (locker) (fun _ -> - if componentID <> 0u && not (isNull mgr) then - mgr.FRevokeComponent(componentID) |> ignore - componentID <- 0u) + try + if not (isNull mgr) && componentID <> 0u then + lock (thisLock) (fun _ -> + if componentID <> 0u then + mgr.FRevokeComponent(componentID) |> ignore + componentID <- 0u) finally base.Dispose(disposing) @@ -379,7 +386,7 @@ namespace rec Microsoft.VisualStudio.FSharp.ProjectSystem override this.FDoIdle(grfidlef:uint32) = // see e.g "C:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Common\IDL\olecm.idl" for details //Trace.Print("CurrentDirectoryDebug", (fun () -> sprintf "curdir='%s'\n" (System.IO.Directory.GetCurrentDirectory()))) // can be useful for watching how GetCurrentDirectory changes - let periodic = (grfidlef &&& (uint32 _OLEIDLEF.oleidlefPeriodic)) <> 0u + let periodic = (grfidlef &&& (uint32 _OLEIDLEF.oleidlefPeriodic)) <> 0u if periodic && not (isNull mgr) && mgr.FContinueIdle() <> 0 then TaskReporterIdleRegistration.DoIdle(mgr) else