Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispose FSharpProjectPackage properly #2058

Merged
merged 2 commits into from
Dec 20, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions vsintegration/src/FSharp.ProjectSystem.FSharp/Project.fs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ namespace rec Microsoft.VisualStudio.FSharp.ProjectSystem
let mutable mgr : IOleComponentManager = null
let mutable componentID = 0u

let locker = obj()

member this.RegisterForIdleTime() =
mgr <- this.GetService(typeof<SOleComponentManager>) :?> IOleComponentManager
if componentID = 0u && not (isNull mgr) then
Expand All @@ -203,10 +205,7 @@ namespace rec Microsoft.VisualStudio.FSharp.ProjectSystem
crinfo0.grfcadvf <- uint32 (_OLECADVF.olecadvfModal ||| _OLECADVF.olecadvfRedrawOff ||| _OLECADVF.olecadvfWarningsOff)
crinfo0.uIdleTimeInterval <- 1000u
crinfo.[0] <- crinfo0
let componentID_out = ref componentID
let _hr = mgr.FRegisterComponent(this, crinfo, componentID_out)
componentID <- componentID_out.Value
()
mgr.FRegisterComponent(this, crinfo, &componentID) |> ignore

/// This method loads a localized string based on the specified resource.

Expand Down Expand Up @@ -355,6 +354,15 @@ namespace rec Microsoft.VisualStudio.FSharp.ProjectSystem
pIdIco <- 400u
VSConstants.S_OK

override this.Dispose(disposing) =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this always happen on a UI thread? should we used interlocked compex on componentID to ensure it's not double disposed, or is double disposing Okay?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I mean double revoking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We guard revoking component by componentId and mgr so I think double revoking should not happen.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look thread safe. But there may be other mitigations in place.

However, as it stands two threads could both invoke mgr..FRevokeComponent(componentID) simultaneously.

Now that might not be a problem ...
for example if mgr..FRevokeComponent(componentID) is resilient to double revoke.

or
Something higher up the stack is ensuring that two threads can't dispose simultaneous ... for example something enforces that only a single thread at a time is doing the dispose.

to make it threadsafe either grabbing a lock and double checking or using Interlocked.CompareExchange to set componentID back to zero would probably work fine.

Copy link
Contributor Author

@dungpa dungpa Dec 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I added locking around revoking component bits.

Looking at the old code, the assumption is that the code should be invoked in a single thread https://github.com/dsyme/old-visualfsharp-clones/blob/8130b1429d3fd83a77a07df1bdc07751a6ee6577/vsintegration/src/vs/FsPkgs/FSharp.LanguageService/servicem.fs#L2069-L2078

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

Thank you.

Kevin

try
lock (locker) (fun _ ->
if componentID <> 0u && not (isNull mgr) then
mgr.FRevokeComponent(componentID) |> ignore
componentID <- 0u)
finally
base.Dispose(disposing)

interface Microsoft.VisualStudio.FSharp.Interactive.ITestVFSI with
member this.SendTextInteraction(s:string) =
GetToolWindowAsITestVFSI().SendTextInteraction(s)
Expand Down