Skip to content
This repository was archived by the owner on Nov 15, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
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
13 changes: 10 additions & 3 deletions main/OpenCover.Framework/Communication/CommunicationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,23 @@ private static void SendChunkAndWaitForConfirmation(int writeSize, IManagedCommu
mcb.InformationReadByProfiler.Reset();
}

private byte[] _data = null;
public byte[] HandleMemoryBlock(IManagedMemoryBlock mmb)
{
var data = new byte[mmb.BufferSize];
_data = _data ?? new byte[mmb.BufferSize];
mmb.ProfilerHasResults.Reset();

mmb.StreamAccessorResults.Seek(0, SeekOrigin.Begin);
mmb.StreamAccessorResults.Read(data, 0, mmb.BufferSize);
mmb.StreamAccessorResults.Read(_data, 0, mmb.BufferSize);

var nCount = (int)BitConverter.ToUInt32(_data, 0);
var dataSize = (nCount + 1)*sizeof (UInt32);
var newData = new byte[dataSize];
Buffer.BlockCopy(_data, 0, newData, 0, dataSize);

mmb.ResultsHaveBeenReceived.Set();
return data;

return newData;
}

public void Complete()
Expand Down
67 changes: 48 additions & 19 deletions main/OpenCover.Framework/Manager/MemoryManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,35 @@
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading;

