From 932479a15b1775f9fec5ef6f079c15004a233266 Mon Sep 17 00:00:00 2001 From: sawilde Date: Sat, 29 Aug 2015 11:13:44 +1000 Subject: [PATCH 01/19] #329 - use a semaphore to act as a sync object around shared memory availability --- .../Manager/MemoryManager.cs | 103 ++++++++++++------ .../ProfilerCommunication.cpp | 34 +++++- .../ProfilerCommunication.h | 2 + main/OpenCover.Profiler/SharedMemory.cpp | 2 +- main/OpenCover.Profiler/Synchronization.h | 33 ++++++ 5 files changed, 136 insertions(+), 38 deletions(-) diff --git a/main/OpenCover.Framework/Manager/MemoryManager.cs b/main/OpenCover.Framework/Manager/MemoryManager.cs index 7115905ef..34bc3f070 100644 --- a/main/OpenCover.Framework/Manager/MemoryManager.cs +++ b/main/OpenCover.Framework/Manager/MemoryManager.cs @@ -57,6 +57,8 @@ internal class ManagedMemoryBlock : ManagedBlock, IManagedMemoryBlock public int BufferSize { get; private set; } public byte[] Buffer { get; private set; } + private readonly Semaphore _semaphore; + /// /// Gets an ACL for unit test purposes /// @@ -72,46 +74,56 @@ internal ManagedMemoryBlock(string @namespace, string key, int bufferSize, int b Namespace = @namespace; Key = key; - EventWaitHandleSecurity open = null; - MemoryMappedFileSecurity transparent = null; + EventWaitHandleSecurity handleSecurity = null; + MemoryMappedFileSecurity memSecurity = null; + SemaphoreSecurity semaphoreSecurity = null; - var service = servicePrincpal.FirstOrDefault(); + var serviceIdentity = servicePrincpal.FirstOrDefault(); var currentIdentity = WindowsIdentity.GetCurrent(); - if (service != null && currentIdentity != null) + if (serviceIdentity != null && currentIdentity != null) { - open = new EventWaitHandleSecurity(); - open.AddAccessRule(new EventWaitHandleAccessRule(currentIdentity.Name, EventWaitHandleRights.FullControl, AccessControlType.Allow)); + handleSecurity = new EventWaitHandleSecurity(); + handleSecurity.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)); + handleSecurity.AddAccessRule(new EventWaitHandleAccessRule(serviceIdentity, EventWaitHandleRights.FullControl, AccessControlType.Allow)); + + memSecurity = new MemoryMappedFileSecurity(); + memSecurity.AddAccessRule(new AccessRule(currentIdentity.Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow)); + memSecurity.AddAccessRule(new AccessRule(serviceIdentity, MemoryMappedFileRights.ReadWrite, AccessControlType.Allow)); - transparent = new MemoryMappedFileSecurity(); - transparent.AddAccessRule(new AccessRule(currentIdentity.Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow)); - transparent.AddAccessRule(new AccessRule(service, MemoryMappedFileRights.ReadWrite, AccessControlType.Allow)); + semaphoreSecurity = new SemaphoreSecurity(); + semaphoreSecurity.AddAccessRule(new SemaphoreAccessRule(currentIdentity.Name, SemaphoreRights.FullControl, AccessControlType.Allow)); + semaphoreSecurity.AddAccessRule(new SemaphoreAccessRule(serviceIdentity, SemaphoreRights.FullControl, AccessControlType.Allow)); } bool createdNew; ProfilerHasResults = new EventWaitHandle( false, - EventResetMode.ManualReset, - MakeName(@"\OpenCover_Profiler_Communication_SendResults_Event_", bufferId), + EventResetMode.ManualReset, + MakeName(@"\OpenCover_Profiler_Results_SendResults_Event_", bufferId), out createdNew, - open); + handleSecurity); ResultsHaveBeenReceived = new EventWaitHandle( false, - EventResetMode.ManualReset, - MakeName(@"\OpenCover_Profiler_Communication_ReceiveResults_Event_", bufferId), + EventResetMode.ManualReset, + MakeName(@"\OpenCover_Profiler_Results_ReceiveResults_Event_", bufferId), + out createdNew, + handleSecurity); + + _semaphore = new Semaphore(0, 2, + MakeName(@"\OpenCover_Profiler_Results_Semaphore_", bufferId), out createdNew, - open); + semaphoreSecurity); _mmfResults = MemoryMappedFile.CreateNew( MakeName(@"\OpenCover_Profiler_Results_MemoryMapFile_", bufferId), bufferSize, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, - transparent, + memSecurity, HandleInheritability.Inheritable); Buffer = new byte[bufferSize]; @@ -125,8 +137,13 @@ internal ManagedMemoryBlock(string @namespace, string key, int bufferSize, int b public void Dispose() { Debug.WriteLine("*** disposing memory block ***"); - StreamAccessorResults.Dispose(); - _mmfResults.Dispose(); + _semaphore.Do(s => + { + s.Release(1); + s.Dispose(); + }); + StreamAccessorResults.Do(r => r.Dispose()); + _mmfResults.Do(r => r.Dispose()); } } @@ -143,6 +160,7 @@ internal class ManagedCommunicationBlock : ManagedBlock, IManagedCommunicationBl public byte[] DataCommunication { get; private set; } public GCHandle PinnedDataCommunication { get; private set; } + private readonly Semaphore _semaphore; /// /// Gets an ACL for unit test purposes /// @@ -159,20 +177,25 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize Namespace = @namespace; Key = key; - EventWaitHandleSecurity open = null; - MemoryMappedFileSecurity transparent = null; + EventWaitHandleSecurity eventSecurity = null; + MemoryMappedFileSecurity memorySecurity = null; - var service = servicePrincpal.FirstOrDefault(); + var serviceIdentity = servicePrincpal.FirstOrDefault(); var currentIdentity = WindowsIdentity.GetCurrent(); - if (service != null && currentIdentity != null) + SemaphoreSecurity semaphoreSecurity = null; + if (serviceIdentity != null && currentIdentity != null) { - open = new EventWaitHandleSecurity(); - open.AddAccessRule(new EventWaitHandleAccessRule(currentIdentity.Name, EventWaitHandleRights.FullControl, AccessControlType.Allow)); - open.AddAccessRule(new EventWaitHandleAccessRule(service, EventWaitHandleRights.FullControl, AccessControlType.Allow)); + eventSecurity = new EventWaitHandleSecurity(); + eventSecurity.AddAccessRule(new EventWaitHandleAccessRule(currentIdentity.Name, EventWaitHandleRights.FullControl, AccessControlType.Allow)); + eventSecurity.AddAccessRule(new EventWaitHandleAccessRule(serviceIdentity, EventWaitHandleRights.FullControl, AccessControlType.Allow)); + + memorySecurity = new MemoryMappedFileSecurity(); + memorySecurity.AddAccessRule(new AccessRule(currentIdentity.Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow)); + memorySecurity.AddAccessRule(new AccessRule(serviceIdentity, MemoryMappedFileRights.ReadWrite, AccessControlType.Allow)); - transparent = new MemoryMappedFileSecurity(); - transparent.AddAccessRule(new AccessRule(currentIdentity.Name, MemoryMappedFileRights.FullControl, AccessControlType.Allow)); - transparent.AddAccessRule(new AccessRule(service, MemoryMappedFileRights.ReadWrite, AccessControlType.Allow)); + semaphoreSecurity = new SemaphoreSecurity(); + semaphoreSecurity.AddAccessRule(new SemaphoreAccessRule(currentIdentity.Name, SemaphoreRights.FullControl, AccessControlType.Allow)); + semaphoreSecurity.AddAccessRule(new SemaphoreAccessRule(serviceIdentity, SemaphoreRights.FullControl, AccessControlType.Allow)); } _memoryMappedFile = MemoryMappedFile.CreateNew( @@ -180,7 +203,7 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize bufferSize, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, - transparent, + memorySecurity, HandleInheritability.Inheritable); StreamAccessorComms = _memoryMappedFile.CreateViewStream(0, bufferSize, MemoryMappedFileAccess.ReadWrite); @@ -192,21 +215,26 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize EventResetMode.ManualReset, MakeName(@"\OpenCover_Profiler_Communication_SendData_Event_", bufferId), out createdNew, - open); + eventSecurity); InformationReadyForProfiler = new EventWaitHandle( false, EventResetMode.ManualReset, MakeName(@"\OpenCover_Profiler_Communication_ReceiveData_Event_", bufferId), out createdNew, - open); + eventSecurity); InformationReadByProfiler = new EventWaitHandle( false, EventResetMode.ManualReset, MakeName(@"\OpenCover_Profiler_Communication_ChunkData_Event_", bufferId), out createdNew, - open); + eventSecurity); + + _semaphore = new Semaphore(0, 2, + MakeName(@"\OpenCover_Profiler_Communication_Semaphore_", bufferId), + out createdNew, + semaphoreSecurity); DataCommunication = new byte[bufferSize]; PinnedDataCommunication = GCHandle.Alloc(DataCommunication, GCHandleType.Pinned); @@ -215,8 +243,13 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize public void Dispose() { Debug.WriteLine("*** disposing communication block ***"); - StreamAccessorComms.Dispose(); - _memoryMappedFile.Dispose(); + _semaphore.Do(s => + { + s.Release(1); + s.Dispose(); + }); + StreamAccessorComms.Do(r => r.Dispose()); + _memoryMappedFile.Do(f => f.Dispose()); PinnedDataCommunication.Free(); } } diff --git a/main/OpenCover.Profiler/ProfilerCommunication.cpp b/main/OpenCover.Profiler/ProfilerCommunication.cpp index 33f0d4b92..4866304b4 100644 --- a/main/OpenCover.Profiler/ProfilerCommunication.cpp +++ b/main/OpenCover.Profiler/ProfilerCommunication.cpp @@ -52,6 +52,9 @@ bool ProfilerCommunication::Initialise(TCHAR *key, TCHAR *ns) m_memoryCommunication.OpenFileMapping((m_namespace + _T("\\OpenCover_Profiler_Communication_MemoryMapFile_") + sharedKey).c_str()); if (!m_memoryCommunication.IsValid()) return false; + _semapore_communication.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_Semaphore_") + sharedKey).c_str()); + if (!_semapore_communication.IsValid()) return false; + RELTRACE(_T("Initialised communication interface")); hostCommunicationActive = true; @@ -86,12 +89,15 @@ bool ProfilerCommunication::Initialise(TCHAR *key, TCHAR *ns) m_pMSG = (MSG_Union*)m_memoryCommunication.MapViewOfFile(0, 0, MAX_MSG_SIZE); + _semapore_communication.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_Semaphore_") + memoryKey).c_str()); + if (!_semapore_communication.IsValid()) return false; + RELTRACE(_T("Re-initialised communication interface => %d"), bufferId); - m_eventProfilerHasResults.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_SendResults_Event_") + memoryKey).c_str()); + m_eventProfilerHasResults.Initialise((m_namespace + _T("\\OpenCover_Profiler_Results_SendResults_Event_") + memoryKey).c_str()); if (!m_eventProfilerHasResults.IsValid()) return false; - m_eventResultsHaveBeenReceived.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_ReceiveResults_Event_") + memoryKey).c_str()); + m_eventResultsHaveBeenReceived.Initialise((m_namespace + _T("\\OpenCover_Profiler_Results_ReceiveResults_Event_") + memoryKey).c_str()); if (!m_eventResultsHaveBeenReceived.IsValid()) return false; m_memoryResults.OpenFileMapping((m_namespace + _T("\\OpenCover_Profiler_Results_MemoryMapFile_") + memoryKey).c_str()); @@ -101,6 +107,9 @@ bool ProfilerCommunication::Initialise(TCHAR *key, TCHAR *ns) m_pVisitPoints->count = 0; + _semapore_results.Initialise((m_namespace + _T("\\OpenCover_Profiler_Results_Semaphore_") + memoryKey).c_str()); + if (!_semapore_results.IsValid()) return false; + RELTRACE(_T("Initialised results interface => %d"), bufferId); } @@ -171,6 +180,13 @@ void ProfilerCommunication::SendThreadVisitPoints(MSG_SendVisitPoints_Request* p if (!hostCommunicationActive) return; + // the previous value should always be zero unless the host process has released + // and that means we have disposed of the shared memory + if (_semapore_results.ReleaseAndWait() != 0) { + hostCommunicationActive = false; + return; + } + handle_exception([=](){ memcpy(m_pVisitPoints, pVisitPoints, sizeof(MSG_SendVisitPoints_Request)); }, _T("SendThreadVisitPoints")); @@ -188,6 +204,13 @@ void ProfilerCommunication::AddVisitPointToBuffer(ULONG uniqueId, MSG_IdType msg if (!hostCommunicationActive) return; + // the previous value should always be zero unless the host process has released + // and that means we have disposed of the shared memory + if (_semapore_results.ReleaseAndWait() != 0) { + hostCommunicationActive = false; + return; + } + handle_exception([=](){ m_pVisitPoints->points[m_pVisitPoints->count].UniqueId = (uniqueId | msgType); }, _T("AddVisitPointToBuffer")); @@ -475,6 +498,13 @@ void ProfilerCommunication::RequestInformation(BR buildRequest, PR processResult ATL::CComCritSecLock lock(m_critComms); if (!hostCommunicationActive) return; + // the previous value should always be zero unless the host process has released + // and that means we have disposed of the shared memory + if (_semapore_communication.ReleaseAndWait() != 0) { + hostCommunicationActive = false; + return; + } + try { handle_exception([&](){ buildRequest(); }, message); diff --git a/main/OpenCover.Profiler/ProfilerCommunication.h b/main/OpenCover.Profiler/ProfilerCommunication.h index e298ca5e4..f39fb7d30 100644 --- a/main/OpenCover.Profiler/ProfilerCommunication.h +++ b/main/OpenCover.Profiler/ProfilerCommunication.h @@ -66,12 +66,14 @@ class ProfilerCommunication CEvent m_eventInformationReadyForProfiler; CEvent m_eventInformationReadByProfiler; MSG_Union *m_pMSG; + CSemaphoreEx _semapore_communication; private: CSharedMemory m_memoryResults; CEvent m_eventProfilerHasResults; CEvent m_eventResultsHaveBeenReceived; MSG_SendVisitPoints_Request *m_pVisitPoints; + CSemaphoreEx _semapore_results; private: ATL::CComAutoCriticalSection m_critResults; diff --git a/main/OpenCover.Profiler/SharedMemory.cpp b/main/OpenCover.Profiler/SharedMemory.cpp index 42f6c6b61..8d8fe5189 100644 --- a/main/OpenCover.Profiler/SharedMemory.cpp +++ b/main/OpenCover.Profiler/SharedMemory.cpp @@ -33,7 +33,7 @@ void* CSharedMemory::MapViewOfFile(DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow } void* pMappedData = ::MapViewOfFile( m_hMemory, - FILE_MAP_ALL_ACCESS, + SECTION_MAP_WRITE | SECTION_MAP_READ, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap diff --git a/main/OpenCover.Profiler/Synchronization.h b/main/OpenCover.Profiler/Synchronization.h index 44da73f78..196f01912 100644 --- a/main/OpenCover.Profiler/Synchronization.h +++ b/main/OpenCover.Profiler/Synchronization.h @@ -22,6 +22,39 @@ class CMutex void CloseHandle() {if (m_hMutex!=NULL) { ::CloseHandle(m_hMutex); m_hMutex=NULL; }} }; +class CSemaphore +{ +public: + CSemaphore() : m_hSemaphore(NULL) {} + ~CSemaphore() { CloseHandle(); } + bool IsValid() { return m_hSemaphore != NULL; } + +public: + void Initialise(const TCHAR * pName) { CloseHandle(); m_hSemaphore = ::CreateSemaphore(NULL, 0, 2, pName); } + void Enter(){ if (m_hSemaphore != NULL) { ::WaitForSingleObject(m_hSemaphore, INFINITE); } } + void Leave(){ if (m_hSemaphore != NULL) { ::ReleaseSemaphore(m_hSemaphore, 1, NULL); } } + +private: + HANDLE m_hSemaphore; + void CloseHandle() { if (m_hSemaphore != NULL) { ::CloseHandle(m_hSemaphore); m_hSemaphore = NULL; } } + + friend class CSemaphoreEx; +}; + +class CSemaphoreEx : public CSemaphore { +public: + LONG ReleaseAndWait() { + if (m_hSemaphore != NULL) { + LONG prevCount = -1; + if (::ReleaseSemaphore(m_hSemaphore, 1, &prevCount) && prevCount == 0) // +1 + ::WaitForSingleObject(m_hSemaphore, INFINITE); // -1 + return prevCount; + } + return -1; + } + +}; + template class CScopedLock { From f6add07d61590e411408c9604f4d02a7d673ad46 Mon Sep 17 00:00:00 2001 From: sawilde Date: Tue, 1 Sep 2015 21:15:39 +1000 Subject: [PATCH 02/19] #329 - add more diagnostics around the communication channel --- main/OpenCover.Profiler/CodeCoverage.cpp | 2 +- .../ProfilerCommunication.cpp | 135 +++++++++++++----- 2 files changed, 103 insertions(+), 34 deletions(-) diff --git a/main/OpenCover.Profiler/CodeCoverage.cpp b/main/OpenCover.Profiler/CodeCoverage.cpp index 30b4f119b..bca62fff8 100644 --- a/main/OpenCover.Profiler/CodeCoverage.cpp +++ b/main/OpenCover.Profiler/CodeCoverage.cpp @@ -94,7 +94,7 @@ HRESULT CCodeCoverage::OpenCoverInitialise(IUnknown *pICorProfilerInfoUnk){ if (!m_host.Initialise(key, ns)) { - RELTRACE(_T(" ::Initialize => Failed to initialise the profiler communications -> GetLastError() => %d"), ::GetLastError()); + RELTRACE(_T(" ::Initialize => Failed to initialise the profiler communications - profiler will not run for this process.")); return E_FAIL; } diff --git a/main/OpenCover.Profiler/ProfilerCommunication.cpp b/main/OpenCover.Profiler/ProfilerCommunication.cpp index 4866304b4..15e6467c9 100644 --- a/main/OpenCover.Profiler/ProfilerCommunication.cpp +++ b/main/OpenCover.Profiler/ProfilerCommunication.cpp @@ -38,24 +38,45 @@ bool ProfilerCommunication::Initialise(TCHAR *key, TCHAR *ns) m_mutexCommunication.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_Mutex_") + m_key).c_str()); if (!m_mutexCommunication.IsValid()) return false; - RELTRACE(_T("Initialised mutexes")); + USES_CONVERSION; + RELTRACE(_T("Initialised mutexes => %s"), W2CT(sharedKey.c_str())); - m_eventProfilerRequestsInformation.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_SendData_Event_") + sharedKey).c_str()); - if (!m_eventProfilerRequestsInformation.IsValid()) return false; + auto resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_SendData_Event_") + sharedKey); + m_eventProfilerRequestsInformation.Initialise(resource_name.c_str()); + if (!m_eventProfilerRequestsInformation.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + return false; + } - m_eventInformationReadByProfiler.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_ChunkData_Event_") + sharedKey).c_str()); - if (!m_eventInformationReadByProfiler.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_ChunkData_Event_") + sharedKey); + m_eventInformationReadByProfiler.Initialise(resource_name.c_str()); + if (!m_eventInformationReadByProfiler.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + return false; + } - m_eventInformationReadyForProfiler.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_ReceiveData_Event_") + sharedKey).c_str()); - if (!m_eventInformationReadyForProfiler.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_ReceiveData_Event_") + sharedKey); + m_eventInformationReadyForProfiler.Initialise(resource_name.c_str()); + if (!m_eventInformationReadyForProfiler.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + return false; + } - m_memoryCommunication.OpenFileMapping((m_namespace + _T("\\OpenCover_Profiler_Communication_MemoryMapFile_") + sharedKey).c_str()); - if (!m_memoryCommunication.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_MemoryMapFile_") + sharedKey); + m_memoryCommunication.OpenFileMapping(resource_name.c_str()); + if (!m_memoryCommunication.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + return false; + } - _semapore_communication.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_Semaphore_") + sharedKey).c_str()); - if (!_semapore_communication.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_Semaphore_") + sharedKey); + _semapore_communication.Initialise(resource_name.c_str()); + if (!_semapore_communication.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + return false; + } - RELTRACE(_T("Initialised communication interface")); + RELTRACE(_T("Initialised communication interface => %s"), W2CT(sharedKey.c_str())); hostCommunicationActive = true; @@ -73,44 +94,92 @@ bool ProfilerCommunication::Initialise(TCHAR *key, TCHAR *ns) memoryKey = m_key + memoryKey; - RELTRACE(_T("Re-initialising communication interface => %d"), bufferId); + RELTRACE(_T("Re-initialising communication interface => %s"), W2CT(memoryKey.c_str())); - m_eventProfilerRequestsInformation.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_SendData_Event_") + memoryKey).c_str()); - if (!m_eventProfilerRequestsInformation.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_SendData_Event_") + memoryKey); + m_eventProfilerRequestsInformation.Initialise(resource_name.c_str()); + if (!m_eventProfilerRequestsInformation.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - m_eventInformationReadByProfiler.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_ChunkData_Event_") + memoryKey).c_str()); - if (!m_eventInformationReadByProfiler.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_ChunkData_Event_") + memoryKey); + m_eventInformationReadByProfiler.Initialise(resource_name.c_str()); + if (!m_eventInformationReadByProfiler.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - m_eventInformationReadyForProfiler.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_ReceiveData_Event_") + memoryKey).c_str()); - if (!m_eventInformationReadyForProfiler.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_ReceiveData_Event_") + memoryKey); + m_eventInformationReadyForProfiler.Initialise(resource_name.c_str()); + if (!m_eventInformationReadyForProfiler.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - m_memoryCommunication.OpenFileMapping((m_namespace + _T("\\OpenCover_Profiler_Communication_MemoryMapFile_") + memoryKey).c_str()); - if (!m_memoryCommunication.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_MemoryMapFile_") + memoryKey); + m_memoryCommunication.OpenFileMapping(resource_name.c_str()); + if (!m_memoryCommunication.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } m_pMSG = (MSG_Union*)m_memoryCommunication.MapViewOfFile(0, 0, MAX_MSG_SIZE); - _semapore_communication.Initialise((m_namespace + _T("\\OpenCover_Profiler_Communication_Semaphore_") + memoryKey).c_str()); - if (!_semapore_communication.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Communication_Semaphore_") + memoryKey); + _semapore_communication.Initialise(resource_name.c_str()); + if (!_semapore_communication.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - RELTRACE(_T("Re-initialised communication interface => %d"), bufferId); + RELTRACE(_T("Re-initialised communication interface => %s"), W2CT(memoryKey.c_str())); - m_eventProfilerHasResults.Initialise((m_namespace + _T("\\OpenCover_Profiler_Results_SendResults_Event_") + memoryKey).c_str()); - if (!m_eventProfilerHasResults.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Results_SendResults_Event_") + memoryKey); + m_eventProfilerHasResults.Initialise(resource_name.c_str()); + if (!m_eventProfilerHasResults.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - m_eventResultsHaveBeenReceived.Initialise((m_namespace + _T("\\OpenCover_Profiler_Results_ReceiveResults_Event_") + memoryKey).c_str()); - if (!m_eventResultsHaveBeenReceived.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Results_ReceiveResults_Event_") + memoryKey); + m_eventResultsHaveBeenReceived.Initialise(resource_name.c_str()); + if (!m_eventResultsHaveBeenReceived.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - m_memoryResults.OpenFileMapping((m_namespace + _T("\\OpenCover_Profiler_Results_MemoryMapFile_") + memoryKey).c_str()); - if (!m_memoryResults.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Results_MemoryMapFile_") + memoryKey); + m_memoryResults.OpenFileMapping(resource_name.c_str()); + if (!m_memoryResults.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } m_pVisitPoints = (MSG_SendVisitPoints_Request*)m_memoryResults.MapViewOfFile(0, 0, MAX_MSG_SIZE); m_pVisitPoints->count = 0; - _semapore_results.Initialise((m_namespace + _T("\\OpenCover_Profiler_Results_Semaphore_") + memoryKey).c_str()); - if (!_semapore_results.IsValid()) return false; + resource_name = (m_namespace + _T("\\OpenCover_Profiler_Results_Semaphore_") + memoryKey); + _semapore_results.Initialise(resource_name.c_str()); + if (!_semapore_results.IsValid()) { + RELTRACE(_T("Failed to initialise resource %s => ::GetLastError() = %d"), W2CT(resource_name.c_str()), ::GetLastError()); + hostCommunicationActive = false; + return false; + } - RELTRACE(_T("Initialised results interface => %d"), bufferId); + RELTRACE(_T("Initialised results interface => %s"), W2CT(memoryKey.c_str())); + } + else { + hostCommunicationActive = false; } return hostCommunicationActive; From bf26a6da2bc49f3cb538f34c9c8758d7b34fe340 Mon Sep 17 00:00:00 2001 From: sawilde Date: Tue, 1 Sep 2015 22:59:07 +1000 Subject: [PATCH 03/19] address some of the XML comment warnings --- .../Communication/MarshalWapper.cs | 20 ++++++++ .../Manager/IManagedCommunicationBlock.cs | 26 ++++++++++ .../Manager/IManagedMemoryBlock.cs | 22 ++++++++ .../Manager/IMemoryManager.cs | 51 +++++++++++++++++++ .../Symbols/ISymbolManager.cs | 2 +- 5 files changed, 120 insertions(+), 1 deletion(-) diff --git a/main/OpenCover.Framework/Communication/MarshalWapper.cs b/main/OpenCover.Framework/Communication/MarshalWapper.cs index db1222451..1f4f71d33 100644 --- a/main/OpenCover.Framework/Communication/MarshalWapper.cs +++ b/main/OpenCover.Framework/Communication/MarshalWapper.cs @@ -11,12 +11,32 @@ namespace OpenCover.Framework.Communication { + /// + /// + /// public interface IMarshalWrapper { + /// + /// Map pinned memory to a structure + /// + /// The type of the structure + /// + /// T PtrToStructure(IntPtr pinnedMemory); + + /// + /// Map a structure to pinned memory + /// + /// + /// + /// + /// void StructureToPtr(T structure, IntPtr pinnedMemory, bool fDeleteOld); } + /// + /// Implementation of + /// public class MarshalWrapper : IMarshalWrapper { public T PtrToStructure(IntPtr pinnedMemory) diff --git a/main/OpenCover.Framework/Manager/IManagedCommunicationBlock.cs b/main/OpenCover.Framework/Manager/IManagedCommunicationBlock.cs index 056d59e57..d2cefcc2c 100644 --- a/main/OpenCover.Framework/Manager/IManagedCommunicationBlock.cs +++ b/main/OpenCover.Framework/Manager/IManagedCommunicationBlock.cs @@ -5,13 +5,39 @@ namespace OpenCover.Framework.Manager { + /// + /// Define a command communication interface + /// public interface IManagedCommunicationBlock : IDisposable { + /// + /// The communication data + /// MemoryMappedViewStream StreamAccessorComms { get; } + + /// + /// Signalled by the profiler when the profiler wants some information + /// EventWaitHandle ProfilerRequestsInformation { get; } + + /// + /// Signalled by the host when the data requested is available + /// EventWaitHandle InformationReadyForProfiler { get; } + + /// + /// signalled by the profiler when te data has been read by the profiler + /// EventWaitHandle InformationReadByProfiler { get; } + + /// + /// The data being communicated + /// byte[] DataCommunication { get; } + + /// + /// A handle to the pinned data + /// GCHandle PinnedDataCommunication { get; } } } \ No newline at end of file diff --git a/main/OpenCover.Framework/Manager/IManagedMemoryBlock.cs b/main/OpenCover.Framework/Manager/IManagedMemoryBlock.cs index 430da6513..33d65f536 100644 --- a/main/OpenCover.Framework/Manager/IManagedMemoryBlock.cs +++ b/main/OpenCover.Framework/Manager/IManagedMemoryBlock.cs @@ -4,12 +4,34 @@ namespace OpenCover.Framework.Manager { + /// + /// Define a results communication interface + /// public interface IManagedMemoryBlock : IDisposable { + /// + /// Signalled by profiler when the profiler has results + /// EventWaitHandle ProfilerHasResults { get; } + + /// + /// Signalled by host when results ahve been read + /// EventWaitHandle ResultsHaveBeenReceived { get; } + + /// + /// Access the results + /// MemoryMappedViewStream StreamAccessorResults { get; } + + /// + /// Get the buffer size + /// int BufferSize { get; } + + /// + /// Get the buffer + /// byte[] Buffer { get; } } } \ No newline at end of file diff --git a/main/OpenCover.Framework/Manager/IMemoryManager.cs b/main/OpenCover.Framework/Manager/IMemoryManager.cs index 48e65ad93..83c3a32b5 100644 --- a/main/OpenCover.Framework/Manager/IMemoryManager.cs +++ b/main/OpenCover.Framework/Manager/IMemoryManager.cs @@ -4,24 +4,75 @@ namespace OpenCover.Framework.Manager { + /// + /// Defines the buffer between the host and a profiler instance + /// public class ManagedBufferBlock { + /// + /// Defines the buffer between the host and a profiler instance + /// public ManagedBufferBlock() { Active = true; } + + /// + /// A communication block is where all commands are sent from profiler to host + /// public IManagedCommunicationBlock CommunicationBlock { get; set; } + + /// + /// A memory block is were the results are sent + /// public IManagedMemoryBlock MemoryBlock { get; set; } + + /// + /// The buffer identifier + /// public uint BufferId { get; set; } + + /// + /// Is the block still active? + /// public bool Active { get; set; } } + /// + /// Defines the interface for a memory manager implementation + /// public interface IMemoryManager : IDisposable { + /// + /// Initialise a memory manager + /// + /// + /// + /// void Initialise(string nameSpace, string key, IEnumerable servicePrincipal); + + /// + /// Allocate a that is used to communicate between host and profiler + /// + /// + /// + /// ManagedBufferBlock AllocateMemoryBuffer(int bufferSize, out uint bufferId); + + /// + /// Get the list of all allocated blocks + /// IList GetBlocks { get; } + + /// + /// Deactivate a + /// + /// void DeactivateMemoryBuffer(uint bufferId); + + /// + /// Remove all deactivated blocks + /// void RemoveDeactivatedBlocks(); } } \ No newline at end of file diff --git a/main/OpenCover.Framework/Symbols/ISymbolManager.cs b/main/OpenCover.Framework/Symbols/ISymbolManager.cs index 8fa5dce75..0c32f92b3 100644 --- a/main/OpenCover.Framework/Symbols/ISymbolManager.cs +++ b/main/OpenCover.Framework/Symbols/ISymbolManager.cs @@ -8,7 +8,7 @@ namespace OpenCover.Framework.Symbols { - public interface ISymbolManager + internal interface ISymbolManager { string ModulePath { get; } From a4309acd32bc2c0a546cae639bb119e648e50cfc Mon Sep 17 00:00:00 2001 From: sawilde Date: Tue, 1 Sep 2015 22:59:52 +1000 Subject: [PATCH 04/19] #329 retry allocating buffer (3 x 3s) rather than a single 10s --- .../ProfilerCommunication.cpp | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/main/OpenCover.Profiler/ProfilerCommunication.cpp b/main/OpenCover.Profiler/ProfilerCommunication.cpp index 15e6467c9..d2c7b7a26 100644 --- a/main/OpenCover.Profiler/ProfilerCommunication.cpp +++ b/main/OpenCover.Profiler/ProfilerCommunication.cpp @@ -16,6 +16,7 @@ #define ONERROR_GOEXIT(hr) if (FAILED(hr)) goto Exit #define COMM_WAIT_SHORT 10000 #define COMM_WAIT_LONG 60000 +#define COMM_WAIT_VSHORT 3000 ProfilerCommunication::ProfilerCommunication() { @@ -456,22 +457,25 @@ bool ProfilerCommunication::AllocateBuffer(LONG bufferSize, ULONG &bufferId) return false; bool response = false; - - RequestInformation( - [=]() - { - m_pMSG->allocateBufferRequest.type = MSG_AllocateMemoryBuffer; - m_pMSG->allocateBufferRequest.lBufferSize = bufferSize; - }, - [=, &response, &bufferId]()->BOOL - { - response = m_pMSG->allocateBufferResponse.bResponse == TRUE; - bufferId = m_pMSG->allocateBufferResponse.ulBufferId; - ::ZeroMemory(m_pMSG, MAX_MSG_SIZE); - return FALSE; - } - , COMM_WAIT_SHORT - , _T("AllocateBuffer")); + int repeat = 0; + while (!response && (++repeat <= 3)){ + hostCommunicationActive = true; + RequestInformation( + [=]() + { + m_pMSG->allocateBufferRequest.type = MSG_AllocateMemoryBuffer; + m_pMSG->allocateBufferRequest.lBufferSize = bufferSize; + }, + [=, &response, &bufferId]()->BOOL + { + response = m_pMSG->allocateBufferResponse.bResponse == TRUE; + bufferId = m_pMSG->allocateBufferResponse.ulBufferId; + ::ZeroMemory(m_pMSG, MAX_MSG_SIZE); + return FALSE; + } + , COMM_WAIT_VSHORT + , _T("AllocateBuffer")); + } return response; } From af2a679acfa998084286a13ebb1588ea100c78af Mon Sep 17 00:00:00 2001 From: sawilde Date: Tue, 1 Sep 2015 23:43:40 +1000 Subject: [PATCH 05/19] address more XML doco warnings --- .../Communication/Messages.cs | 204 ++++++++++++++++++ .../Symbols/ISymbolManager.cs | 47 +++- 2 files changed, 250 insertions(+), 1 deletion(-) diff --git a/main/OpenCover.Framework/Communication/Messages.cs b/main/OpenCover.Framework/Communication/Messages.cs index 6bdfccfef..40f5efed1 100644 --- a/main/OpenCover.Framework/Communication/Messages.cs +++ b/main/OpenCover.Framework/Communication/Messages.cs @@ -7,124 +7,311 @@ namespace OpenCover.Framework.Communication { + /// + /// The command supportd by the host + /// +// ReSharper disable InconsistentNaming public enum MSG_Type : int { + /// + /// Does this assembly have any code that can be covered + /// MSG_TrackAssembly = 1, + + /// + /// Get the sequence point for a method + /// MSG_GetSequencePoints = 2, + + /// + /// Get the branch points for a method + /// MSG_GetBranchPoints = 3, + + /// + /// Do we track this method (test methods only) + /// MSG_TrackMethod = 4, + + /// + /// allocate a provate memory buffer for profiler/host communications + /// MSG_AllocateMemoryBuffer = 5, + + /// + /// Close a channel between host and profiler + /// MSG_CloseChannel = 6, } + /// + /// The type of results + /// public enum MSG_IdType : uint { + /// + /// a basic coverage vist point + /// IT_VisitPoint = 0x00000000, + + /// + /// A test method enter + /// IT_MethodEnter = 0x40000000, + + /// + /// A test method exit + /// IT_MethodLeave = 0x80000000, + + /// + /// A test method tail call + /// IT_MethodTailcall = 0xC0000000, + /// + /// A mask of the above + /// IT_Mask = 0x3FFFFFFF, } + /// + /// Trck an assembly + /// [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct MSG_TrackAssembly_Request { + /// + /// The message type + /// public MSG_Type type; + + /// + /// The path to the module/assembly + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string modulePath; + + /// + /// The name of the module/assembly + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string assemblyName; } + /// + /// The response to a + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_TrackAssembly_Response { + /// + /// True - if the assembly has instrumentable code + /// [MarshalAs(UnmanagedType.Bool)] public bool track; } + /// + /// Get the sequence points for a method + /// [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct MSG_GetSequencePoints_Request { + /// + /// The type of message + /// public MSG_Type type; + + /// + /// The token of the method + /// public int functionToken; + + /// + /// The path to the module hosting the emthod + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string modulePath; + + /// + /// The name of the module/assembly hosting the method + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string assemblyName; } + /// + /// Defines a seqence point + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_SequencePoint { + /// + /// The identifier of the sequence point + /// public uint uniqueId; + + /// + /// The original IL offset of where the sequence pont should be placed + /// public int offset; } + /// + /// The response to a + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_GetSequencePoints_Response { + /// + /// Do we have more data + /// [MarshalAs(UnmanagedType.Bool)] public bool more; + /// + /// The number of sequence points that follow + /// public int count; } + /// + /// Get the branch points of a method + /// [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct MSG_GetBranchPoints_Request { + /// + /// The type of message + /// public MSG_Type type; + + /// + /// The token of the method + /// public int functionToken; + + /// + /// The path to the module hosting the emthod + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string modulePath; + + /// + /// The name of the module/assembly hosting the method + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string assemblyName; } + /// + /// Defines a branch point + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_BranchPoint { + /// + /// The uniqueid of the branch point + /// public uint uniqueId; + + /// + /// The original IL offset of the branch instruction to be instrumented + /// public int offset; + + /// + /// Which of the paths T/F or switch that the point is intending to cover. + /// public int path; } + /// + /// The response to a + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_GetBranchPoints_Response { + /// + /// Do we have more data + /// [MarshalAs(UnmanagedType.Bool)] public bool more; + /// + /// The number of branch points that follow + /// public int count; } + /// + /// Should we track this method + /// [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct MSG_TrackMethod_Request { + /// + /// The type of message + /// public MSG_Type type; + + /// + /// The token of the method under test + /// public int functionToken; + + /// + /// Te path to the module + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string modulePath; + + /// + /// The name of the assemby/module + /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] public string assemblyName; } + /// + /// the response to a + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_TrackMethod_Response { + /// + /// True - the method should be tracked + /// [MarshalAs(UnmanagedType.Bool)] public bool track; + + /// + /// The uniqueid assigned to the method + /// public uint uniqueId; } + /// + /// Request to allocate a buffer + /// [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct MSG_AllocateBuffer_Request { + /// + /// The type of message + /// public MSG_Type type; + + /// + /// The buffer size + /// public int bufferSize; } + /// + /// The response to a + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_AllocateBuffer_Response { @@ -133,18 +320,35 @@ public struct MSG_AllocateBuffer_Response public uint bufferId; } + /// + /// A close channel request + /// [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] public struct MSG_CloseChannel_Request { + /// + /// The type of message + /// public MSG_Type type; + + /// + /// The id of the buffer to close + /// public uint bufferId; } + /// + /// The response to a + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MSG_CloseChannel_Response { + /// + /// The buffer should be cleared. + /// [MarshalAs(UnmanagedType.Bool)] public bool done; } + // ReSharper restore InconsistentNaming } diff --git a/main/OpenCover.Framework/Symbols/ISymbolManager.cs b/main/OpenCover.Framework/Symbols/ISymbolManager.cs index 0c32f92b3..8aea025dd 100644 --- a/main/OpenCover.Framework/Symbols/ISymbolManager.cs +++ b/main/OpenCover.Framework/Symbols/ISymbolManager.cs @@ -8,26 +8,71 @@ namespace OpenCover.Framework.Symbols { - internal interface ISymbolManager + /// + /// defines a symbol manager for an assembly/module being profiled + /// + public interface ISymbolManager { + /// + /// The path to the module + /// string ModulePath { get; } + /// + /// The name of the module + /// string ModuleName { get; } + /// + /// The source files that made up the module + /// + /// File[] GetFiles(); + /// + /// The types (with implementation) found in the module + /// + /// Class[] GetInstrumentableTypes(); + /// + /// The methods for a type in the module + /// + /// + /// + /// Method[] GetMethodsForType(Class type, File[] files); + /// + /// The sequence points for a method + /// + /// + /// SequencePoint[] GetSequencePointsForToken(int token); + /// + /// The branch points for a method + /// + /// + /// BranchPoint[] GetBranchPointsForToken(int token); + /// + /// The cyclomatic complexity for a method + /// + /// + /// int GetCyclomaticComplexityForToken(int token); + /// + /// The source assembly + /// AssemblyDefinition SourceAssembly { get; } + /// + /// Test methods that are being tracked + /// + /// TrackedMethod[] GetTrackedMethods(); } } \ No newline at end of file From be0ed1e329a7c8975200cf5657f46a47e47e6a33 Mon Sep 17 00:00:00 2001 From: sawilde Date: Wed, 2 Sep 2015 18:46:28 +1000 Subject: [PATCH 06/19] #329 log exceptions and respond safely --- .../Communication/MessageHandler.cs | 104 +++++++++---- .../Manager/MemoryManager.cs | 39 ++--- main/OpenCover.Framework/log4net.config | 4 +- .../Communication/MessageHandlerTests.cs | 147 +++++++++++++++++- .../Framework/Manager/MemoryManagerTests.cs | 63 ++++++++ .../Framework/Manager/ProfilerManagerTests.cs | 1 - main/OpenCover.Test/OpenCover.Test.csproj | 1 + main/cmdline/report_coverage.cmd | 2 +- 8 files changed, 305 insertions(+), 56 deletions(-) create mode 100644 main/OpenCover.Test/Framework/Manager/MemoryManagerTests.cs diff --git a/main/OpenCover.Framework/Communication/MessageHandler.cs b/main/OpenCover.Framework/Communication/MessageHandler.cs index e3ed9c854..aabdece87 100644 --- a/main/OpenCover.Framework/Communication/MessageHandler.cs +++ b/main/OpenCover.Framework/Communication/MessageHandler.cs @@ -86,11 +86,11 @@ public int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Act break; case MSG_Type.MSG_TrackMethod: - writeSize = HandleTrackMethodMessage(pinnedMemory); + writeSize = HandleTrackMethodMessage(pinnedMemory); break; case MSG_Type.MSG_AllocateMemoryBuffer: - writeSize = HandlerAllocateBufferMessage(offloadHandling, pinnedMemory); + writeSize = HandleAllocateBufferMessage(offloadHandling, pinnedMemory); break; case MSG_Type.MSG_CloseChannel: @@ -140,7 +140,7 @@ private int HandleGetSequencePointsMessage(IntPtr pinnedMemory, IManagedCommunic } catch (Exception ex) { - Logger.DebugFormat("{0}:{1}", ex.GetType(), ex.Message); + Logger.DebugFormat("HandleGetSequencePointsMessage => {0}:{1}", ex.GetType(), ex.Message); response.more = false; response.count = 0; _marshalWrapper.StructureToPtr(response, pinnedMemory, false); @@ -189,7 +189,7 @@ private int HandleGetBranchPointsMessage(IntPtr pinnedMemory, IManagedCommunicat } catch (Exception ex) { - Logger.DebugFormat("{0}:{1}", ex.GetType(), ex.Message); + Logger.DebugFormat("HandleGetBranchPointsMessage => {0}:{1}", ex.GetType(), ex.Message); response.more = false; response.count = 0; _marshalWrapper.StructureToPtr(response, pinnedMemory, false); @@ -197,49 +197,97 @@ private int HandleGetBranchPointsMessage(IntPtr pinnedMemory, IManagedCommunicat return writeSize; } - private int HandlerAllocateBufferMessage(Action offloadHandling, IntPtr pinnedMemory) + private int HandleAllocateBufferMessage(Action offloadHandling, IntPtr pinnedMemory) { - var request = _marshalWrapper.PtrToStructure(pinnedMemory); - uint bufferId; - var block = _memoryManager.AllocateMemoryBuffer(request.bufferSize, out bufferId); - var response = new MSG_AllocateBuffer_Response { allocated = true, bufferId = bufferId }; - _marshalWrapper.StructureToPtr(response, pinnedMemory, false); var writeSize = Marshal.SizeOf(typeof(MSG_AllocateBuffer_Response)); - offloadHandling(block); + var response = new MSG_AllocateBuffer_Response { allocated = false, bufferId = 0 }; + try + { + var request = _marshalWrapper.PtrToStructure(pinnedMemory); + uint bufferId; + var block = _memoryManager.AllocateMemoryBuffer(request.bufferSize, out bufferId); + response.allocated=true; + response.bufferId = bufferId; + offloadHandling(block); + } + catch (Exception ex) + { + Logger.DebugFormat("HandlerAllocateBufferMessage => {0}:{1}", ex.GetType(), ex.Message); + response.allocated = false; + response.bufferId = 0; + } + finally + { + _marshalWrapper.StructureToPtr(response, pinnedMemory, false); + } return writeSize; } private int HandleCloseChannelMessage(IntPtr pinnedMemory) { - var request = _marshalWrapper.PtrToStructure(pinnedMemory); - var bufferId = request.bufferId; - var response = new MSG_CloseChannel_Response {done = true}; - _marshalWrapper.StructureToPtr(response, pinnedMemory, false); - var writeSize = Marshal.SizeOf(typeof (MSG_CloseChannel_Response)); - _memoryManager.DeactivateMemoryBuffer(bufferId); + var writeSize = Marshal.SizeOf(typeof(MSG_CloseChannel_Response)); + var response = new MSG_CloseChannel_Response { done = true }; + try + { + var request = _marshalWrapper.PtrToStructure(pinnedMemory); + var bufferId = request.bufferId; + _marshalWrapper.StructureToPtr(response, pinnedMemory, false); + _memoryManager.DeactivateMemoryBuffer(bufferId); + } + catch (Exception ex) + { + Logger.DebugFormat("HandleCloseChannelMessage => {0}:{1}", ex.GetType(), ex.Message); + } + finally + { + _marshalWrapper.StructureToPtr(response, pinnedMemory, false); + } return writeSize; } private int HandleTrackMethodMessage(IntPtr pinnedMemory) { - var request = _marshalWrapper.PtrToStructure(pinnedMemory); + var writeSize = Marshal.SizeOf(typeof(MSG_TrackMethod_Response)); var response = new MSG_TrackMethod_Response(); - uint uniqueId; - response.track = _profilerCommunication.TrackMethod(request.modulePath, - request.assemblyName, request.functionToken, out uniqueId); - response.uniqueId = uniqueId; - _marshalWrapper.StructureToPtr(response, pinnedMemory, false); - var writeSize = Marshal.SizeOf(typeof (MSG_TrackMethod_Response)); + try + { + var request = _marshalWrapper.PtrToStructure(pinnedMemory); + uint uniqueId; + response.track = _profilerCommunication.TrackMethod(request.modulePath, + request.assemblyName, request.functionToken, out uniqueId); + response.uniqueId = uniqueId; + } + catch (Exception ex) + { + Logger.DebugFormat("HandleTrackMethodMessage => {0}:{1}", ex.GetType(), ex.Message); + response.track = false; + response.uniqueId = 0; + } + finally + { + _marshalWrapper.StructureToPtr(response, pinnedMemory, false); + } return writeSize; } private int HandleTrackAssemblyMessage(IntPtr pinnedMemory) { - var request = _marshalWrapper.PtrToStructure(pinnedMemory); var response = new MSG_TrackAssembly_Response(); - response.track = _profilerCommunication.TrackAssembly(request.modulePath, request.assemblyName); - _marshalWrapper.StructureToPtr(response, pinnedMemory, false); - var writeSize = Marshal.SizeOf(typeof (MSG_TrackAssembly_Response)); + var writeSize = Marshal.SizeOf(typeof(MSG_TrackAssembly_Response)); + try + { + var request = _marshalWrapper.PtrToStructure(pinnedMemory); + response.track = _profilerCommunication.TrackAssembly(request.modulePath, request.assemblyName); + } + catch (Exception ex) + { + Logger.DebugFormat("HandleTrackAssemblyMessage => {0}:{1}", ex.GetType(), ex.Message); + response.track = false; + } + finally + { + _marshalWrapper.StructureToPtr(response, pinnedMemory, false); + } return writeSize; } diff --git a/main/OpenCover.Framework/Manager/MemoryManager.cs b/main/OpenCover.Framework/Manager/MemoryManager.cs index 34bc3f070..c97604ef1 100644 --- a/main/OpenCover.Framework/Manager/MemoryManager.cs +++ b/main/OpenCover.Framework/Manager/MemoryManager.cs @@ -136,12 +136,13 @@ internal ManagedMemoryBlock(string @namespace, string key, int bufferSize, int b public void Dispose() { - Debug.WriteLine("*** disposing memory block ***"); _semaphore.Do(s => { s.Release(1); s.Dispose(); }); + ProfilerHasResults.Do(e => e.Dispose()); + ResultsHaveBeenReceived.Do(e => e.Dispose()); StreamAccessorResults.Do(r => r.Dispose()); _mmfResults.Do(r => r.Dispose()); } @@ -198,16 +199,6 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize semaphoreSecurity.AddAccessRule(new SemaphoreAccessRule(serviceIdentity, SemaphoreRights.FullControl, AccessControlType.Allow)); } - _memoryMappedFile = MemoryMappedFile.CreateNew( - MakeName(@"\OpenCover_Profiler_Communication_MemoryMapFile_", bufferId), - bufferSize, - MemoryMappedFileAccess.ReadWrite, - MemoryMappedFileOptions.None, - memorySecurity, - HandleInheritability.Inheritable); - - StreamAccessorComms = _memoryMappedFile.CreateViewStream(0, bufferSize, MemoryMappedFileAccess.ReadWrite); - bool createdNew; ProfilerRequestsInformation = new EventWaitHandle( @@ -236,18 +227,30 @@ internal ManagedCommunicationBlock(string @namespace, string key, int bufferSize out createdNew, semaphoreSecurity); + _memoryMappedFile = MemoryMappedFile.CreateNew( + MakeName(@"\OpenCover_Profiler_Communication_MemoryMapFile_", bufferId), + bufferSize, + MemoryMappedFileAccess.ReadWrite, + MemoryMappedFileOptions.None, + memorySecurity, + HandleInheritability.Inheritable); + + StreamAccessorComms = _memoryMappedFile.CreateViewStream(0, bufferSize, MemoryMappedFileAccess.ReadWrite); + DataCommunication = new byte[bufferSize]; PinnedDataCommunication = GCHandle.Alloc(DataCommunication, GCHandleType.Pinned); } public void Dispose() { - Debug.WriteLine("*** disposing communication block ***"); _semaphore.Do(s => { s.Release(1); s.Dispose(); }); + ProfilerRequestsInformation.Do(e => e.Dispose()); + InformationReadyForProfiler.Do(e => e.Dispose()); + InformationReadByProfiler.Do(e => e.Dispose()); StreamAccessorComms.Do(r => r.Dispose()); _memoryMappedFile.Do(f => f.Dispose()); PinnedDataCommunication.Free(); @@ -333,9 +336,8 @@ public void RemoveDeactivatedBlocks() var list = _blocks.Where(b => !b.Active).ToList(); foreach (var b in list) { - Debug.WriteLine("*** removing deactivated ***"); - b.CommunicationBlock.Dispose(); - b.MemoryBlock.Dispose(); + b.CommunicationBlock.Do(x => x.Dispose()); + b.MemoryBlock.Do(x => x.Dispose()); _blocks.RemoveAt(_blocks.IndexOf(b)); } } @@ -343,13 +345,12 @@ public void RemoveDeactivatedBlocks() public void Dispose() { - //Console.WriteLine("Disposing..."); lock (_lockObject) { - foreach(var block in _blocks.Where(b => b.Active)) + foreach(var block in _blocks) { - block.CommunicationBlock.Dispose(); - block.MemoryBlock.Dispose(); + block.CommunicationBlock.Do(x => x.Dispose()); + block.MemoryBlock.Do(x => x.Dispose()); } _blocks.Clear(); } diff --git a/main/OpenCover.Framework/log4net.config b/main/OpenCover.Framework/log4net.config index 4d8afe674..fec0fa787 100644 --- a/main/OpenCover.Framework/log4net.config +++ b/main/OpenCover.Framework/log4net.config @@ -19,9 +19,9 @@ - + - + diff --git a/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs b/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs index a8cd1bdb9..9f917a627 100644 --- a/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs +++ b/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs @@ -87,7 +87,6 @@ public void Handles_MSG_AllocateMemoryBuffer() Instance.StandardMessage(MSG_Type.MSG_AllocateMemoryBuffer, _mockCommunicationBlock.Object, (i, block) => { }, block => { }); // assert - uint uniqueId; Container.GetMock() .Verify(x => x.AllocateMemoryBuffer(It.IsAny(), out bufferId), Times.Once()); @@ -120,6 +119,7 @@ public void Handles_MSG_GetSequencePoints_Small() .Returns(new MSG_GetSequencePoints_Request()); var points = Enumerable.Repeat(new InstrumentationPoint(), 2).ToArray(); + Assert.NotNull(points); Container.GetMock() .Setup(x => x.GetSequencePoints(It.IsAny(), It.IsAny(), It.IsAny(), out points)); @@ -143,6 +143,7 @@ public void Handles_MSG_GetSequencePoints_Large_StartsToChunk() .Returns(new MSG_GetSequencePoints_Request()); var points = Enumerable.Repeat(new InstrumentationPoint(), 10000).ToArray(); + Assert.NotNull(points); //var points = new[] { new SequencePoint(), new SequencePoint(), new SequencePoint(), new SequencePoint(), new SequencePoint(), new SequencePoint() }; Container.GetMock() @@ -187,6 +188,8 @@ public void Handles_MSG_GetBranchPoints_Small() .Returns(new MSG_GetBranchPoints_Request()); var points = Enumerable.Repeat(new BranchPoint(), 2).ToArray(); + Assert.NotNull(points); + Container.GetMock() .Setup(x => x.GetBranchPoints(It.IsAny(), It.IsAny(), It.IsAny(), out points)); @@ -210,6 +213,7 @@ public void Handles_MSG_GetBranchPoints_Large_StartsToChunk() .Returns(new MSG_GetBranchPoints_Request()); var points = Enumerable.Repeat(new BranchPoint(), 10000).ToArray(); + Assert.NotNull(points); Container.GetMock() .Setup(x => x.GetBranchPoints(It.IsAny(), It.IsAny(), It.IsAny(), out points)); @@ -242,6 +246,31 @@ public void WhenComplete_Stop_ProfilerCommunication() Container.GetMock().Verify(x => x.Stopping(), Times.Once()); } + [Test] + public void Handles_MSG_CloseChannel_ReturnsDoneAsTrue() + { + // arrange + Container.GetMock() + .Setup(x => x.PtrToStructure(It.IsAny())) + .Returns(new MSG_CloseChannel_Request()); + + var response = new MSG_CloseChannel_Response { done = false }; + Container.GetMock() + .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((msg, ptr, b) => { response = msg; }); + + // act + Instance.StandardMessage(MSG_Type.MSG_CloseChannel, _mockCommunicationBlock.Object, + (i, block) => { }, + block => { }); + + // assert + Assert.AreEqual(true, response.done); + Container.GetMock() + .Verify(x => x.DeactivateMemoryBuffer(It.IsAny()), Times.Once); + + } + [Test] public void ExceptionDuring_MSG_GetSequencePoints_ReturnsLastBlockAsEmpty() { @@ -251,15 +280,16 @@ public void ExceptionDuring_MSG_GetSequencePoints_ReturnsLastBlockAsEmpty() .Returns(new MSG_GetSequencePoints_Request()); var points = Enumerable.Repeat(new SequencePoint(), 100).ToArray(); + Assert.NotNull(points); Container.GetMock() .Setup(x => x.GetSequencePoints(It.IsAny(), It.IsAny(), It.IsAny(), out points)) .Throws(); - var response = new MSG_GetSequencePoints_Response(){count = -1, more = true}; + var response = new MSG_GetSequencePoints_Response{count = -1, more = true}; Container.GetMock() .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((pts, ptr, b) => { response = pts; }); + .Callback((msg, ptr, b) => { response = msg; }); var chunked = false; @@ -283,15 +313,16 @@ public void ExceptionDuring_MSG_GetBranchPoints_ReturnsLastBlockAsEmpty() .Returns(new MSG_GetBranchPoints_Request()); var points = Enumerable.Repeat(new BranchPoint(), 100).ToArray(); + Assert.NotNull(points); Container.GetMock() .Setup(x => x.GetBranchPoints(It.IsAny(), It.IsAny(), It.IsAny(), out points)) .Throws(); - var response = new MSG_GetBranchPoints_Response() { count = -1, more = true }; + var response = new MSG_GetBranchPoints_Response { count = -1, more = true }; Container.GetMock() .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((pts, ptr, b) => { response = pts; }); + .Callback((msg, ptr, b) => { response = msg; }); var chunked = false; @@ -305,5 +336,111 @@ public void ExceptionDuring_MSG_GetBranchPoints_ReturnsLastBlockAsEmpty() Assert.AreEqual(0, response.count); Assert.AreEqual(false, response.more); } + + [Test] + public void ExceptionDuring_MSG_AllocateMemoryBuffer_ReturnsAllocatedAsFalse() + { + // arrange + Container.GetMock() + .Setup(x => x.PtrToStructure(It.IsAny())) + .Returns(new MSG_AllocateBuffer_Request()); + + var response = new MSG_AllocateBuffer_Response { allocated = true }; + Container.GetMock() + .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((msg, ptr, b) => { response = msg; }); + + uint bufferId; + Container.GetMock() + .Setup(x => x.AllocateMemoryBuffer(It.IsAny(), out bufferId)) + .Throws(); + + // act + Instance.StandardMessage(MSG_Type.MSG_AllocateMemoryBuffer, _mockCommunicationBlock.Object, + (i, block) => { }, + block => { }); + + // assert + Assert.AreEqual(false, response.allocated); + } + + [Test] + public void ExceptionDuring_MSG_CloseChannel_ReturnsDoneAsTrue() + { + // arrange + Container.GetMock() + .Setup(x => x.PtrToStructure(It.IsAny())) + .Returns(new MSG_CloseChannel_Request()); + + var response = new MSG_CloseChannel_Response { done = false }; + Container.GetMock() + .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((msg, ptr, b) => { response = msg; }); + + Container.GetMock() + .Setup(x => x.DeactivateMemoryBuffer(It.IsAny())) + .Throws(); + + // act + Instance.StandardMessage(MSG_Type.MSG_CloseChannel, _mockCommunicationBlock.Object, + (i, block) => { }, + block => { }); + + // assert + Assert.AreEqual(true, response.done); + } + + [Test] + public void ExceptionDuring_MSG_TrackMethod_ReturnsTrackAsFalse() + { + // arrange + Container.GetMock() + .Setup(x => x.PtrToStructure(It.IsAny())) + .Returns(new MSG_TrackMethod_Request()); + + var response = new MSG_TrackMethod_Response { track = true }; + Container.GetMock() + .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((msg, ptr, b) => { response = msg; }); + + uint uniqueId; + Container.GetMock() + .Setup(x => x.TrackMethod(It.IsAny(), It.IsAny(), It.IsAny(), out uniqueId)) + .Throws(); + + // act + Instance.StandardMessage(MSG_Type.MSG_TrackMethod, _mockCommunicationBlock.Object, + (i, block) => { }, + block => { }); + + // assert + Assert.AreEqual(false, response.track); + } + + [Test] + public void ExceptionDuring_MSG_TrackAssembly_ReturnsTrackAsFalse() + { + // arrange + Container.GetMock() + .Setup(x => x.PtrToStructure(It.IsAny())) + .Returns(new MSG_TrackAssembly_Request()); + + var response = new MSG_TrackAssembly_Response { track = true }; + Container.GetMock() + .Setup(x => x.StructureToPtr(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((msg, ptr, b) => { response = msg; }); + + Container.GetMock() + .Setup(x => x.TrackAssembly(It.IsAny(), It.IsAny())) + .Throws(); + + // act + Instance.StandardMessage(MSG_Type.MSG_TrackAssembly, _mockCommunicationBlock.Object, + (i, block) => { }, + block => { }); + + // assert + Assert.AreEqual(false, response.track); + } } } diff --git a/main/OpenCover.Test/Framework/Manager/MemoryManagerTests.cs b/main/OpenCover.Test/Framework/Manager/MemoryManagerTests.cs new file mode 100644 index 000000000..ad4509d24 --- /dev/null +++ b/main/OpenCover.Test/Framework/Manager/MemoryManagerTests.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using NUnit.Framework; +using OpenCover.Framework.Manager; + +namespace OpenCover.Test.Framework.Manager +{ + [TestFixture] + public class MemoryManagerTests + { + private MemoryManager _manager; + + [SetUp] + public void SetUp() + { + _manager = new MemoryManager(); + _manager.Initialise("Local", "C#", new String[0]); + } + + [TearDown] + public void Teardown() + { + _manager.Dispose(); + } + + [Test] + public void DeactivateMemoryBuffer_SetsActive_ForBlock_False() + { + // arrange + uint bufferId; + _manager.AllocateMemoryBuffer(100, out bufferId); + Assert.AreEqual(1, _manager.GetBlocks.Count); + Assert.IsTrue(_manager.GetBlocks.First().Active); + + // act + _manager.DeactivateMemoryBuffer(bufferId); + + // assert + Assert.IsFalse(_manager.GetBlocks.First().Active); + } + + [Test] + public void RemoveDeactivatedBlocks_RemovesAllBlocks_ThatHaveActiveFalse() + { + // arrange + uint bufferId; + _manager.AllocateMemoryBuffer(100, out bufferId); + _manager.AllocateMemoryBuffer(100, out bufferId); + Assert.AreEqual(2, _manager.GetBlocks.Count); + Assert.AreEqual(2, _manager.GetBlocks.Count(b => b.Active)); + _manager.DeactivateMemoryBuffer(bufferId); + Assert.AreEqual(2, _manager.GetBlocks.Count); + Assert.AreEqual(1, _manager.GetBlocks.Count(b => b.Active)); + + // act + _manager.RemoveDeactivatedBlocks(); + + // assert + Assert.AreEqual(1, _manager.GetBlocks.Count); + Assert.AreEqual(1, _manager.GetBlocks.Count(b => b.Active)); + } + } +} \ No newline at end of file diff --git a/main/OpenCover.Test/Framework/Manager/ProfilerManagerTests.cs b/main/OpenCover.Test/Framework/Manager/ProfilerManagerTests.cs index a2a91a743..86024dc92 100644 --- a/main/OpenCover.Test/Framework/Manager/ProfilerManagerTests.cs +++ b/main/OpenCover.Test/Framework/Manager/ProfilerManagerTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Specialized; -using System.Diagnostics; using System.Linq; using System.Security.AccessControl; using System.Security.Principal; diff --git a/main/OpenCover.Test/OpenCover.Test.csproj b/main/OpenCover.Test/OpenCover.Test.csproj index 629b02218..fb09b74b3 100644 --- a/main/OpenCover.Test/OpenCover.Test.csproj +++ b/main/OpenCover.Test/OpenCover.Test.csproj @@ -147,6 +147,7 @@ + diff --git a/main/cmdline/report_coverage.cmd b/main/cmdline/report_coverage.cmd index c81f1c1fc..49b7c453d 100644 --- a/main/cmdline/report_coverage.cmd +++ b/main/cmdline/report_coverage.cmd @@ -1 +1 @@ -..\..\..\main\packages\ReportGenerator.2.1.8.0\ReportGenerator.exe -reports:opencovertests.xml -targetdir:report \ No newline at end of file +..\..\..\main\packages\ReportGenerator.2.1.8.0\tools\ReportGenerator.exe -reports:opencovertests.xml -targetdir:report \ No newline at end of file From 0820553d9d21a5f2a0eff8020bbadced803dd17c Mon Sep 17 00:00:00 2001 From: sawilde Date: Thu, 3 Sep 2015 06:39:20 +1000 Subject: [PATCH 07/19] #329 configure special logger for debug output --- .../Communication/MessageHandler.cs | 14 ++--- .../Persistance/BasePersistance.cs | 61 +++++++++++++++++-- .../Persistance/FilePersistance.cs | 2 +- main/OpenCover.Framework/log4net.config | 12 ++-- .../Persistance/BasePersistenceTests.cs | 4 +- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/main/OpenCover.Framework/Communication/MessageHandler.cs b/main/OpenCover.Framework/Communication/MessageHandler.cs index aabdece87..55a9d933a 100644 --- a/main/OpenCover.Framework/Communication/MessageHandler.cs +++ b/main/OpenCover.Framework/Communication/MessageHandler.cs @@ -52,7 +52,7 @@ public class MessageHandler : IMessageHandler private readonly IMarshalWrapper _marshalWrapper; private readonly IMemoryManager _memoryManager; - private static readonly ILog Logger = LogManager.GetLogger("OpenCover"); + private static readonly ILog DebugLogger = LogManager.GetLogger("DebugLogger"); /// /// Construct a Message Handler @@ -140,7 +140,7 @@ private int HandleGetSequencePointsMessage(IntPtr pinnedMemory, IManagedCommunic } catch (Exception ex) { - Logger.DebugFormat("HandleGetSequencePointsMessage => {0}:{1}", ex.GetType(), ex.Message); + DebugLogger.ErrorFormat("HandleGetSequencePointsMessage => {0}:{1}", ex.GetType(), ex.Message); response.more = false; response.count = 0; _marshalWrapper.StructureToPtr(response, pinnedMemory, false); @@ -189,7 +189,7 @@ private int HandleGetBranchPointsMessage(IntPtr pinnedMemory, IManagedCommunicat } catch (Exception ex) { - Logger.DebugFormat("HandleGetBranchPointsMessage => {0}:{1}", ex.GetType(), ex.Message); + DebugLogger.ErrorFormat("HandleGetBranchPointsMessage => {0}:{1}", ex.GetType(), ex.Message); response.more = false; response.count = 0; _marshalWrapper.StructureToPtr(response, pinnedMemory, false); @@ -212,7 +212,7 @@ private int HandleAllocateBufferMessage(Action offloadHandli } catch (Exception ex) { - Logger.DebugFormat("HandlerAllocateBufferMessage => {0}:{1}", ex.GetType(), ex.Message); + DebugLogger.ErrorFormat("HandlerAllocateBufferMessage => {0}:{1}", ex.GetType(), ex.Message); response.allocated = false; response.bufferId = 0; } @@ -236,7 +236,7 @@ private int HandleCloseChannelMessage(IntPtr pinnedMemory) } catch (Exception ex) { - Logger.DebugFormat("HandleCloseChannelMessage => {0}:{1}", ex.GetType(), ex.Message); + DebugLogger.ErrorFormat("HandleCloseChannelMessage => {0}:{1}", ex.GetType(), ex.Message); } finally { @@ -259,7 +259,7 @@ private int HandleTrackMethodMessage(IntPtr pinnedMemory) } catch (Exception ex) { - Logger.DebugFormat("HandleTrackMethodMessage => {0}:{1}", ex.GetType(), ex.Message); + DebugLogger.ErrorFormat("HandleTrackMethodMessage => {0}:{1}", ex.GetType(), ex.Message); response.track = false; response.uniqueId = 0; } @@ -281,7 +281,7 @@ private int HandleTrackAssemblyMessage(IntPtr pinnedMemory) } catch (Exception ex) { - Logger.DebugFormat("HandleTrackAssemblyMessage => {0}:{1}", ex.GetType(), ex.Message); + DebugLogger.ErrorFormat("HandleTrackAssemblyMessage => {0}:{1}", ex.GetType(), ex.Message); response.track = false; } finally diff --git a/main/OpenCover.Framework/Persistance/BasePersistance.cs b/main/OpenCover.Framework/Persistance/BasePersistance.cs index 79e57e234..d09e25b1b 100644 --- a/main/OpenCover.Framework/Persistance/BasePersistance.cs +++ b/main/OpenCover.Framework/Persistance/BasePersistance.cs @@ -15,7 +15,9 @@ public abstract class BasePersistance : IPersistance protected readonly ICommandLine CommandLine; private readonly ILog _logger; private uint _trackedMethodId; - private readonly Dictionary>> _moduleMethodMap = new Dictionary>>(); + private readonly Dictionary>> _moduleMethodMap = new Dictionary>>(); + + private static readonly ILog DebugLogger = LogManager.GetLogger("DebugLogger"); /// /// constructor @@ -25,13 +27,20 @@ public abstract class BasePersistance : IPersistance protected BasePersistance(ICommandLine commandLine, ILog logger) { CommandLine = commandLine; - _logger = logger; + _logger = logger ?? DebugLogger; CoverageSession = new CoverageSession(); _trackedMethodId = 0; } + /// + /// A coverage session + /// public CoverageSession CoverageSession { get; private set; } + /// + /// Add the to the current session + /// + /// public void PersistModule(Module module) { if (module == null) return; @@ -56,6 +65,9 @@ public void PersistModule(Module module) CoverageSession.Modules = list.ToArray(); } + /// + /// Clear the current coverage session data + /// protected void ClearCoverageSession() { _moduleMethodMap.Clear(); @@ -374,7 +386,7 @@ from method in @class.Methods.Where(x => !x.ShouldSerializeSkippedDueTo()) @class.Summary.MaxCyclomaticComplexity = Math.Max(@class.Summary.MaxCyclomaticComplexity, method.CyclomaticComplexity); } - @class.Summary.NumClasses = (@class.Summary.NumMethods > 0) ? 1 : 0; ; + @class.Summary.NumClasses = (@class.Summary.NumMethods > 0) ? 1 : 0; @class.Summary.VisitedClasses = (@class.Summary.VisitedMethods > 0) ? 1 : 0; AddPoints(module.Summary, @class.Summary); @@ -434,6 +446,13 @@ private static void AddPoints(Summary parent, Summary child) parent.VisitedMethods += child.VisitedMethods; } + /// + /// Get the sequence points for a function + /// + /// + /// + /// + /// public bool GetSequencePointsForFunction(string modulePath, int functionToken, out InstrumentationPoint[] sequencePoints) { sequencePoints = new InstrumentationPoint[0]; @@ -452,6 +471,13 @@ public bool GetSequencePointsForFunction(string modulePath, int functionToken, o return false; } + /// + /// Get the branch ponts for a function + /// + /// + /// + /// + /// public bool GetBranchPointsForFunction(string modulePath, int functionToken, out BranchPoint[] branchPoints) { branchPoints = new BranchPoint[0]; @@ -466,6 +492,13 @@ public bool GetBranchPointsForFunction(string modulePath, int functionToken, out return false; } + /// + /// Get data for a function + /// + /// + /// + /// + /// private Method GetMethod(string modulePath, int functionToken, out Class @class) { @class = null; @@ -479,6 +512,12 @@ private Method GetMethod(string modulePath, int functionToken, out Class @class) return pair.Value; } + /// + /// Get the class name of a function + /// + /// + /// + /// public string GetClassFullName(string modulePath, int functionToken) { Class @class; @@ -486,12 +525,16 @@ public string GetClassFullName(string modulePath, int functionToken) return @class != null ? @class.FullName : null; } + /// + /// Save the visit data to the session model + /// + /// public void SaveVisitData(byte[] data) { var nCount = BitConverter.ToUInt32(data, 0); if (nCount > (data.Count()/4) - 1) { - _logger.DebugFormat("Failed to process points as count ({0}) exceeded available buffer size ({1})", + _logger.ErrorFormat("Failed to process points as count ({0}) exceeded available buffer size ({1})", nCount, (data.Count()/4) - 1); return; } @@ -502,7 +545,7 @@ public void SaveVisitData(byte[] data) { if (!InstrumentationPoint.AddVisitCount(spid, _trackedMethodId)) { - _logger.DebugFormat("Failed to add a visit to {0} with tracking method {1}. Max point count is {2}", + _logger.ErrorFormat("Failed to add a visit to {0} with tracking method {1}. Max point count is {2}", spid, _trackedMethodId, InstrumentationPoint.Count); } } @@ -514,6 +557,14 @@ public void SaveVisitData(byte[] data) } } + /// + /// determine if the method (test method) should be tracked + /// + /// + /// + /// + /// + /// public bool GetTrackingMethod(string modulePath, string assemblyName, int functionToken, out uint uniqueId) { uniqueId = 0; diff --git a/main/OpenCover.Framework/Persistance/FilePersistance.cs b/main/OpenCover.Framework/Persistance/FilePersistance.cs index 1023e9ed7..ffc063810 100644 --- a/main/OpenCover.Framework/Persistance/FilePersistance.cs +++ b/main/OpenCover.Framework/Persistance/FilePersistance.cs @@ -26,7 +26,7 @@ public class FilePersistance : BasePersistance /// /// /// - public FilePersistance(ICommandLine commandLine, ILog logger) : base(commandLine, logger) + public FilePersistance(ICommandLine commandLine, ILog logger) : base(commandLine, null) { _logger = logger; } diff --git a/main/OpenCover.Framework/log4net.config b/main/OpenCover.Framework/log4net.config index fec0fa787..2ae44f521 100644 --- a/main/OpenCover.Framework/log4net.config +++ b/main/OpenCover.Framework/log4net.config @@ -19,19 +19,19 @@ - + - - - - + + + + + - diff --git a/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs b/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs index 466692a0f..f53dcb00d 100644 --- a/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs +++ b/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs @@ -1067,7 +1067,7 @@ public void SaveVisitPoints_Warns_WhenPointID_IsOutOfRange_High() Instance.SaveVisitData(data.ToArray()); //assert - Container.GetMock().Verify(x => x.DebugFormat(It.IsAny(), + Container.GetMock().Verify(x => x.ErrorFormat(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } @@ -1083,7 +1083,7 @@ public void SaveVisitPoints_Warns_WhenPointID_IsOutOfRange_Low() Instance.SaveVisitData(data.ToArray()); //assert - Container.GetMock().Verify(x => x.DebugFormat(It.IsAny(), + Container.GetMock().Verify(x => x.ErrorFormat(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); } From c6e2196271781104d9afed7fa211167556fc6a47 Mon Sep 17 00:00:00 2001 From: sawilde Date: Fri, 4 Sep 2015 08:13:03 +1000 Subject: [PATCH 08/19] more doco tidy up --- main/OpenCover.Framework/CommandLineParserBase.cs | 8 +++++++- .../Model/IInstrumentationModelBuilderFactory.cs | 12 +++++++++--- .../Model/InstrumentationModelBuilderFactory.cs | 12 ++++++++++-- main/OpenCover.Framework/Utility/PerfCounters.cs | 14 +++++++++++--- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/main/OpenCover.Framework/CommandLineParserBase.cs b/main/OpenCover.Framework/CommandLineParserBase.cs index 57b968efd..dc03f7b86 100644 --- a/main/OpenCover.Framework/CommandLineParserBase.cs +++ b/main/OpenCover.Framework/CommandLineParserBase.cs @@ -5,7 +5,6 @@ // using System; using System.Collections.Generic; -using System.Text; namespace OpenCover.Framework { @@ -17,12 +16,19 @@ public abstract class CommandLineParserBase { private readonly string[] _arguments; + /// + /// Instantiate the base command line parser + /// + /// protected CommandLineParserBase(string[] arguments) { _arguments = arguments; ParsedArguments = new Dictionary(); } + /// + /// Get the parsed arguments + /// protected IDictionary ParsedArguments { get; private set; } /// diff --git a/main/OpenCover.Framework/Model/IInstrumentationModelBuilderFactory.cs b/main/OpenCover.Framework/Model/IInstrumentationModelBuilderFactory.cs index a0fe927be..7a917c16d 100644 --- a/main/OpenCover.Framework/Model/IInstrumentationModelBuilderFactory.cs +++ b/main/OpenCover.Framework/Model/IInstrumentationModelBuilderFactory.cs @@ -4,13 +4,19 @@ // This source code is released under the MIT License; see the accompanying license file. // -using System.Collections.Generic; -using OpenCover.Framework.Strategy; - namespace OpenCover.Framework.Model { + /// + /// Define the model builder factory + /// public interface IInstrumentationModelBuilderFactory { + /// + /// Create a model builder for a module + /// + /// + /// + /// IInstrumentationModelBuilder CreateModelBuilder(string modulePath, string moduleName); } } \ No newline at end of file diff --git a/main/OpenCover.Framework/Model/InstrumentationModelBuilderFactory.cs b/main/OpenCover.Framework/Model/InstrumentationModelBuilderFactory.cs index 60eca7e86..160356ea9 100644 --- a/main/OpenCover.Framework/Model/InstrumentationModelBuilderFactory.cs +++ b/main/OpenCover.Framework/Model/InstrumentationModelBuilderFactory.cs @@ -4,14 +4,15 @@ // This source code is released under the MIT License; see the accompanying license file. // -using System.Collections.Generic; -using System.Linq; using OpenCover.Framework.Strategy; using OpenCover.Framework.Symbols; using log4net; namespace OpenCover.Framework.Model { + /// + /// Implement a model builder factory + /// public class InstrumentationModelBuilderFactory : IInstrumentationModelBuilderFactory { private readonly ICommandLine _commandLine; @@ -19,6 +20,13 @@ public class InstrumentationModelBuilderFactory : IInstrumentationModelBuilderFa private readonly ILog _logger; private readonly ITrackedMethodStrategyManager _trackedMethodStrategyManager; + /// + /// Instantiate a model builder factory + /// + /// + /// + /// + /// public InstrumentationModelBuilderFactory(ICommandLine commandLine, IFilter filter, ILog logger, ITrackedMethodStrategyManager trackedMethodStrategyManager) { _commandLine = commandLine; diff --git a/main/OpenCover.Framework/Utility/PerfCounters.cs b/main/OpenCover.Framework/Utility/PerfCounters.cs index 3ee767280..e1774b247 100644 --- a/main/OpenCover.Framework/Utility/PerfCounters.cs +++ b/main/OpenCover.Framework/Utility/PerfCounters.cs @@ -3,28 +3,33 @@ namespace OpenCover.Framework.Utility { /// - /// + /// Expose some performance counters /// - /// [ExcludeFromCoverage("Performance counters can only be created by Administrators")] public class PerfCounters : IPerfCounters { private PerformanceCounter _memoryQueue; private PerformanceCounter _queueThrougput; + /// + /// get the current queue size + /// public int CurrentMemoryQueueSize { set { _memoryQueue.RawValue = value; } } public void IncrementBlocksReceived() { _queueThrougput.RawValue += 1; } + /// + /// Instantiate the Performance Counters + /// public PerfCounters() { CreateCounters(); ResetCounters(); } - private const string InstanceName = "OpenCover"; + //private const string InstanceName = "OpenCover"; private const string CategoryName = "OpenCover"; private const string MemoryQueue = "MemoryQueue"; private const string QueueThroughput = "QueueThroughput"; @@ -61,6 +66,9 @@ public void ResetCounters() [ExcludeFromCoverage("Performance counters can only be created by Administrators")] public class NullPerfCounter : IPerfCounters { + /// + /// A null performance counters implementation + /// public int CurrentMemoryQueueSize { set; private get; } public void IncrementBlocksReceived() { From cc6dbfd32e4c6bc2402e055239c04571ab8644da Mon Sep 17 00:00:00 2001 From: sawilde Date: Fri, 4 Sep 2015 08:13:37 +1000 Subject: [PATCH 09/19] distinguish between host and profiler logging in DebugView --- main/OpenCover.Framework/log4net.config | 2 +- main/OpenCover.Profiler/ReleaseTrace.h | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/main/OpenCover.Framework/log4net.config b/main/OpenCover.Framework/log4net.config index 2ae44f521..d6c61f707 100644 --- a/main/OpenCover.Framework/log4net.config +++ b/main/OpenCover.Framework/log4net.config @@ -21,7 +21,7 @@ - + diff --git a/main/OpenCover.Profiler/ReleaseTrace.h b/main/OpenCover.Profiler/ReleaseTrace.h index 4f96b0bf3..c5a6ab0f8 100644 --- a/main/OpenCover.Profiler/ReleaseTrace.h +++ b/main/OpenCover.Profiler/ReleaseTrace.h @@ -13,8 +13,8 @@ class CReleaseTrace { } - const char* PREFIX = "OpenCover: "; - const wchar_t* WPREFIX = L"OpenCover: "; + const char* PREFIX = "OpenCover: (Profiler) "; + const wchar_t* WPREFIX = L"OpenCover: (Profiler) "; #pragma warning(push) #pragma warning(disable : 4793) @@ -63,3 +63,8 @@ class CReleaseTrace }; #define RELTRACE CReleaseTrace() + +#ifdef _DEBUG +#undef ATLTRACE +#define ATLTRACE CReleaseTrace() +#endif \ No newline at end of file From d9c20c80b4df1e6260ebc15833fac1d388b2cda1 Mon Sep 17 00:00:00 2001 From: sawilde Date: Fri, 4 Sep 2015 08:15:24 +1000 Subject: [PATCH 10/19] #329 alter the way we start the thread that handles each profiler instance --- .../Manager/ProfilerManager.cs | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/main/OpenCover.Framework/Manager/ProfilerManager.cs b/main/OpenCover.Framework/Manager/ProfilerManager.cs index eb062f5f9..571468f9f 100644 --- a/main/OpenCover.Framework/Manager/ProfilerManager.cs +++ b/main/OpenCover.Framework/Manager/ProfilerManager.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using log4net; using OpenCover.Framework.Communication; using OpenCover.Framework.Persistance; using OpenCover.Framework.Utility; @@ -38,6 +39,8 @@ public class ProfilerManager : IProfilerManager private ConcurrentQueue _messageQueue; + private static readonly ILog DebugLogger = LogManager.GetLogger("DebugLogger"); + /// /// Create an instance of the profiler manager /// @@ -56,6 +59,11 @@ public ProfilerManager(ICommunicationManager communicationManager, IPersistance _perfCounters = perfCounters; } + /// + /// Start the target process + /// + /// + /// public void RunProcess(Action> process, string[] servicePrincipal) { var key = Guid.NewGuid().GetHashCode().ToString("X"); @@ -173,7 +181,14 @@ private void ProcessMessages(WaitHandle[] handles) break; case 1: - _communicationManager.HandleCommunicationBlock(_mcb, block => threadHandles.Add(StartProcessingThread(block))); + _communicationManager.HandleCommunicationBlock(_mcb, + block => Task.Factory.StartNew(() => + { + lock (threadHandles) + { + threadHandles.Add(StartProcessingThread(block)); + } + })); break; } } while (_continueWait); @@ -186,25 +201,28 @@ private void ProcessMessages(WaitHandle[] handles) _messageQueue.Enqueue(data); } - if (threadHandles.Any()) + lock (threadHandles) { - var tasks = threadHandles - .Select((e, index) => new {Pair = e, Block = index / NumHandlesPerBlock}) - .GroupBy(g => g.Block) - .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)); - })).ToArray(); - Task.WaitAll(tasks); - - foreach(var threadHandle in threadHandles) + if (threadHandles.Any()) { - threadHandle.Item1.Dispose(); - threadHandle.Item2.Dispose(); + var tasks = threadHandles + .Select((e, index) => new {Pair = e, Block = index/NumHandlesPerBlock}) + .GroupBy(g => g.Block) + .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)); + })).ToArray(); + Task.WaitAll(tasks); + + foreach (var threadHandle in threadHandles) + { + threadHandle.Item1.Dispose(); + threadHandle.Item2.Dispose(); + } + threadHandles.Clear(); } - threadHandles.Clear(); } _messageQueue.Enqueue(new byte[0]); @@ -212,6 +230,7 @@ private void ProcessMessages(WaitHandle[] handles) private Tuple StartProcessingThread(ManagedBufferBlock block) { + DebugLogger.InfoFormat("Starting Process Block => {0}", block.BufferId); var terminateThread = new ManualResetEvent(false); var threadTerminated = new ManualResetEvent(false); @@ -221,6 +240,7 @@ private Tuple StartProcessingThread(ManagedBuf threadActivated, threadTerminated)); threadActivated.WaitOne(); } + DebugLogger.InfoFormat("Started Process Block => {0}", block.BufferId); return new Tuple(terminateThread, threadTerminated); } From 7b0908b5d6d3657a9d6d0263da5470d58012638c Mon Sep 17 00:00:00 2001 From: sawilde Date: Sat, 5 Sep 2015 12:30:28 +1000 Subject: [PATCH 11/19] update readme --- README.md | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e8b2e06de..4d671b5d4 100644 --- a/README.md +++ b/README.md @@ -12,35 +12,36 @@ The primary repo for the project is [on GitHub](https://github.com/opencover/ope ### Team communication [![Join the chat at https://gitter.im/OpenCover/opencover](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/OpenCover/opencover?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Team communications can also be done via [slack](http://slack.com), raise an issue to request access (include your email - obfuscated if you wish) and we will send you an invite then just visit the [team page](https://opencover.slack.com/) to sign up and join the conversation. +### WIKI +Please review the [wiki pages](https://github.com/opencover/opencover/wiki/_pages) on how to use OpenCover and take particular interest in the [Usage guide](https://github.com/opencover/opencover/wiki/Usage). + +### Issues +Please raise issues on GitHub, if you can repeat the issue then please provide a sample to make it easier for us to also repeat it and then implement a fix. Please do not hijack unrelated issues, I would rather you create a new issue than add noise to an unrelated issue. + +[Dropbox](http://db.tt/VanqFDn) is very useful for sharing files alternatively you could create a [gist](https://gist.github.com/). ### Licence All Original Software is licensed under the [MIT Licence](https://github.com/opencover/opencover/blob/master/License.md) and does not apply to any other 3rd party tools, utilities or code which may be used to develop this application. If anyone is aware of any licence violations that this code may be making please inform the developers so that the issue can be investigated and rectified. -### WIKI -Please review the [wiki pages](https://github.com/opencover/opencover/wiki/_pages) on how to use OpenCover and take particular interest in the [Usage guide](https://github.com/opencover/opencover/wiki/Usage). +### Integration Test support +OpenCover was initially created to support unit testing techniques such as TDD and tools like NUnit and MSTest. Over time others have found ways to use OpenCover for integration testing especially in tricky scenarios such as IIS and Windows Services. I'll put links here as to how people have achieved this however as they say YMMV (You Mileage May Vary). -### Service support -Note that .zip and .nuget packages (at least) will not ACL files so that a low-privilege service can execute them -- manually add the service principal with read/execute privilege to the OpenCover.Profiler.dll ACLs, either through explorer properties or by a `Get-Acl`/`Set-Acl` PowerShell script. +#### IIS support +Please refer to the wiki - [IIS Support](https://github.com/OpenCover/opencover/wiki/IIS-Support) -Launching the profiling operation must be done with Administrator privilege -- this is required to even start the service, and is also needed to create the global objects and set the per-service environment that registers the COM object. Assuming that the COM objects have been pre-registered, the command line to use is like +#### DNX support +Please refer to the wiki - [DNX Support](https://github.com/OpenCover/opencover/wiki/DNX-Support) - OpenCover.console.exe -service:byname -target: -output:coverage.xml - -As this is a blocking operation, launching the coverage gathering a separate process as +#### Win8/Win10 Application Support +Note yet [implemented](https://github.com/OpenCover/opencover/issues/144). Sorry no call for it I assume the WPF way of separating model and UI has led to people getting all they need from unit-tests; I know how that is how it works for me. - start-process OpenCover.console.exe @("-target:", "-service:byName", "-output:coverage.xml") - -or equivalent in your test scripts. +#### Service support +please refer to the wiki - [Service Support](https://github.com/OpenCover/opencover/wiki/Service-Support) -The `byname` qualifier is used to prevent races if multiple services are being started concurrently by injecting the OpenCover profiling information to the service specific environment. - -### Issues -Please raise issues on GitHub, if you can repeat the issue then please provide a sample to make it easier for us to also repeat it and then implement a fix. Please do not hijack unrelated issues, I would rather you create a new issue than add noise to an unrelated issue. - -[Dropbox](http://db.tt/VanqFDn) is very useful for sharing files alternatively you could create a [gist](https://gist.github.com/). +#### Silverlight support +Please refer to wiki - [Silverlight support](https://github.com/OpenCover/opencover/wiki/Silverlight-Support) ### Building You will need: @@ -85,7 +86,7 @@ I would like to thank * JetBrains for my Open Source [ReSharper licence](http://www.jetbrains.com/resharper/), * [AppVeyor](https://ci.appveyor.com/project/sawilde/opencover) for allowing free build CI services for Open Source projects, * [Coveralls](https://coveralls.io/r/OpenCover/opencover) for allowing free services for Open Source projects, -* NDepend for my [NDepend licence](http://www.ndepend.com/). +* NDepend for my [NDepend licence](http://www.ndepend.com/), * the guys at [CodeBetter](http://codebetter.com/), [Devlicious](http://devlicio.us/) and [Los Techies](http://lostechies.com/) who orignally arranged my MSDN licence all those years ago without which I doubt I'd have been able to start OpenCover (now no longer needed as we can build OpenCover using the VS2013 Community Edition), * the [NextGenUG](http://www.nxtgenug.net/) and their free swag from where I got lots of useful tools, From 2eb03df5dc4ba6b39861e0dfe90e7f636f96dada Mon Sep 17 00:00:00 2001 From: sawilde Date: Sat, 5 Sep 2015 12:55:29 +1000 Subject: [PATCH 12/19] move signer project sign crash reporter --- ...er.gendarme.snk => opencover.3rdparty.snk} | Bin main/.nuget/packages.config | 1 + .../App.config | 0 .../CrashReporterSigner.cs | 52 ++++++++++++++++ .../GendarmeSigner.cs} | 49 ++++----------- .../OpenCover.3rdParty.Signer.csproj} | 10 +++- main/OpenCover.3rdParty.Signer/Program.cs | 56 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 0 .../packages.config | 0 main/OpenCover.sln | 21 +++---- main/packages/repositories.config | 1 + 11 files changed, 141 insertions(+), 49 deletions(-) rename build/Version/{opencover.gendarme.snk => opencover.3rdparty.snk} (100%) rename main/{OpenCover.Gendarme.Signer => OpenCover.3rdParty.Signer}/App.config (100%) create mode 100644 main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs rename main/{OpenCover.Gendarme.Signer/Program.cs => OpenCover.3rdParty.Signer/GendarmeSigner.cs} (67%) rename main/{OpenCover.Gendarme.Signer/OpenCover.Gendarme.Signer.csproj => OpenCover.3rdParty.Signer/OpenCover.3rdParty.Signer.csproj} (90%) create mode 100644 main/OpenCover.3rdParty.Signer/Program.cs rename main/{OpenCover.Gendarme.Signer => OpenCover.3rdParty.Signer}/Properties/AssemblyInfo.cs (100%) rename main/{OpenCover.Gendarme.Signer => OpenCover.3rdParty.Signer}/packages.config (100%) diff --git a/build/Version/opencover.gendarme.snk b/build/Version/opencover.3rdparty.snk similarity index 100% rename from build/Version/opencover.gendarme.snk rename to build/Version/opencover.3rdparty.snk diff --git a/main/.nuget/packages.config b/main/.nuget/packages.config index 6a2daf408..0d36bd4f6 100644 --- a/main/.nuget/packages.config +++ b/main/.nuget/packages.config @@ -1,5 +1,6 @@  + diff --git a/main/OpenCover.Gendarme.Signer/App.config b/main/OpenCover.3rdParty.Signer/App.config similarity index 100% rename from main/OpenCover.Gendarme.Signer/App.config rename to main/OpenCover.3rdParty.Signer/App.config diff --git a/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs b/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs new file mode 100644 index 000000000..e4e2f4bbc --- /dev/null +++ b/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs @@ -0,0 +1,52 @@ +using System.IO; +using System.Linq; +using System.Reflection; +using Mono.Cecil; + +namespace OpenCover.ThirdParty.Signer +{ + internal static class CrashReporterSigner + { + + private const string Version = "1.5"; + + private static readonly string GendarmeAssemblyName = string.Format("CrashReporterdotNet.{0}", Version); + + public static readonly string TargetFolder = Path.Combine("..", "tools", "CrashReporterSigned"); + private static readonly string SourceFolder = Path.Combine("packages", GendarmeAssemblyName, "lib", "net20"); + private static readonly string StrongNameKey = Path.Combine("..", "build", "Version", "opencover.3rdparty.snk"); + + + public static bool AlreadySigned(string baseFolder) + { + var frameworkAssembly = Path.Combine(baseFolder, TargetFolder, "CrashReporter.NET.dll"); + if (File.Exists(frameworkAssembly)) + { + try + { + var frameworkDefinition = AssemblyDefinition.ReadAssembly(frameworkAssembly); + return frameworkDefinition.Name.HasPublicKey; + } + catch + { + } + } + return false; + } + + public static void SignAssembly(string baseFolder) + { + var key = Path.Combine(baseFolder, StrongNameKey); + var assembly = Path.Combine(baseFolder, SourceFolder, "CrashReporter.NET.dll"); + var newAssembly = Path.Combine(baseFolder, TargetFolder, "CrashReporter.NET.dll"); + + assembly = Path.GetFullPath(assembly); + newAssembly = Path.GetFullPath(newAssembly); + + File.Copy(assembly, newAssembly, true); + var definition = AssemblyDefinition.ReadAssembly(newAssembly); + var keyPair = new StrongNameKeyPair(new FileStream(key, FileMode.Open, FileAccess.Read)); + definition.Write(newAssembly, new WriterParameters() { StrongNameKeyPair = keyPair }); + } + } +} \ No newline at end of file diff --git a/main/OpenCover.Gendarme.Signer/Program.cs b/main/OpenCover.3rdParty.Signer/GendarmeSigner.cs similarity index 67% rename from main/OpenCover.Gendarme.Signer/Program.cs rename to main/OpenCover.3rdParty.Signer/GendarmeSigner.cs index 8ae24e077..cc88103d8 100644 --- a/main/OpenCover.Gendarme.Signer/Program.cs +++ b/main/OpenCover.3rdParty.Signer/GendarmeSigner.cs @@ -1,48 +1,23 @@ -using System; -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using Mono.Cecil; -namespace OpenCover.Gendarme.Signer +namespace OpenCover.ThirdParty.Signer { - class Program + internal static class GendarmeSigner { - private const string GendarmeVersion = "2.11.0.20121120"; - private static readonly string GendarmeAssemblyName = string.Format("Mono.Gendarme.{0}", GendarmeVersion); + private const string GendarmeVersion = "2.11.0.20121120"; - private static readonly string TargetFolder = Path.Combine("..", "tools", "GendarmeSigned"); - private static readonly string SourceFolder = Path.Combine("packages", GendarmeAssemblyName, "tools"); - private static readonly string StrongNameKey = Path.Combine("..", "build", "Version", "opencover.gendarme.snk"); - - static void Main(string[] args) - { - var assemblyLocation = Assembly.GetAssembly (typeof(Program)).Location; - var assemblyFolder = Path.GetDirectoryName(assemblyLocation); - var baseFolder = Path.Combine(assemblyFolder, "..", "..", ".."); + private static readonly string GendarmeAssemblyName = string.Format("Mono.Gendarme.{0}", GendarmeVersion); - var targetDirectory = Path.Combine (baseFolder, TargetFolder); - if (!Directory.Exists(targetDirectory)) - Directory.CreateDirectory (targetDirectory); - - if (AlreadySigned(baseFolder)) - { - Console.WriteLine("Gendarme Framework is already Signed"); - return; - } - - Console.WriteLine("Signing Gendarme Framework"); - SignGendarmeFramework(baseFolder); + public static readonly string TargetFolder = Path.Combine("..", "tools", "GendarmeSigned"); + private static readonly string SourceFolder = Path.Combine("packages", GendarmeAssemblyName, "tools"); + private static readonly string StrongNameKey = Path.Combine("..", "build", "Version", "opencover.3rdparty.snk"); - Console.WriteLine("Signing Gendarme Rules Maintainability"); - SignGendarmeRulesMaintainability(baseFolder); - } - private static bool AlreadySigned(string baseFolder) + public static bool AlreadySigned(string baseFolder) { var frameworkAssembly = Path.Combine(baseFolder, TargetFolder, "Gendarme.Framework.dll"); if (File.Exists(frameworkAssembly)) @@ -59,7 +34,7 @@ private static bool AlreadySigned(string baseFolder) return false; } - private static void SignGendarmeRulesMaintainability(string baseFolder) + public static void SignGendarmeRulesMaintainability(string baseFolder) { var frameworkAssembly = Path.Combine(baseFolder, TargetFolder, "Gendarme.Framework.dll"); var frameworkDefinition = AssemblyDefinition.ReadAssembly(frameworkAssembly); @@ -97,7 +72,7 @@ private static void SignGendarmeRulesMaintainability(string baseFolder) } - private static void SignGendarmeFramework(string baseFolder) + public static void SignGendarmeFramework(string baseFolder) { var key = Path.Combine(baseFolder, StrongNameKey); var assembly = Path.Combine(baseFolder, SourceFolder, "Gendarme.Framework.dll"); @@ -112,4 +87,4 @@ private static void SignGendarmeFramework(string baseFolder) definition.Write(newAssembly, new WriterParameters() { StrongNameKeyPair = keyPair }); } } -} +} \ No newline at end of file diff --git a/main/OpenCover.Gendarme.Signer/OpenCover.Gendarme.Signer.csproj b/main/OpenCover.3rdParty.Signer/OpenCover.3rdParty.Signer.csproj similarity index 90% rename from main/OpenCover.Gendarme.Signer/OpenCover.Gendarme.Signer.csproj rename to main/OpenCover.3rdParty.Signer/OpenCover.3rdParty.Signer.csproj index 7582c303e..484dbfabb 100644 --- a/main/OpenCover.Gendarme.Signer/OpenCover.Gendarme.Signer.csproj +++ b/main/OpenCover.3rdParty.Signer/OpenCover.3rdParty.Signer.csproj @@ -7,8 +7,8 @@ {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E} Exe Properties - OpenCover.Gendarme.Signer - OpenCover.Gendarme.Signer + OpenCover.ThirdParty.Signer + OpenCover.3rdParty.Signer v4.0 512 ..\ @@ -65,6 +65,8 @@ + + @@ -79,6 +81,10 @@ $(SolutionDir)OpenCover.Gendarme.Signer\bin\$(ConfigurationName)\OpenCover.Gendarme.Signer.exe mono OpenCover.Gendarme.Signer.exe + + cd $(SolutionDir)OpenCover.3rdParty.Signer\bin\$(ConfigurationName) +$(SolutionDir)OpenCover.3rdParty.Signer\bin\$(ConfigurationName)\OpenCover.3rdParty.Signer.exe +