提交 c36177f4 编写于 作者: K Kevin Halverson

Merge pull request #2152 from KevinH-MS/CrossThreadCall

Use different mechanism for passing symbol reader to MTA...
......@@ -10,6 +10,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.EditAndContinue
[Guid("B69910A9-4AD6-475F-859A-5DC0B1072A5D")]
internal interface IENCSymbolReaderProvider
{
void GetSymbolReader(out IntPtr ppSymbolReaderMta);
void GetSymbolReader([MarshalAs(UnmanagedType.IUnknown)] out object ppSymbolReader);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.EditAndContinue.Interop
{
internal static class NativeMethods
{
private static Guid IID_IUnknown = new Guid(0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
[DllImport("ole32.dll")]
private static extern int CoMarshalInterThreadInterfaceInStream([In] ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] object pUnk, out IntPtr ppStm);
[DllImport("ole32.dll")]
private static extern int CoGetInterfaceAndReleaseStream(IntPtr pStm, [In] ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);
public static int GetStreamForObject(object pUnk, out IntPtr stream)
{
return CoMarshalInterThreadInterfaceInStream(ref IID_IUnknown, pUnk, out stream);
}
public static int GetObjectForStream(IntPtr stream, out object pUnk)
{
return CoGetInterfaceAndReleaseStream(stream, ref IID_IUnknown, out pUnk);
}
}
}
......@@ -23,6 +23,7 @@
using Microsoft.DiaSymReader;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices.Implementation.EditAndContinue.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Roslyn.Utilities;
......@@ -87,7 +88,7 @@ internal sealed class VsENCRebuildableProjectImpl
private ISymUnmanagedReader _pdbReader;
private IntPtr _pdbReaderMtaPointer;
private IntPtr _pdbReaderObjAsStream;
#endregion
......@@ -322,7 +323,7 @@ public int StopDebuggingPE()
_committedBaseline = null;
_activeStatementIds = null;
Debug.Assert((_pdbReader == null) == (_pdbReaderMtaPointer == IntPtr.Zero));
Debug.Assert((_pdbReaderObjAsStream == IntPtr.Zero) || (_pdbReader == null));
if (_pdbReader != null)
{
......@@ -330,8 +331,6 @@ public int StopDebuggingPE()
_pdbReader = null;
}
_pdbReaderMtaPointer = IntPtr.Zero;
// The HResult is ignored by the debugger.
return VSConstants.S_OK;
}
......@@ -926,20 +925,20 @@ public unsafe int BuildForEnc(object pUpdatePE)
Debug.Assert(_lastEditSessionSummary == ProjectAnalysisSummary.ValidInsignificantChanges ||
_lastEditSessionSummary == ProjectAnalysisSummary.ValidChanges);
var updater = (Interop.IDebugUpdateInMemoryPE2)pUpdatePE;
var updater = (IDebugUpdateInMemoryPE2)pUpdatePE;
if (_committedBaseline == null)
{
Interop.IENCDebugInfo debugInfo;
updater.GetENCDebugInfo(out debugInfo);
var symbolReaderProvider = (Interop.IENCSymbolReaderProvider)debugInfo;
symbolReaderProvider.GetSymbolReader(out _pdbReaderMtaPointer);
var hr = MarshalPdbReader(updater, out _pdbReaderObjAsStream);
if (hr != VSConstants.S_OK)
{
return hr;
}
_committedBaseline = EmitBaseline.CreateInitialBaseline(_metadata, GetBaselineEncDebugInfo);
}
// ISymUnmanagedReader can only be accessed from an MTA thread,
// so dispatch it to one of thread pool threads, which are MTA:
// ISymUnmanagedReader can only be accessed from an MTA thread,
// so dispatch it to one of thread pool threads, which are MTA.
var emitTask = Task.Factory.SafeStartNew(EmitProjectDelta, CancellationToken.None, TaskScheduler.Default);
Deltas delta;
......@@ -1050,9 +1049,17 @@ private EditAndContinueMethodDebugInformation GetBaselineEncDebugInfo(MethodDefi
if (_pdbReader == null)
{
Debug.Assert(_pdbReaderMtaPointer != IntPtr.Zero);
object pdbReaderObj = Marshal.GetObjectForIUnknown(_pdbReaderMtaPointer);
_pdbReader = (ISymUnmanagedReader)pdbReaderObj;
// Unmarshal the symbol reader (being marshalled cross thread from STA -> MTA).
Debug.Assert(_pdbReaderObjAsStream != IntPtr.Zero);
object pdbReaderObjMta;
int hr = NativeMethods.GetObjectForStream(_pdbReaderObjAsStream, out pdbReaderObjMta);
_pdbReaderObjAsStream = IntPtr.Zero;
if (hr != VSConstants.S_OK)
{
log.Write("Error unmarshaling object from stream.");
return default(EditAndContinueMethodDebugInformation);
}
_pdbReader = (ISymUnmanagedReader)pdbReaderObjMta;
}
int methodToken = MetadataTokens.GetToken(methodHandle);
......@@ -1138,6 +1145,33 @@ public int GetCurrentExceptionSpanPosition(uint id, VsTextSpan[] ptsNewPosition)
}
}
private static int MarshalPdbReader(IDebugUpdateInMemoryPE2 updater, out IntPtr pdbReaderPointer)
{
// ISymUnmanagedReader can only be accessed from an MTA thread, however, we need
// fetch the IUnknown instance (call IENCSymbolReaderProvider.GetSymbolReader) here
// in the STA. To further complicate things, we need to return synchronously from
// this method. Waiting for the MTA thread to complete so we can return synchronously
// blocks the STA thread, so we need to make sure the CLR doesn't try to marshal
// ISymUnmanagedReader calls made in an MTA back to the STA for execution (if this
// happens we'll be deadlocked). We'll use CoMarshalInterThreadInterfaceInStream to
// achieve this. First, we'll marshal the object in a Stream and pass a Stream pointer
// over to the MTA. In the MTA, we'll get the Stream from the pointer and unmarshal
// the object. The reader object was originally created on an MTA thread, and the
// instance we retrieved in the STA was a proxy. When we unmarshal the Stream in the
// MTA, it "unwraps" the proxy, allowing us to directly call the implementation.
// Another way to achieve this would be for the symbol reader to implement IAgileObject,
// but the symbol reader we use today does not. If that changes, we should consider
// removing this marshal/unmarshal code.
IENCDebugInfo debugInfo;
updater.GetENCDebugInfo(out debugInfo);
var symbolReaderProvider = (IENCSymbolReaderProvider)debugInfo;
object pdbReaderObjSta;
symbolReaderProvider.GetSymbolReader(out pdbReaderObjSta);
int hr = NativeMethods.GetStreamForObject(pdbReaderObjSta, out pdbReaderPointer);
Marshal.ReleaseComObject(pdbReaderObjSta);
return hr;
}
#region Testing
#if DEBUG
......
......@@ -24,6 +24,7 @@
<Compile Include="Implementation\AnalyzerDependencyConflict.cs" />
<Compile Include="Implementation\CompilationErrorTelemetry\CompilationErrorTelemetryIncrementalAnalyzer.cs" />
<Compile Include="Implementation\Diagnostics\VisualStudioVenusSpanMappingService.cs" />
<Compile Include="Implementation\EditAndContinue\Interop\NativeMethods.cs" />
<Compile Include="Implementation\Interop\IComWrapperFactory.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\AbstractSourceTreeItem.cs" />
<Compile Include="Implementation\Library\FindResults\TreeItems\MetadataDefinitionTreeItem.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册