namespace OpenCover.Framework.Manager
{
/// <summary>
/// Manages the blocks used for communcation and data between host and profiler
/// </summary>
public class MemoryManager : IMemoryManager
{
private string _namespace;
private string _key;
private readonly object lockObject = new object();
private readonly object _lockObject = new object();

private readonly IList<Tuple<IManagedCommunicationBlock, IManagedMemoryBlock>> _blocks = new List<Tuple<IManagedCommunicationBlock, IManagedMemoryBlock>>();

/// <summary>
///
/// </summary>
public class ManagedBlock
{
protected string Namespace;
protected string Key;

/// <summary>
/// Create a unique name
/// </summary>
/// <param name="name"></param>
/// <param name="id"></param>
/// <returns></returns>
protected string MakeName(string name, int id)
{
var newName = string.Format("{0}{1}{2}{3}", Namespace, name, Key, id);
Expand Down Expand Up @@ -61,17 +72,18 @@ internal ManagedMemoryBlock(string @namespace, string key, int bufferSize, int b
EventWaitHandleSecurity open = null;
MemoryMappedFileSecurity transparent = null;

if (servicePrincpal.Any())
var service = servicePrincpal.FirstOrDefault();
var currentIdentity = WindowsIdentity.GetCurrent();
if (service != null && currentIdentity != null)
{
var service = servicePrincpal.First();
open = new EventWaitHandleSecurity();
open.AddAccessRule(new EventWaitHandleAccessRule(WindowsIdentity.GetCurrent().Name, EventWaitHandleRights.FullControl, AccessControlType.Allow));
open.AddAccessRule(new EventWaitHandleAccessRule(currentIdentity.Name, EventWaitHandleRights.FullControl, AccessControlType.Allow));

// The event handles need more than just EventWaitHandleRights.Modify | EventWaitHandleRights.Synchronize to work
open.AddAccessRule(new EventWaitHandleAccessRule(service, EventWaitHandleRights.FullControl, AccessControlType.Allow));

transparent = new MemoryMappedFileSecurity();
transparent.AddAccessRule(new AccessRule<MemoryMappedFileRights>(WindowsIdentity.GetCurrent().Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow));
transparent.AddAccessRule(new AccessRule<MemoryMappedFileRights>(currentIdentity.Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow));
transparent.AddAccessRule(new AccessRule<MemoryMappedFileRights>(service, MemoryMappedFileRights.ReadWrite, AccessControlType.Allow));
}

Expand Down Expand Up @@ -143,15 +155,16 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize
EventWaitHandleSecurity open = null;
MemoryMappedFileSecurity transparent = null;

if (servicePrincpal.Any())
var service = servicePrincpal.FirstOrDefault();
var currentIdentity = WindowsIdentity.GetCurrent();
if (service != null && currentIdentity != null)
{
var service = servicePrincpal.First();
open = new EventWaitHandleSecurity();
open.AddAccessRule(new EventWaitHandleAccessRule(WindowsIdentity.GetCurrent().Name, EventWaitHandleRights.FullControl, AccessControlType.Allow));
open.AddAccessRule(new EventWaitHandleAccessRule(currentIdentity.Name, EventWaitHandleRights.FullControl, AccessControlType.Allow));
open.AddAccessRule(new EventWaitHandleAccessRule(service, EventWaitHandleRights.FullControl, AccessControlType.Allow));

transparent = new MemoryMappedFileSecurity();
transparent.AddAccessRule(new AccessRule<MemoryMappedFileRights>(WindowsIdentity.GetCurrent().Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow));
transparent.AddAccessRule(new AccessRule<MemoryMappedFileRights>(currentIdentity.Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow));
transparent.AddAccessRule(new AccessRule<MemoryMappedFileRights>(service, MemoryMappedFileRights.ReadWrite, AccessControlType.Allow));
}

Expand Down Expand Up @@ -200,32 +213,48 @@ public void Dispose()
}
}

private bool isIntialised = false;
private bool _isIntialised;

private string[] _servicePrincipal;

/// <summary>
/// Initialise the memory manager
/// </summary>
/// <param name="namespace"></param>
/// <param name="key"></param>
/// <param name="servicePrincipal"></param>
public void Initialise(string @namespace, string key, IEnumerable<string> servicePrincipal)
{
if (isIntialised) return;
if (_isIntialised) return;
_namespace = @namespace;
_key = key;
this._servicePrincipal = servicePrincipal.ToArray();
isIntialised = true;
_servicePrincipal = servicePrincipal.ToArray();
_isIntialised = true;
}

/// <summary>
/// Allocate a memory buffer
/// </summary>
/// <param name="bufferSize"></param>
/// <param name="bufferId"></param>
/// <returns></returns>
public Tuple<IManagedCommunicationBlock, IManagedMemoryBlock> AllocateMemoryBuffer(int bufferSize, uint bufferId)
{
if (!isIntialised) return null;
if (!_isIntialised) return null;

lock (lockObject)
lock (_lockObject)
{
var tuple = new Tuple<IManagedCommunicationBlock, IManagedMemoryBlock>(
new ManagedCommunicationBlock(_namespace, _key, bufferSize, (int)bufferId, this._servicePrincipal),
new ManagedMemoryBlock(_namespace, _key, bufferSize, (int)bufferId, this._servicePrincipal));
new ManagedCommunicationBlock(_namespace, _key, bufferSize, (int)bufferId, _servicePrincipal),
new ManagedMemoryBlock(_namespace, _key, bufferSize, (int)bufferId, _servicePrincipal));
_blocks.Add(tuple);
return tuple;
}
}

/// <summary>
/// get a pair of communication+memory blocks
/// </summary>
public IList<Tuple<IManagedCommunicationBlock, IManagedMemoryBlock>> GetBlocks
{
get { return _blocks; }
Expand All @@ -234,7 +263,7 @@ public IList<Tuple<IManagedCommunicationBlock, IManagedMemoryBlock>> GetBlocks
public void Dispose()
{
//Console.WriteLine("Disposing...");
lock (lockObject)
lock (_lockObject)
{
foreach(var block in _blocks)
{
Expand Down
16 changes: 13 additions & 3 deletions main/OpenCover.Framework/Manager/ProfilerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ private void ProcessMessages(WaitHandle[] handles)
var tasks = threadHandles
.Select((e, index) => new {Pair = e, Block = index / NumHandlesPerBlock})
.GroupBy(g => g.Block)
.Select(g => g.Select(a => a.Pair))
.Select(g => g.Select(a => a.Pair).ToList())
.Select(g => Task.Factory.StartNew(() =>
{
g.Select(h => h.Item1).ToList().ForEach(h => h.Set());
WaitHandle.WaitAll(g.Select(h => h.Item2).ToArray(), new TimeSpan(0, 0, 20));
WaitHandle.WaitAll(g.Select(h => h.Item2).ToArray<WaitHandle>(), new TimeSpan(0, 0, 20));
})).ToArray();
Task.WaitAll(tasks);

Expand Down Expand Up @@ -225,7 +225,7 @@ private WaitCallback ProcessBlock(IManagedCommunicationBlock communicationBlock,
{
return state =>
{
var processEvents = new WaitHandle[]
var processEvents = new []
{
communicationBlock.ProfilerRequestsInformation,
memoryBlock.ProfilerHasResults,
Expand All @@ -242,7 +242,17 @@ private WaitCallback ProcessBlock(IManagedCommunicationBlock communicationBlock,
break;
case 1:
var data = _communicationManager.HandleMemoryBlock(memoryBlock);
// don't let the queue get too big as using too much memory causes
// problems i.e. the target process closes down but the host takes
// ages to shutdown; this is a compromise.
_messageQueue.Enqueue(data);
if (_messageQueue.Count > 400)
{
do
{
Thread.Yield();
} while (_messageQueue.Count > 200);
}
break;
case 2:
threadTerminated.Set();
Expand Down
51 changes: 41 additions & 10 deletions main/OpenCover.Profiler/CodeCoverage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ DWORD CCodeCoverage::AppendProfilerEventMask(DWORD currentEventMask)
}
#endif

dwMask |= COR_PRF_MONITOR_THREADS;

return dwMask;
}

Expand All @@ -162,6 +164,10 @@ HRESULT STDMETHODCALLTYPE CCodeCoverage::Shutdown( void)
if (m_chainedProfiler != NULL)
m_chainedProfiler->Shutdown();

if (!m_tracingEnabled){
m_host.SendRemainingThreadBuffers();
}

WCHAR szExeName[MAX_PATH];
GetModuleFileNameW(NULL, szExeName, MAX_PATH);
RELTRACE(_T("::Shutdown - Nothing left to do but return S_OK(%s)"), szExeName);
Expand All @@ -176,12 +182,33 @@ HRESULT STDMETHODCALLTYPE CCodeCoverage::Shutdown( void)
/// </remarks>
static void __fastcall InstrumentPointVisit(ULONG seq)
{
CCodeCoverage::g_pProfiler->AddVisitPoint(seq);
CCodeCoverage::g_pProfiler->AddVisitPoint(seq);
}

void CCodeCoverage::AddVisitPoint(ULONG uniqueId)
{
m_host.AddVisitPointWithThreshold(uniqueId, m_threshold);
void __fastcall CCodeCoverage::AddVisitPoint(ULONG uniqueId)
{
if (uniqueId == 0) return;
if (m_threshold != 0)
{
ULONG& threshold = m_thresholds.at(uniqueId);
if (threshold >= m_threshold)
return;
threshold++;
}

if (m_tracingEnabled){
m_host.AddVisitPoint(uniqueId);
}
else {
m_host.AddVisitPointToThreadBuffer(uniqueId, IT_VisitPoint);
}
}

void CCodeCoverage::Resize(ULONG minSize) {
if (minSize > m_thresholds.size()){
ULONG newSize = ((minSize / BUFFER_SIZE) + 1) * BUFFER_SIZE;
m_thresholds.resize(newSize);
}
}

HRESULT STDMETHODCALLTYPE CCodeCoverage::ModuleLoadFinished(
Expand Down Expand Up @@ -262,7 +289,7 @@ HRESULT STDMETHODCALLTYPE CCodeCoverage::JITCompilationStarted(
// Instrument method
InstrumentMethod(moduleId, instumentedMethod, seqPoints, brPoints);

instumentedMethod.DumpIL();
//instumentedMethod.DumpIL();

CComPtr<IMethodMalloc> methodMalloc;
COM_FAIL_MSG_RETURN_ERROR(m_profilerInfo2->GetILFunctionBodyAllocator(moduleId, &methodMalloc),
Expand All @@ -287,9 +314,9 @@ HRESULT STDMETHODCALLTYPE CCodeCoverage::JITCompilationStarted(
if (m_threshold != 0)
{
if (seqPoints.size() > 0)
m_host.Resize(seqPoints.back().UniqueId + 1);
Resize(seqPoints.back().UniqueId + 1);
if (brPoints.size() > 0)
m_host.Resize(brPoints.back().UniqueId + 1);
Resize(brPoints.back().UniqueId + 1);
}
}
}
Expand All @@ -314,7 +341,8 @@ void CCodeCoverage::InstrumentMethod(ModuleID moduleId, Method& method, std::ve
void(__fastcall *pt)(ULONG) = GetInstrumentPointVisit();

InstructionList instructions;
CoverageInstrumentation::InsertFunctionCall(instructions, pvsig, (FPTR)pt, seqPoints[0].UniqueId);
if (seqPoints.size() > 0)
CoverageInstrumentation::InsertFunctionCall(instructions, pvsig, (FPTR)pt, seqPoints[0].UniqueId);
if (method.IsInstrumented(0, instructions)) return;

CoverageInstrumentation::AddBranchCoverage([pvsig, pt](InstructionList& instructions, ULONG uniqueId)->Instruction*
Expand All @@ -332,7 +360,8 @@ void CCodeCoverage::InstrumentMethod(ModuleID moduleId, Method& method, std::ve
mdMethodDef injectedVisitedMethod = RegisterSafeCuckooMethod(moduleId);

InstructionList instructions;
CoverageInstrumentation::InsertInjectedMethod(instructions, injectedVisitedMethod, seqPoints[0].UniqueId);
if (seqPoints.size() > 0)
CoverageInstrumentation::InsertInjectedMethod(instructions, injectedVisitedMethod, seqPoints[0].UniqueId);
if (method.IsInstrumented(0, instructions)) return;

CoverageInstrumentation::AddBranchCoverage([injectedVisitedMethod](InstructionList& instructions, ULONG uniqueId)->Instruction*
Expand All @@ -359,7 +388,7 @@ HRESULT CCodeCoverage::InstrumentMethodWith(ModuleID moduleId, mdToken functionT

instumentedMethod.InsertInstructionsAtOriginalOffset(0, instructions);

instumentedMethod.DumpIL();
//instumentedMethod.DumpIL();

// now to write the method back
CComPtr<IMethodMalloc> methodMalloc;
Expand All @@ -370,4 +399,6 @@ HRESULT CCodeCoverage::InstrumentMethodWith(ModuleID moduleId, mdToken functionT
instumentedMethod.WriteMethod(pNewMethod);
COM_FAIL_MSG_RETURN_ERROR(m_profilerInfo->SetILFunctionBody(moduleId, functionToken, (LPCBYTE)pNewMethod),
_T(" ::InstrumentMethodWith(...) => SetILFunctionBody => 0x%X"));

return S_OK;
}
Loading