From 4cbf8bd3b7d8e2e01b40b043175206beb8478d2f Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Thu, 20 Jul 2023 13:08:02 -0700 Subject: [PATCH] Fire AssemblyUnloadStarted event (#87890) Fixes https://github.com/dotnet/runtime/issues/86178 AssemblyUnloadStarted event is now being fired --- src/coreclr/vm/loaderallocator.cpp | 2 + src/tests/profiler/assembly/ALCTest.cs | 35 +++++++++++++ src/tests/profiler/assembly/ALCTest.csproj | 19 +++++++ src/tests/profiler/assembly/TestFile.cs | 16 ++++++ src/tests/profiler/assembly/TestFile.csproj | 14 ++++++ src/tests/profiler/native/CMakeLists.txt | 1 + .../assemblyprofiler/assemblyprofiler.cpp | 50 +++++++++++++++++++ .../assemblyprofiler/assemblyprofiler.h | 25 ++++++++++ src/tests/profiler/native/classfactory.cpp | 5 ++ 9 files changed, 167 insertions(+) create mode 100644 src/tests/profiler/assembly/ALCTest.cs create mode 100644 src/tests/profiler/assembly/ALCTest.csproj create mode 100644 src/tests/profiler/assembly/TestFile.cs create mode 100644 src/tests/profiler/assembly/TestFile.csproj create mode 100644 src/tests/profiler/native/assemblyprofiler/assemblyprofiler.cpp create mode 100644 src/tests/profiler/native/assemblyprofiler/assemblyprofiler.h diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index c9eed61a132f6..604aa8218b683 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -535,6 +535,8 @@ void LoaderAllocator::GCLoaderAllocators(LoaderAllocator* pOriginalLoaderAllocat DomainAssemblyIterator domainAssemblyIt(pDomainLoaderAllocatorDestroyIterator->m_pFirstDomainAssemblyFromSameALCToDelete); while (!domainAssemblyIt.end()) { + // Call AssemblyUnloadStarted event + domainAssemblyIt->GetAssembly()->StartUnload(); // Notify the debugger domainAssemblyIt->NotifyDebuggerUnload(); domainAssemblyIt++; diff --git a/src/tests/profiler/assembly/ALCTest.cs b/src/tests/profiler/assembly/ALCTest.cs new file mode 100644 index 0000000000000..edc3c18421bec --- /dev/null +++ b/src/tests/profiler/assembly/ALCTest.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Reflection; + +namespace Profiler.Tests +{ + class ALCTest + { + static readonly Guid AssemblyProfilerGuid = new Guid("19A49007-9E58-4E31-B655-83EC3B924E7B"); + + public static int RunTest(String[] args) + { + string currentAssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string testAssemblyFullPath = Path.Combine(currentAssemblyDirectory, "..", "TestFile", "TestFile.dll"); + + int exitCode = TestLibrary.Utilities.ExecuteAndUnload(testAssemblyFullPath, args); + return exitCode; + } + + public static int Main(string[] args) + { + if (args.Length > 0 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase)) + { + return RunTest(args); + } + + return ProfilerTestRunner.Run(profileePath: System.Reflection.Assembly.GetExecutingAssembly().Location, + testName: "ALCTest", + profilerClsid: AssemblyProfilerGuid); + } + } +} diff --git a/src/tests/profiler/assembly/ALCTest.csproj b/src/tests/profiler/assembly/ALCTest.csproj new file mode 100644 index 0000000000000..f20fc4207d6ea --- /dev/null +++ b/src/tests/profiler/assembly/ALCTest.csproj @@ -0,0 +1,19 @@ + + + .NETCoreApp + exe + true + true + + true + + + + + + + + diff --git a/src/tests/profiler/assembly/TestFile.cs b/src/tests/profiler/assembly/TestFile.cs new file mode 100644 index 0000000000000..074b25e1547bc --- /dev/null +++ b/src/tests/profiler/assembly/TestFile.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Profiler.Tests +{ + class TestFile + { + + public static int Main(string[] args) + { + return 100; + } + } +} diff --git a/src/tests/profiler/assembly/TestFile.csproj b/src/tests/profiler/assembly/TestFile.csproj new file mode 100644 index 0000000000000..f47300c2a5258 --- /dev/null +++ b/src/tests/profiler/assembly/TestFile.csproj @@ -0,0 +1,14 @@ + + + .NETCoreApp + exe + true + true + + + + + + + + diff --git a/src/tests/profiler/native/CMakeLists.txt b/src/tests/profiler/native/CMakeLists.txt index 7ff5152f95539..59a753c56c91c 100644 --- a/src/tests/profiler/native/CMakeLists.txt +++ b/src/tests/profiler/native/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.20) project(Profiler) set(SOURCES + assemblyprofiler/assemblyprofiler.cpp eltprofiler/slowpatheltprofiler.cpp eventpipeprofiler/eventpipereadingprofiler.cpp eventpipeprofiler/eventpipewritingprofiler.cpp diff --git a/src/tests/profiler/native/assemblyprofiler/assemblyprofiler.cpp b/src/tests/profiler/native/assemblyprofiler/assemblyprofiler.cpp new file mode 100644 index 0000000000000..fd105cba81af7 --- /dev/null +++ b/src/tests/profiler/native/assemblyprofiler/assemblyprofiler.cpp @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "assemblyprofiler.h" + +GUID AssemblyProfiler::GetClsid() +{ + GUID clsid = { 0x19A49007, 0x9E58, 0x4E31,{ 0xB6, 0x55, 0x83, 0xEC, 0x3B, 0x92, 0x4E, 0x7B } }; + return clsid; +} + +HRESULT AssemblyProfiler::Initialize(IUnknown* pICorProfilerInfoUnk) +{ + Profiler::Initialize(pICorProfilerInfoUnk); + + return S_OK; +} + +HRESULT AssemblyProfiler::Shutdown() +{ + Profiler::Shutdown(); + + if (_assemblyUnloadStartedCount != _assemblyUnloadFinishedCount) + { + printf("AssemblyProfiler::Shutdown: FAIL: Expected AssemblyUnloadStarted and AssemblyUnloadFinished to be called the same number of times\n"); + } + else + { + printf("PROFILER TEST PASSES\n"); + } + + fflush(stdout); + return S_OK; +} + +HRESULT AssemblyProfiler::AssemblyUnloadStarted(AssemblyID assemblyId) +{ + SHUTDOWNGUARD(); + + _assemblyUnloadStartedCount++; + return S_OK; +} + +HRESULT AssemblyProfiler::AssemblyUnloadFinished(AssemblyID assemblyId, HRESULT hrStatus) +{ + SHUTDOWNGUARD(); + + _assemblyUnloadFinishedCount++; + return S_OK; +} diff --git a/src/tests/profiler/native/assemblyprofiler/assemblyprofiler.h b/src/tests/profiler/native/assemblyprofiler/assemblyprofiler.h new file mode 100644 index 0000000000000..0d77e7c67c986 --- /dev/null +++ b/src/tests/profiler/native/assemblyprofiler/assemblyprofiler.h @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "../profiler.h" + +class AssemblyProfiler : public Profiler +{ +public: + AssemblyProfiler() : Profiler(), + _assemblyUnloadStartedCount(0), + _assemblyUnloadFinishedCount(0) + {} + + static GUID GetClsid(); + virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk); + virtual HRESULT STDMETHODCALLTYPE Shutdown(); + virtual HRESULT STDMETHODCALLTYPE AssemblyUnloadStarted(AssemblyID assemblyId); + virtual HRESULT STDMETHODCALLTYPE AssemblyUnloadFinished(AssemblyID assemblyId, HRESULT hrStatus); + +private: + std::atomic _assemblyUnloadStartedCount; + std::atomic _assemblyUnloadFinishedCount; +}; diff --git a/src/tests/profiler/native/classfactory.cpp b/src/tests/profiler/native/classfactory.cpp index 7d8aa7942e5d9..c1aec6af53b29 100644 --- a/src/tests/profiler/native/classfactory.cpp +++ b/src/tests/profiler/native/classfactory.cpp @@ -19,6 +19,7 @@ #include "multiple/multiple.h" #include "inlining/inlining.h" #include "moduleload/moduleload.h" +#include "assemblyprofiler/assemblyprofiler.h" ClassFactory::ClassFactory(REFCLSID clsid) : refCount(0), clsid(clsid) { @@ -134,6 +135,10 @@ HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFI { profiler = new ModuleLoad(); } + else if (clsid == AssemblyProfiler::GetClsid()) + { + profiler = new AssemblyProfiler(); + } else { printf("No profiler found in ClassFactory::CreateInstance. Did you add your profiler to the list?\n");