diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index 506d9bd5320f54..5d22c457f23f8a 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -169,6 +169,7 @@ + @@ -176,6 +177,21 @@ + + + + + + + + + + + + + + + diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 1437fc59feb482..fcb13923813afe 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -11,6 +11,14 @@ set(CMAKE_CXX_FLAGS_CHECKED "") set(CMAKE_EXE_LINKER_FLAGS_CHECKED "") set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "") +if(NOT MONO_LIB_NAME) + set(MONO_LIB_NAME "monosgen-2.0") +endif() + +if(NOT MONO_SHARED_LIB_NAME) + set(MONO_SHARED_LIB_NAME "$(MONO_LIB_NAME)") +endif() + include(GNUInstallDirs) include(CheckIncludeFile) include(CheckFunctionExists) @@ -106,7 +114,6 @@ if(DISABLE_INTERPRETER) endif() add_definitions(-DHAVE_CONFIG_H) -add_definitions(-DMONO_DLL_EXPORT) if(GCC) add_definitions(-g) # TODO: should this really be on by default? @@ -652,6 +659,18 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") endif() ### End of debug build checks +###################################### +# COMPONENT BUILD CHECKS +###################################### +if(DISABLE_COMPONENTS AND NOT STATIC_COMPONENTS) + set(STATIC_COMPONENTS 1) +endif() + +if(DISABLE_LINK_STATIC_COMPONENTS AND NOT STATIC_COMPONENTS) + set(STATIC_COMPONENTS 1) +endif() +### End of component build checks + ###################################### # OTHER CHECKS ###################################### diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index 259fff72457acd..b466563394a041 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -1052,9 +1052,11 @@ /* Enable runtime support for metadata updates */ #cmakedefine ENABLE_METADATA_UPDATE 1 +/* Enable static linking of mono runtime components */ +#cmakedefine STATIC_COMPONENTS + #if defined(ENABLE_LLVM) && defined(HOST_WIN32) && defined(TARGET_WIN32) && (!defined(TARGET_AMD64) || !defined(_MSC_VER)) #error LLVM for host=Windows and target=Windows is only supported on x64 MSVC build. #endif #endif - diff --git a/src/mono/cmake/options.cmake b/src/mono/cmake/options.cmake index 56da20953393db..b18f3aa4b1aaf4 100644 --- a/src/mono/cmake/options.cmake +++ b/src/mono/cmake/options.cmake @@ -53,6 +53,7 @@ option (ENABLE_CHECKED_BUILD_THREAD "Enable runtime history of per-thread coop s option (ENABLE_CHECKED_BUILD_METADATA "Enable runtime checks of mempool references between metadata images (must set env var MONO_CHECK_MODE=metadata)") option (ENABLE_METADATA_UPDATE "Enable runtime support for metadata updates") option (ENABLE_MSCORDBI "Generate mscordbi to support icordbg interface") +option (STATIC_COMPONENTS "Compile mono runtime components as static (not dynamic) libraries") set (GC_SUSPEND "default" CACHE STRING "GC suspend method (default, preemptive, coop, hybrid)") set (CHECKED_BUILD "" CACHE STRING "Set ENABLE_CHECKED_BUILD_ options at once. Comma-separated list of lowercase ENABLE_CHECKED_BUILD_ options ie. 'gc,threads,private_types' etc.") @@ -60,3 +61,4 @@ set (ENABLE_MINIMAL "" CACHE STRING "Set many DISABLE_ options at once. Comma-se set (AOT_TARGET_TRIPLE "" CACHE STRING "Target triple for AOT cross compiler") set (AOT_OFFSETS_FILE "" CACHE STRING "Offsets file for AOT cross compiler") set (LLVM_PREFIX "" CACHE STRING "Enable LLVM support with LLVM installed at .") + diff --git a/src/mono/mono.proj b/src/mono/mono.proj index c41d29595c8c62..c9b3f7e36ad228 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -19,24 +19,24 @@ .cmd .sh .exe - .dll - .dylib - .dylib - .so - lib - lib + lib + .dylib + .dll + .so + .lib + .a \" python3 python - coreclr.dll - libcoreclr.dylib - libcoreclr.dylib - libcoreclr.so - libmonosgen-2.0.dylib - libmonosgen-2.0.so - libmonosgen-2.0.a - $(CoreClrFileName) - libmonosgen-2.0.a + coreclr + $(LibPrefix)$(CoreClrLibName)$(SharedLibExt) + monosgen-2.0 + $(MonoLibName) + $(CoreClrLibName) + $(LibPrefix)$(MonoSharedLibName)$(SharedLibExt) + $(LibPrefix)$(MonoLibName)$(StaticLibExt) + $(MonoStaticLibFileName) + $(MonoSharedLibFileName) $(Configuration) $(Configuration) $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'tests', 'coreclr', '$(TargetOS).$(Platform).$(CoreClrTestConfig)', 'Tests', 'Core_Root')) @@ -74,6 +74,16 @@ hybrid + + + true + true + true + + + true + + @@ -190,6 +200,8 @@ <_MonoCMakeArgs Condition="'$(CMakeArgs)' != ''" Include="$(CMakeArgs)"/> <_MonoCMakeArgs Condition="'$(MonoEnableLLVM)' == 'true'" Include="-DLLVM_PREFIX=$(MonoLLVMDir.TrimEnd('\/'))" /> <_MonoCMakeArgs Include="-DGC_SUSPEND=$(MonoThreadSuspend)" /> + <_MonoCMakeArgs Include="-DMONO_LIB_NAME=$(MonoLibName)" /> + <_MonoCMakeArgs Include="-DMONO_SHARED_LIB_NAME=$(MonoSharedLibName)" /> @@ -272,10 +284,11 @@ <_MonoMinimal Condition="'$(Configuration)' == 'Release' and '$(MonoEnableAssertMessages)' != 'true'">$(_MonoMinimal),assert_messages - <_MonoCMakeArgs Include="-DENABLE_MINIMAL=jit,portability,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,shared_perfcounters,interpreter,threads,eventpipe,qcalls$(_MonoMinimal)"/> + <_MonoCMakeArgs Include="-DENABLE_MINIMAL=jit,portability,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,shared_perfcounters,interpreter,threads,qcalls$(_MonoMinimal)"/> <_MonoCMakeArgs Include="-DENABLE_INTERP_LIB=1"/> <_MonoCMakeArgs Include="-DDISABLE_ICALL_TABLES=1"/> <_MonoCMakeArgs Include="-DDISABLE_CRASH_REPORTING=1"/> + <_MonoCMakeArgs Include="-DDISABLE_COMPONENTS=1"/> <_MonoCMakeArgs Include="-DENABLE_ICALL_EXPORT=1"/> <_MonoCMakeArgs Include="-DENABLE_LAZY_GC_THREAD_CREATION=1"/> <_MonoCMakeArgs Include="-DENABLE_LLVM_RUNTIME=1"/> @@ -349,7 +362,6 @@ <_MonoCMakeArgs Include="-DENABLE_MINIMAL=ssa,portability,logging" /> <_MonoCMakeArgs Include="-DENABLE_SIGALTSTACK=1"/> <_MonoCMakeArgs Include="-DDISABLE_CRASH_REPORTING=1"/> - <_MonoCMakeArgs Include="-DENABLE_PERFTRACING=0"/> <_MonoCFLAGS Condition="'$(Platform)' == 'arm'" Include="-march=armv7-a" /> <_MonoCFLAGS Condition="'$(Platform)' == 'arm'" Include="-mtune=cortex-a8" /> @@ -396,6 +408,17 @@ <_MonoCMakeArgs Include="-DENABLE_MSCORDBI=1" /> + + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_PAL_TCP=1"/> + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_LISTEN_PORTS=1"/> + <_MonoCMakeArgs Include="-DDISABLE_LINK_STATIC_COMPONENTS=1" /> + + + + + <_MonoCMakeArgs Include="-DSTATIC_COMPONENTS=1" /> + + <_MonoCFLAGSOption>-DCMAKE_C_FLAGS="@(_MonoCPPFLAGS, ' ') @(_MonoCFLAGS, ' ')" <_MonoCXXFLAGSOption>-DCMAKE_CXX_FLAGS="@(_MonoCPPFLAGS, ' ') @(_MonoCXXFLAGS, ' ')" @@ -546,6 +569,7 @@ + @@ -607,14 +631,9 @@ - <_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true'">$(MonoObjDir)out\bin\monosgen-2.0.dll - <_MonoRuntimeFilePath Condition="'$(TargetsOSX)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib - <_MonoRuntimeFilePath Condition="'$(TargetsMacCatalyst)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib - <_MonoRuntimeFilePath Condition="'$(TargetsiOS)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib - <_MonoRuntimeFilePath Condition="'$(TargetstvOS)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib - <_MonoRuntimeFilePath Condition="'$(TargetsBrowser)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.a - <_MonoRuntimeFilePath Condition="'$(_MonoRuntimeFilePath)' == ''">$(MonoObjDir)out\lib\libmonosgen-2.0.so - <_MonoRuntimeStaticFilePath Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsAndroid)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.a + <_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true'">$(MonoObjDir)out\bin\$(MonoFileName) + <_MonoRuntimeFilePath Condition="'$(_MonoRuntimeFilePath)' == ''">$(MonoObjDir)out\lib\$(MonoFileName) + <_MonoRuntimeStaticFilePath Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsAndroid)' == 'true'">$(MonoObjDir)out\lib\$(MonoStaticLibFileName) <_MonoIncludeInterpStaticFiles Condition="'$(TargetsBrowser)' == 'true'">true <_MonoIncludeIcuFiles Condition="'$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'">true @@ -624,11 +643,20 @@ - <_MonoRuntimeArtifacts Include="$(_MonoRuntimeFilePath)"> + <_MonoRuntimeComponentsStaticFilePath Include="$([System.IO.Directory]::GetParent($(_MonoRuntimeFilePath)))\libmono-component-*$(StaticLibExt)" Condition="Exists($(_MonoRuntimeFilePath))" /> + <_MonoRuntimeComponentsSharedFilePath Include="$([System.IO.Directory]::GetParent($(_MonoRuntimeFilePath)))\libmono-component-*$(SharedLibExt)" Condition="Exists($(_MonoRuntimeFilePath))" /> + <_MonoRuntimeArtifacts Include="$(_MonoRuntimeFilePath)" Condition="Exists($(_MonoRuntimeFilePath))"> $(RuntimeBinDir)$(MonoFileName) - <_MonoRuntimeArtifacts Include="$(_MonoRuntimeStaticFilePath)"> - $(RuntimeBinDir)$(MonoStaticFileName) + <_MonoRuntimeArtifacts Include="$(_MonoRuntimeStaticFilePath)" Condition="Exists($(_MonoRuntimeStaticFilePath)) and '$(_MonoRuntimeStaticFilePath)' != '$(_MonoRuntimeFilePath)'"> + $(RuntimeBinDir)$(MonoStaticLibFileName) + + + <_MonoRuntimeArtifacts Include="@(_MonoRuntimeComponentsStaticFilePath)"> + $(RuntimeBinDir)%(_MonoRuntimeComponentsStaticFilePath.Filename)%(_MonoRuntimeComponentsStaticFilePath.Extension) + + <_MonoRuntimeArtifacts Include="@(_MonoRuntimeComponentsSharedFilePath)"> + $(RuntimeBinDir)%(_MonoRuntimeComponentsSharedFilePath.Filename)%(_MonoRuntimeComponentsSharedFilePath.Extension) <_MonoRuntimeArtifacts Include="$(_MonoAotCrossFilePath)"> $(RuntimeBinDir)cross\$(PackageRID)\mono-aot-cross$(ExeExt) @@ -658,11 +686,11 @@ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true' and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-profiler-aot.a"> $(RuntimeBinDir)libmono-profiler-aot.a - <_MonoICorDebugArtifacts Condition="'$(MonoMsCorDbi)' == 'true'" Include="$(MonoObjDir)out\lib\$(LibPrefix)dbgshim$(LibExt)"> - $(RuntimeBinDir)$(LibPrefix)dbgshim$(LibExt) + <_MonoICorDebugArtifacts Condition="'$(MonoMsCorDbi)' == 'true'" Include="$(MonoObjDir)out\lib\$(LibPrefix)dbgshim$(SharedLibExt)"> + $(RuntimeBinDir)$(LibPrefix)dbgshim$(SharedLibExt) - <_MonoICorDebugArtifacts Condition="'$(MonoMsCorDbi)' == 'true'" Include="$(MonoObjDir)out\lib\$(LibPrefix)mscordbi$(LibExt)"> - $(RuntimeBinDir)$(LibPrefix)mscordbi$(LibExt) + <_MonoICorDebugArtifacts Condition="'$(MonoMsCorDbi)' == 'true'" Include="$(MonoObjDir)out\lib\$(LibPrefix)mscordbi$(SharedLibExt)"> + $(RuntimeBinDir)$(LibPrefix)mscordbi$(SharedLibExt) <_IcuArtifacts Condition="'$(_MonoIncludeIcuFiles)' == 'true'" diff --git a/src/mono/mono/CMakeLists.txt b/src/mono/mono/CMakeLists.txt index 817a804b68752c..897a1886ac74b8 100644 --- a/src/mono/mono/CMakeLists.txt +++ b/src/mono/mono/CMakeLists.txt @@ -2,12 +2,6 @@ project(mono) set(subdirs mini profiler) -if(ENABLE_PERFTRACING) - list(APPEND subdirs - eventpipe/test - ) -endif(ENABLE_PERFTRACING) - foreach(dir ${subdirs}) add_subdirectory(${dir}) endforeach() diff --git a/src/mono/mono/component/CMakeLists.txt b/src/mono/mono/component/CMakeLists.txt new file mode 100644 index 00000000000000..276be1a596dce0 --- /dev/null +++ b/src/mono/mono/component/CMakeLists.txt @@ -0,0 +1,131 @@ +# a list of every component. +set(components "") + +# the sources for each individiable component define a new +# component_name-sources_base list for each component, and a +# component_name-stub-sources_base list for the component stub. + +# hot_reload +list(APPEND components + hot_reload +) +set(hot_reload-sources_base + hot_reload.c + hot_reload.h + ) +set(hot_reload-stub-sources_base + hot_reload-stub.c + ) + +# diagnostics_tracing (event_pipe/diagnostics_server) +list(APPEND components + diagnostics_tracing +) + +set(SHARED_EVENTPIPE_INCLUDE_PATH "../../../native/") +set(SHARED_EVENTPIPE_SOURCE_PATH "../../../native/eventpipe/") +set(MONO_EVENTPIPE_SHIM_SOURCE_PATH "../eventpipe/") + +include(${MONO_EVENTPIPE_SHIM_SOURCE_PATH}/CMakeLists.txt) + +include_directories( + ${SHARED_EVENTPIPE_INCLUDE_PATH} + ${MONO_EVENTPIPE_SHIM_SOURCE_PATH} +) + +set(diagnostics_tracing-sources_base + ${eventpipe_sources} + ${diagnostic_server_sources} + event_pipe.c + event_pipe.h + diagnostics_server.c + diagnostics_server.h + ) +set(diagnostics_tracing-stub-sources_base + event_pipe-stub.c + diagnostics_server-stub.c + ) + +# from here down, all the components are treated in the same way + +# a generic component interface that all components implement +add_library(component_base INTERFACE) +target_sources(component_base INTERFACE + ../component/component.h +) + +if(DISABLE_COMPONENTS OR (NOT STATIC_COMPONENTS AND HOST_WIN32)) + set(DISABLE_COMPONENT_OBJECTS 1) +endif() + +# define a component_name-objects and component_name-stub-objects object +# targets with the relative source file names +foreach(component IN LISTS components) + addprefix("${component}-sources" ../component "${${component}-sources_base}") + if(NOT DISABLE_COMPONENT_OBJECTS) + add_library("${component}-objects" OBJECT "${${component}-sources}") + target_link_libraries("${component}-objects" component_base) + endif() + addprefix("${component}-stub-sources" ../component "${${component}-stub-sources_base}") + add_library("${component}-stub-objects" OBJECT "${${component}-stub-sources}") + target_link_libraries("${component}-stub-objects" component_base) +endforeach() + +if(NOT DISABLE_COMPONENTS AND NOT STATIC_COMPONENTS) + # define a shared library for each component + foreach(component IN LISTS components) + if(HOST_WIN32) + add_library("mono-component-${component}" SHARED "${${component}-sources}") + target_compile_definitions("mono-component-${component}" PRIVATE -DCOMPILING_COMPONENT_DYNAMIC;-DMONO_DLL_IMPORT) + else() + add_library("mono-component-${component}" SHARED $) + endif() + # each shared library component gets its own copy for eglib + # + # FIXME: this is bad for things like the g_log_set_default_handler/g_logv + # which use global state - we should move those functions into + # monosgen-shared and get them via dynamic linking. + target_sources("mono-component-${component}" PRIVATE $) + if(NOT DISABLE_SHARED_LIBS) + # If we disable shared libs, but build dynamic components we would need + # to enable allowing undefined symbols here (presumably to be resolved + # from the mono-sgen executable. But that's not a configuration we + # should need in dotnet/runtime. + target_link_libraries("mono-component-${component}" PRIVATE monosgen-shared) + endif() + target_link_libraries("mono-component-${component}" PRIVATE ${OS_LIBS}) + install(TARGETS "mono-component-${component}" LIBRARY) + endforeach() + +elseif(NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS) + + #define a static library for each component and component stub + foreach(component IN LISTS components) + add_library("mono-component-${component}-static" STATIC $) + install(TARGETS "mono-component-${component}-static" LIBRARY) + endforeach() + foreach(component IN LISTS components) + add_library("mono-component-${component}-stub-static" STATIC $) + install(TARGETS "mono-component-${component}-stub-static" LIBRARY) + endforeach() + + # define a list of mono-components objects for mini if building a shared libmono with static-linked components + set(mono-components-objects "") + foreach(component IN LISTS components) + list(APPEND mono-components-objects $) + endforeach() + +endif() + +# define a list of mono-components-stubs objects that will be linked into +# the runtime to be used as fallbacks if the dynamic components are not +# available or when only static component stubs are requested. +set(mono-components-stub-objects "") +foreach(component IN LISTS components) + list(APPEND mono-components-stub-objects $) +endforeach() + + +# component tests +set(MONO_EVENTPIPE_TEST_SOURCE_PATH "${MONO_EVENTPIPE_SHIM_SOURCE_PATH}/test") +include(${MONO_EVENTPIPE_TEST_SOURCE_PATH}/CMakeLists.txt) diff --git a/src/mono/mono/component/component.h b/src/mono/mono/component/component.h new file mode 100644 index 00000000000000..afc15a118739a0 --- /dev/null +++ b/src/mono/mono/component/component.h @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#ifndef _MONO_COMPONENT_COMPONENT_H +#define _MONO_COMPONENT_COMPONENT_H + +#include +#ifndef __cplusplus +#include +#endif // __cplusplus + +#define MONO_COMPONENT_ITF_VERSION 1 + +typedef struct _MonoComponent MonoComponent; + +typedef bool (*MonoComponent_AvailableFn) (void); + +struct _MonoComponent { + intptr_t itf_version; + MonoComponent_AvailableFn available; +}; + +#endif/*_MONO_COMPONENT_COMPONENT_H*/ diff --git a/src/mono/mono/component/diagnostics_server-stub.c b/src/mono/mono/component/diagnostics_server-stub.c new file mode 100644 index 00000000000000..0a8f6649cda25a --- /dev/null +++ b/src/mono/mono/component/diagnostics_server-stub.c @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include +#include "mono/component/diagnostics_server.h" +#include "mono/metadata/components.h" + +/* + * Forward declares of all static functions. + */ + +static bool +diagnostics_server_stub_available (void); + +static bool +diagnostics_server_stub_init (void); + +static bool +diagnostics_server_stub_shutdown (void); + +static void +diagnostics_server_stub_pause_for_diagnostics_monitor (void); + +static void +diagnostics_server_stub_disable (void); + +static MonoComponentDiagnosticsServer fn_table = { + { MONO_COMPONENT_ITF_VERSION, &diagnostics_server_stub_available }, + &diagnostics_server_stub_init, + &diagnostics_server_stub_shutdown, + &diagnostics_server_stub_pause_for_diagnostics_monitor, + &diagnostics_server_stub_disable +}; + +static bool +diagnostics_server_stub_available (void) +{ + return false; +} + +static bool +diagnostics_server_stub_init (void) +{ + return true; +} + +static bool +diagnostics_server_stub_shutdown (void) +{ + return true; +} + +static void +diagnostics_server_stub_pause_for_diagnostics_monitor (void) +{ +} + +static void +diagnostics_server_stub_disable (void) +{ +} + +#ifdef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server_init (void) +{ + return mono_component_diagnostics_server_stub_init (); +} +#endif + +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server_stub_init (void) +{ + return &fn_table; +} diff --git a/src/mono/mono/component/diagnostics_server.c b/src/mono/mono/component/diagnostics_server.c new file mode 100644 index 00000000000000..c03b1296038d9d --- /dev/null +++ b/src/mono/mono/component/diagnostics_server.c @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include +#include +#include +#include +#include + +#ifndef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server_init (void); +#endif + +static bool +diagnostics_server_available (void); + +static MonoComponentDiagnosticsServer fn_table = { + { MONO_COMPONENT_ITF_VERSION, &diagnostics_server_available }, + &ds_server_init, + &ds_server_shutdown, + &ds_server_pause_for_diagnostics_monitor, + &ds_server_disable +}; + +static bool +diagnostics_server_available (void) +{ + return true; +} + +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server_init (void) +{ + return &fn_table; +} diff --git a/src/mono/mono/component/diagnostics_server.h b/src/mono/mono/component/diagnostics_server.h new file mode 100644 index 00000000000000..cbc32eb9192d1a --- /dev/null +++ b/src/mono/mono/component/diagnostics_server.h @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#ifndef _MONO_COMPONENT_DIAGNOSTICS_SERVER_H +#define _MONO_COMPONENT_DIAGNOSTICS_SERVER_H + +#include "mono/component/component.h" +#include "mono/utils/mono-compiler.h" + +#ifndef ENABLE_PERFTRACING +#define ENABLE_PERFTRACING +#endif + +#include +#include + +typedef struct _MonoComponentDiagnosticsServer { + MonoComponent component; + bool (*init) (void); + bool (*shutdown) (void); + void (*pause_for_diagnostics_monitor) (void); + void (*disable) (void); +} MonoComponentDiagnosticsServer; + +#ifdef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server_init (void); +#endif + +#endif /*_MONO_COMPONENT_DIAGNOSTICS_SERVER_H*/ diff --git a/src/mono/mono/component/event_pipe-stub.c b/src/mono/mono/component/event_pipe-stub.c new file mode 100644 index 00000000000000..ce008d05b4f297 --- /dev/null +++ b/src/mono/mono/component/event_pipe-stub.c @@ -0,0 +1,263 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include +#include "mono/component/event_pipe.h" +#include "mono/metadata/components.h" + +static EventPipeSessionID _dummy_session_id; + +static uint8_t _max_event_pipe_type_size [256]; + +/* + * Forward declares of all static functions. + */ + +static bool +event_pipe_stub_available (void); + +static void +event_pipe_stub_init (void); + +static void +event_pipe_stub_finish_init (void); + +static void +event_pipe_stub_shutdown (void); + +static EventPipeSessionID +event_pipe_stub_enable ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfigurationNative *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + EventPipeSessionSynchronousCallback sync_callback); + +static void +event_pipe_stub_disable (EventPipeSessionID id); + +static bool +event_pipe_stub_get_next_event ( + EventPipeSessionID session_id, + EventPipeEventInstanceData *instance); + +static EventPipeWaitHandle +event_pipe_stub_get_wait_handle (EventPipeSessionID session_id); + +static void +event_pipe_stub_start_streaming (EventPipeSessionID session_id); + +static void +event_pipe_stub_write_event_2 ( + EventPipeEvent *ep_event, + EventData *event_data, + uint32_t event_data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static EventPipeProvider * +event_pipe_stub_create_provider ( + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + EventPipeCallbackDataFree callback_data_free_func, + void *callback_data); + +static void +event_pipe_stub_delete_provider (EventPipeProvider *provider); + +static EventPipeProvider * +event_pipe_stub_get_provider (const ep_char8_t *provider_name); + +static EventPipeEvent * +event_pipe_stub_provider_add_event ( + EventPipeProvider *provider, + uint32_t event_id, + uint64_t keywords, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len); + +static bool +event_pipe_stub_get_session_info ( + EventPipeSessionID session_id, + EventPipeSessionInfo *instance); + +static bool +event_pipe_stub_thread_ctrl_activity_id ( + EventPipeActivityControlCode activity_control_code, + uint8_t *activity_id, + uint32_t activity_id_len); + +static bool +event_pipe_stub_write_event_ee_startup_start (void); + + +static MonoComponentEventPipe fn_table = { + { MONO_COMPONENT_ITF_VERSION, &event_pipe_stub_available }, + &event_pipe_stub_init, + &event_pipe_stub_finish_init, + &event_pipe_stub_shutdown, + &event_pipe_stub_enable, + &event_pipe_stub_disable, + &event_pipe_stub_get_next_event, + &event_pipe_stub_get_wait_handle, + &event_pipe_stub_start_streaming, + &event_pipe_stub_write_event_2, + &event_pipe_stub_create_provider, + &event_pipe_stub_delete_provider, + &event_pipe_stub_get_provider, + &event_pipe_stub_provider_add_event, + &event_pipe_stub_get_session_info, + &event_pipe_stub_thread_ctrl_activity_id, + &event_pipe_stub_write_event_ee_startup_start +}; + +static bool +event_pipe_stub_available (void) +{ + return false; +} + +static void +event_pipe_stub_init (void) +{ +} + +static void +event_pipe_stub_finish_init (void) +{ +} + +static void +event_pipe_stub_shutdown (void) +{ +} + +static EventPipeSessionID +event_pipe_stub_enable ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfigurationNative *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + EventPipeSessionSynchronousCallback sync_callback) +{ + return (EventPipeSessionID)&_dummy_session_id; +} + +static void +event_pipe_stub_disable (EventPipeSessionID id) +{ +} + +static bool +event_pipe_stub_get_next_event ( + EventPipeSessionID session_id, + EventPipeEventInstanceData *instance) +{ + return false; +} + +static EventPipeWaitHandle +event_pipe_stub_get_wait_handle (EventPipeSessionID session_id) +{ + return (EventPipeWaitHandle)NULL; +} + +static void +event_pipe_stub_start_streaming (EventPipeSessionID session_id) +{ +} + +static void +event_pipe_stub_write_event_2 ( + EventPipeEvent *ep_event, + EventData *event_data, + uint32_t event_data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ +} + +static EventPipeProvider * +event_pipe_stub_create_provider ( + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + EventPipeCallbackDataFree callback_data_free_func, + void *callback_data) +{ + return (EventPipeProvider *)_max_event_pipe_type_size; +} + +static void +event_pipe_stub_delete_provider (EventPipeProvider *provider) +{ +} + +static EventPipeProvider * +event_pipe_stub_get_provider (const ep_char8_t *provider_name) +{ + return NULL; +} + +static EventPipeEvent * +event_pipe_stub_provider_add_event ( + EventPipeProvider *provider, + uint32_t event_id, + uint64_t keywords, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len) +{ + return (EventPipeEvent *)_max_event_pipe_type_size; +} + +static bool +event_pipe_stub_get_session_info ( + EventPipeSessionID session_id, + EventPipeSessionInfo *instance) +{ + return false; +} + +static bool +event_pipe_stub_thread_ctrl_activity_id ( + EventPipeActivityControlCode activity_control_code, + uint8_t *activity_id, + uint32_t activity_id_len) +{ + return false; +} + +static bool +event_pipe_stub_write_event_ee_startup_start (void) +{ + return true; +} + +#ifdef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentEventPipe * +mono_component_event_pipe_init (void) +{ + return mono_component_event_pipe_stub_init (); +} +#endif + +MonoComponentEventPipe * +mono_component_event_pipe_stub_init (void) +{ + return &fn_table; +} diff --git a/src/mono/mono/component/event_pipe.c b/src/mono/mono/component/event_pipe.c new file mode 100644 index 00000000000000..74588de587e84b --- /dev/null +++ b/src/mono/mono/component/event_pipe.c @@ -0,0 +1,245 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +struct _EventPipeProviderConfigurationNative { + gunichar2 *provider_name; + uint64_t keywords; + uint32_t logging_level; + gunichar2 *filter_data; +}; + +struct _EventPipeSessionInfo { + int64_t starttime_as_utc_filetime; + int64_t start_timestamp; + int64_t timestamp_frequency; +}; + +struct _EventPipeEventInstanceData { + intptr_t provider_id; + uint32_t event_id; + uint32_t thread_id; + int64_t timestamp; + uint8_t activity_id [EP_ACTIVITY_ID_SIZE]; + uint8_t related_activity_id [EP_ACTIVITY_ID_SIZE]; + const uint8_t *payload; + uint32_t payload_len; +}; + +/* + * Forward declares of all static functions. + */ + +static bool +event_pipe_available (void); + +static EventPipeSessionID +event_pipe_enable ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfigurationNative *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + EventPipeSessionSynchronousCallback sync_callback); + +static bool +event_pipe_get_next_event ( + EventPipeSessionID session_id, + EventPipeEventInstanceData *instance); + +static bool +event_pipe_get_session_info ( + EventPipeSessionID session_id, + EventPipeSessionInfo *instance); + +static bool +event_pipe_thread_ctrl_activity_id( + EventPipeActivityControlCode activity_control_code, + uint8_t *activity_id, + uint32_t activity_id_len); + +static MonoComponentEventPipe fn_table = { + { MONO_COMPONENT_ITF_VERSION, &event_pipe_available }, + &ep_init, + &ep_finish_init, + &ep_shutdown, + &event_pipe_enable, + &ep_disable, + &event_pipe_get_next_event, + &ep_get_wait_handle, + &ep_start_streaming, + &ep_write_event_2, + &ep_create_provider, + &ep_delete_provider, + &ep_get_provider, + &ep_provider_add_event, + &event_pipe_get_session_info, + &event_pipe_thread_ctrl_activity_id, + &ep_rt_mono_write_event_ee_startup_start +}; + +static bool +event_pipe_available (void) +{ + return true; +} + +static EventPipeSessionID +event_pipe_enable ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfigurationNative *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + EventPipeSessionSynchronousCallback sync_callback) +{ + ERROR_DECL (error); + EventPipeSessionID session_id = 0; + + EventPipeProviderConfiguration *config_providers = g_new0 (EventPipeProviderConfiguration, providers_len); + + if (config_providers) { + for (int i = 0; i < providers_len; ++i) { + ep_provider_config_init ( + &config_providers[i], + providers[i].provider_name ? mono_utf16_to_utf8 (providers[i].provider_name, g_utf16_len (providers[i].provider_name), error) : NULL, + providers [i].keywords, + (EventPipeEventLevel)providers [i].logging_level, + providers[i].filter_data ? mono_utf16_to_utf8 (providers[i].filter_data, g_utf16_len (providers[i].filter_data), error) : NULL); + } + } + + session_id = ep_enable ( + output_path, + circular_buffer_size_in_mb, + config_providers, + providers_len, + session_type, + format, + rundown_requested, + stream, + sync_callback); + + if (config_providers) { + for (int i = 0; i < providers_len; ++i) { + ep_provider_config_fini (&config_providers[i]); + g_free ((ep_char8_t *)ep_provider_config_get_provider_name (&config_providers[i])); + g_free ((ep_char8_t *)ep_provider_config_get_filter_data (&config_providers[i])); + } + } + + return session_id; +} + +static bool +event_pipe_get_next_event ( + EventPipeSessionID session_id, + EventPipeEventInstanceData *instance) +{ + EP_ASSERT (instance != NULL); + + EventPipeEventInstance *const next_instance = ep_get_next_event (session_id); + EventPipeEventInstanceData *const data = (EventPipeEventInstanceData *)instance; + if (next_instance && data) { + const EventPipeEvent *const ep_event = ep_event_instance_get_ep_event (next_instance); + if (ep_event) { + data->provider_id = (intptr_t)ep_event_get_provider (ep_event); + data->event_id = ep_event_get_event_id (ep_event); + } + data->thread_id = ep_event_instance_get_thread_id (next_instance); + data->timestamp = ep_event_instance_get_timestamp (next_instance); + memcpy (&data->activity_id, ep_event_instance_get_activity_id_cref (next_instance), EP_ACTIVITY_ID_SIZE); + memcpy (&data->related_activity_id, ep_event_instance_get_related_activity_id_cref (next_instance), EP_ACTIVITY_ID_SIZE); + data->payload = ep_event_instance_get_data (next_instance); + data->payload_len = ep_event_instance_get_data_len (next_instance); + } + + return next_instance != NULL; +} + +static bool +event_pipe_get_session_info ( + EventPipeSessionID session_id, + EventPipeSessionInfo *instance) +{ + bool result = false; + if (instance) { + EventPipeSession *session = ep_get_session ((EventPipeSessionID)session_id); + if (session) { + instance->starttime_as_utc_filetime = ep_session_get_session_start_time (session); + instance->start_timestamp = ep_session_get_session_start_timestamp (session); + instance->timestamp_frequency = ep_perf_frequency_query (); + result = true; + } + } + + return result; +} + +static bool +event_pipe_thread_ctrl_activity_id ( + EventPipeActivityControlCode activity_control_code, + uint8_t *activity_id, + uint32_t activity_id_len) +{ + bool result = true; + ep_rt_thread_activity_id_handle_t activity_id_handle = ep_thread_get_activity_id_handle (); + + if (activity_id_handle == NULL) + return false; + + uint8_t current_activity_id [EP_ACTIVITY_ID_SIZE]; + switch (activity_control_code) { + case EP_ACTIVITY_CONTROL_GET_ID: + ep_thread_get_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_SET_ID: + ep_thread_set_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_CREATE_ID: + ep_thread_create_activity_id (activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_GET_SET_ID: + ep_thread_get_activity_id (activity_id_handle, current_activity_id, EP_ACTIVITY_ID_SIZE); + ep_thread_set_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); + memcpy (activity_id, current_activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_CREATE_SET_ID: + ep_thread_get_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); + ep_thread_create_activity_id (current_activity_id, EP_ACTIVITY_ID_SIZE); + ep_thread_set_activity_id (activity_id_handle, current_activity_id, EP_ACTIVITY_ID_SIZE); + break; + default: + result = false; + break; + } + + return result; +} + +#ifndef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentEventPipe * +mono_component_event_pipe_init (void); +#endif + +MonoComponentEventPipe * +mono_component_event_pipe_init (void) +{ + return &fn_table; +} diff --git a/src/mono/mono/component/event_pipe.h b/src/mono/mono/component/event_pipe.h new file mode 100644 index 00000000000000..76ac80d9f484f1 --- /dev/null +++ b/src/mono/mono/component/event_pipe.h @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#ifndef _MONO_COMPONENT_EVENT_PIPE_H +#define _MONO_COMPONENT_EVENT_PIPE_H + +#include +#include "mono/utils/mono-compiler.h" + +#ifndef ENABLE_PERFTRACING +#define ENABLE_PERFTRACING +#endif + +#include +#include + +typedef enum _EventPipeActivityControlCode { + EP_ACTIVITY_CONTROL_GET_ID = 1, + EP_ACTIVITY_CONTROL_SET_ID = 2, + EP_ACTIVITY_CONTROL_CREATE_ID = 3, + EP_ACTIVITY_CONTROL_GET_SET_ID = 4, + EP_ACTIVITY_CONTROL_CREATE_SET_ID = 5 +} EventPipeActivityControlCode; + +typedef struct _EventPipeProviderConfigurationNative EventPipeProviderConfigurationNative; +typedef struct _EventPipeEventInstanceData EventPipeEventInstanceData; +typedef struct _EventPipeSessionInfo EventPipeSessionInfo; + +/* + * EventPipe. + */ + +typedef void +(*event_pipe_component_init_func) (void); + +typedef void +(*event_pipe_component_finish_init_func) (void); + +typedef void +(*event_pipe_component_shutdown_func) (void); + +typedef EventPipeSessionID +(*event_pipe_component_enable_func) ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfigurationNative *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + EventPipeSessionSynchronousCallback sync_callback); + +typedef void +(*event_pipe_component_disable_func) (EventPipeSessionID id); + +typedef bool +(*event_pipe_component_get_next_event_func) ( + EventPipeSessionID session_id, + EventPipeEventInstanceData *instance); + +typedef EventPipeWaitHandle +(*event_pipe_component_get_wait_handle_func) (EventPipeSessionID session_id); + +typedef void +(*event_pipe_component_start_streaming_func) (EventPipeSessionID session_id); + +typedef void +(*event_pipe_component_write_event_2_func) ( + EventPipeEvent *ep_event, + EventData *event_data, + uint32_t event_data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +/* + * EventPipeProvider. + */ + +typedef EventPipeProvider * +(*event_pipe_component_create_provider_func) ( + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + EventPipeCallbackDataFree callback_data_free_func, + void *callback_data); + +typedef void +(*event_pipe_component_delete_provider_func) (EventPipeProvider *provider); + +typedef EventPipeProvider * +(*event_pipe_component_get_provider_func) (const ep_char8_t *provider_name); + +typedef EventPipeEvent * +(*event_pipe_component_provider_add_event_func) ( + EventPipeProvider *provider, + uint32_t event_id, + uint64_t keywords, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len); + +/* + * EventPipeSession. + */ + +typedef bool +(*event_pipe_component_get_session_info_func) ( + EventPipeSessionID session_id, + EventPipeSessionInfo *instance); + +/* + * EventPipeThread. + */ + +typedef bool +(*event_pipe_component_thread_ctrl_activity_id_func)( + EventPipeActivityControlCode activity_control_code, + uint8_t *activity_id, + uint32_t activity_id_len); + +/* + * EventPipe Native Events. + */ + +typedef bool +(*event_pipe_component_write_event_ee_startup_start_func)(void); + +/* + * MonoComponentEventPipe function table. + */ + +typedef struct _MonoComponentEventPipe { + MonoComponent component; + event_pipe_component_init_func init; + event_pipe_component_finish_init_func finish_init; + event_pipe_component_shutdown_func shutdown; + event_pipe_component_enable_func enable; + event_pipe_component_disable_func disable; + event_pipe_component_get_next_event_func get_next_event; + event_pipe_component_get_wait_handle_func get_wait_handle; + event_pipe_component_start_streaming_func start_streaming; + event_pipe_component_write_event_2_func write_event_2; + event_pipe_component_create_provider_func create_provider; + event_pipe_component_delete_provider_func delete_provider; + event_pipe_component_get_provider_func get_provider; + event_pipe_component_provider_add_event_func provider_add_event; + event_pipe_component_get_session_info_func get_session_info; + event_pipe_component_thread_ctrl_activity_id_func thread_ctrl_activity_id; + event_pipe_component_write_event_ee_startup_start_func write_event_ee_startup_start; +} MonoComponentEventPipe; + +#ifdef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentEventPipe * +mono_component_event_pipe_init (void); +#endif + +#endif /*_MONO_COMPONENT_EVENT_PIPE_H*/ diff --git a/src/mono/mono/component/hot_reload-stub.c b/src/mono/mono/component/hot_reload-stub.c new file mode 100644 index 00000000000000..7f1fdd20f03c20 --- /dev/null +++ b/src/mono/mono/component/hot_reload-stub.c @@ -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 +#include +#include "mono/component/component.h" +#include "mono/component/hot_reload.h" +#include "mono/metadata/components.h" +#include "mono/utils/mono-compiler.h" +#include "mono/utils/mono-error-internals.h" + +static bool +hot_reload_stub_available (void); + +static void +hot_reload_stub_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); + +static MonoComponentHotReload fn_table = { + { MONO_COMPONENT_ITF_VERSION, &hot_reload_stub_available }, + &hot_reload_stub_apply_changes, +}; + +#ifdef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentHotReload * +mono_component_hot_reload_init (void) +{ + return mono_component_hot_reload_stub_init (); +} +#endif + +MonoComponentHotReload * +mono_component_hot_reload_stub_init (void) +{ + return &fn_table; +} + +bool +hot_reload_stub_available (void) +{ + return false; +} + +void +hot_reload_stub_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error) +{ + mono_error_set_not_supported (error, "Hot reload not supported in this runtime."); +} + diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c new file mode 100644 index 00000000000000..2963eb6648914e --- /dev/null +++ b/src/mono/mono/component/hot_reload.c @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include +#include + +#include + +#include + +#ifndef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentHotReload * +mono_component_hot_reload_init (void); +#endif + +static bool +hot_reload_available (void); + +static void +hot_reload_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); + +static MonoComponentHotReload fn_table = { + { MONO_COMPONENT_ITF_VERSION, &hot_reload_available }, + &hot_reload_apply_changes, +}; + +MonoComponentHotReload * +mono_component_hot_reload_init (void) +{ + /* TODO: implement me */ + return &fn_table; +} + +static bool +hot_reload_available (void) +{ + return true; +} + +static void +hot_reload_apply_changes (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error) +{ + /* TODO: implement me */ +} diff --git a/src/mono/mono/component/hot_reload.h b/src/mono/mono/component/hot_reload.h new file mode 100644 index 00000000000000..eb56b51006d12a --- /dev/null +++ b/src/mono/mono/component/hot_reload.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. +// + +#ifndef _MONO_COMPONENT_HOT_RELOAD_H +#define _MONO_COMPONENT_HOT_RELOAD_H + +#include +#include "mono/metadata/object-forward.h" +#include "mono/utils/mono-error.h" +#include "mono/utils/mono-compiler.h" +#include "mono/component/component.h" + +typedef struct _MonoComponentHotReload { + MonoComponent component; + void (*apply_changes) (MonoImage *base_image, gconstpointer dmeta, uint32_t dmeta_len, gconstpointer dil, uint32_t dil_len, MonoError *error); +} MonoComponentHotReload; + +#ifdef STATIC_COMPONENTS +MONO_COMPONENT_EXPORT_ENTRYPOINT +MonoComponentHotReload * +mono_component_hot_reload_init (void); +#endif + +#endif/*_MONO_COMPONENT_HOT_RELOAD_H*/ diff --git a/src/mono/mono/eglib/CMakeLists.txt b/src/mono/mono/eglib/CMakeLists.txt index 520359c38e1ea8..d8b7d01a1e4bf7 100644 --- a/src/mono/mono/eglib/CMakeLists.txt +++ b/src/mono/mono/eglib/CMakeLists.txt @@ -45,3 +45,5 @@ set(eglib_common_sources unicode-data.h) addprefix(eglib_sources ../eglib/ "${eglib_platform_sources};${eglib_common_sources}") + +add_library(eglib_objects OBJECT "${eglib_sources}") diff --git a/src/mono/mono/eventpipe/CMakeLists.txt b/src/mono/mono/eventpipe/CMakeLists.txt index 7dad16975afdc6..f7ee1e3c0bdde2 100644 --- a/src/mono/mono/eventpipe/CMakeLists.txt +++ b/src/mono/mono/eventpipe/CMakeLists.txt @@ -1,33 +1,56 @@ if(ENABLE_PERFTRACING) if (FEATURE_PERFTRACING_PAL_TCP) - add_definitions(-DFEATURE_PERFTRACING_PAL_TCP) + add_definitions(-DENABLE_PERFTRACING_PAL_TCP) endif (FEATURE_PERFTRACING_PAL_TCP) + if (FEATURE_PERFTRACING_DISABLE_LISTEN_PORTS) + add_definitions(-DENABLE_PERFTRACING_DISABLE_LISTEN_PORTS) + endif (FEATURE_PERFTRACING_DISABLE_LISTEN_PORTS) + + if (FEATURE_PERFTRACING_DISABLE_CONNECT_PORTS) + add_definitions(-DENABLE_PERFTRACING_DISABLE_CONNECT_PORTS) + endif (FEATURE_PERFTRACING_DISABLE_CONNECT_PORTS) + include (${SHARED_EVENTPIPE_SOURCE_PATH}CMakeLists.txt) set(MONO_EVENTPIPE_SHIM_SOURCES "") set(MONO_EVENTPIPE_SHIM_HEADERS "") + set(MONO_DIAGNOSTIC_SERVER_SHIM_SOURCES "") + set(MONO_DIAGNOSTIC_SERVER_SHIM_HEADERS "") + list(APPEND MONO_EVENTPIPE_SHIM_SOURCES - ds-rt-mono.c ep-rt-mono.c ) + list(APPEND MONO_DIAGNOSTIC_SERVER_SHIM_SOURCES + ds-rt-mono.c + ) + list(APPEND MONO_EVENTPIPE_SHIM_HEADERS - ds-rt-mono.h - ds-rt-types-mono.h ep-rt-config-mono.h ep-rt-mono.h ep-rt-types-mono.h ) + list(APPEND MONO_DIAGNOSTIC_SERVER_SHIM_HEADERS + ds-rt-mono.h + ds-rt-types-mono.h + ) + set(shared_eventpipe_sources_base "") set(mono_eventpipe_shim_sources_base "") + set(shared_diagnostic_server_sources_base "") + set(mono_diagnostic_server_shim_sources_base "") + list(APPEND shared_eventpipe_sources_base ${SHARED_EVENTPIPE_SOURCES} ${SHARED_EVENTPIPE_HEADERS} + ) + + list(APPEND shared_diagnostic_server_sources_base ${SHARED_DIAGNOSTIC_SERVER_SOURCES} ${SHARED_DIAGNOSTIC_SERVER_HEADERS} ${SHARED_DIAGNOSTIC_SERVER_PAL_SOURCES} @@ -39,10 +62,19 @@ if(ENABLE_PERFTRACING) ${MONO_EVENTPIPE_SHIM_HEADERS} ) + list(APPEND mono_diagnostic_server_shim_sources_base + ${MONO_DIAGNOSTIC_SERVER_SHIM_SOURCES} + ${MONO_DIAGNOSTIC_SERVER_SHIM_HEADERS} + ) + addprefix(shared_eventpipe_sources_base ${SHARED_EVENTPIPE_SOURCE_PATH} "${shared_eventpipe_sources_base}") addprefix(mono_eventpipe_shim_sources_base ${MONO_EVENTPIPE_SHIM_SOURCE_PATH} "${mono_eventpipe_shim_sources_base}") + addprefix(shared_diagnostic_server_sources_base ${SHARED_EVENTPIPE_SOURCE_PATH} "${shared_diagnostic_server_sources_base}") + addprefix(mono_diagnostic_server_shim_sources_base ${MONO_EVENTPIPE_SHIM_SOURCE_PATH} "${mono_diagnostic_server_shim_sources_base}") + set(eventpipe_sources ${shared_eventpipe_sources_base} ${mono_eventpipe_shim_sources_base}) + set(diagnostic_server_sources ${shared_diagnostic_server_sources_base} ${mono_diagnostic_server_shim_sources_base}) set_source_files_properties(${SHARED_EVENTPIPE_SOURCE_PATH}/ep-sources.c PROPERTIES COMPILE_DEFINITIONS EP_FORCE_INCLUDE_SOURCE_FILES) set_source_files_properties(${SHARED_EVENTPIPE_SOURCE_PATH}/ds-sources.c PROPERTIES COMPILE_DEFINITIONS DS_FORCE_INCLUDE_SOURCE_FILES) diff --git a/src/mono/mono/eventpipe/ep-rt-config-mono.h b/src/mono/mono/eventpipe/ep-rt-config-mono.h index ec3ceb9f4aba01..7b08ff795f3909 100644 --- a/src/mono/mono/eventpipe/ep-rt-config-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-config-mono.h @@ -1,7 +1,6 @@ #ifndef __EVENTPIPE_RT_CONFIG_MONO_H__ #define __EVENTPIPE_RT_CONFIG_MONO_H__ -#define EP_RT_MONO_USE_STATIC_RUNTIME #define EP_THREAD_INCLUDE_ACTIVITY_ID #endif /* __EVENTPIPE_RT_CONFIG_MONO_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 3cc88969dda0f1..7c677639b085a4 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -6,326 +6,671 @@ #include #include #include -#include + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +// EventPipe rt init state. +gboolean _ep_rt_mono_initialized; + +// EventPipe TLS key. +MonoNativeTlsKey _ep_rt_mono_thread_holder_tls_id; + +// Random byte provider. +gpointer _ep_rt_mono_rand_provider; + +// EventPipe global config lock. ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock = {0}; -EventPipeMonoFuncTable _ep_rt_mono_func_table = {0}; +// OS cmd line. mono_lazy_init_t _ep_rt_mono_os_cmd_line_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; char *_ep_rt_mono_os_cmd_line = NULL; +// Managed cmd line. mono_lazy_init_t _ep_rt_mono_managed_cmd_line_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; char *_ep_rt_mono_managed_cmd_line = NULL; -#ifdef HOST_WIN32 -int64_t -ep_rt_mono_perf_counter_query (void) -{ - LARGE_INTEGER value; - if (QueryPerformanceCounter (&value)) - return (int64_t)value.QuadPart; - else - return 0; -} +// Sample profiler. +static GArray * _ep_rt_mono_sampled_thread_callstacks = NULL; +static uint32_t _ep_rt_mono_max_sampled_thread_count = 32; -int64_t -ep_rt_mono_perf_frequency_query (void) -{ - LARGE_INTEGER value; - if (QueryPerformanceFrequency (&value)) - return (int64_t)value.QuadPart; - else - return 0; -} +// Rundown events. +EventPipeProvider *EventPipeProviderDotNETRuntimeRundown = NULL; +EventPipeEvent *EventPipeEventMethodDCEndVerbose_V1 = NULL; +EventPipeEvent *EventPipeEventDCEndInit_V1 = NULL; +EventPipeEvent *EventPipeEventDCEndComplete_V1 = NULL; +EventPipeEvent *EventPipeEventMethodDCEndILToNativeMap = NULL; +EventPipeEvent *EventPipeEventDomainModuleDCEnd_V1 = NULL; +EventPipeEvent *EventPipeEventModuleDCEnd_V2 = NULL; +EventPipeEvent *EventPipeEventAssemblyDCEnd_V1 = NULL; +EventPipeEvent *EventPipeEventAppDomainDCEnd_V1 = NULL; +EventPipeEvent *EventPipeEventRuntimeInformationDCStart = NULL; -void -ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) -{ - SYSTEMTIME value; - GetSystemTime (&value); +// Runtime private events. +EventPipeProvider *EventPipeProviderDotNETRuntimePrivate = NULL; +EventPipeEvent *EventPipeEventEEStartupStart_V1 = NULL; - EP_ASSERT (system_time != NULL); - ep_system_time_set ( - system_time, - value.wYear, - value.wMonth, - value.wDayOfWeek, - value.wDay, - value.wHour, - value.wMinute, - value.wSecond, - value.wMilliseconds); -} +// Rundown types. +typedef +bool +(*ep_rt_mono_fire_method_rundown_events_func)( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + void *user_data); -int64_t -ep_rt_mono_system_timestamp_get (void) -{ - FILETIME value; - GetSystemTimeAsFileTime (&value); - return (int64_t)((((uint64_t)value.dwHighDateTime) << 32) | (uint64_t)value.dwLowDateTime); -} -#else -#include -#include -#include -#include +typedef +bool +(*ep_rt_mono_fire_assembly_rundown_events_func)( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data); -#if HAVE_SYS_TIME_H -#include -#endif // HAVE_SYS_TIME_H +typedef +bool +(*ep_rt_mono_fire_domain_rundown_events_func)( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data); -#if HAVE_MACH_ABSOLUTE_TIME -#include -static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; -static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0}; -#endif +typedef struct _EventPipeFireMethodEventsData{ + MonoDomain *domain; + uint8_t *buffer; + size_t buffer_size; + ep_rt_mono_fire_method_rundown_events_func method_events_func; +} EventPipeFireMethodEventsData; -#ifdef HAVE_LOCALTIME_R -#define HAVE_GMTIME_R 1 -#endif +typedef struct _EventPipeSampleProfileData { + EventPipeStackContents stack_contents; + uint64_t thread_id; + uintptr_t thread_ip; + uint32_t payload_data; +} EventPipeSampleProfileData; -static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; -static const int64_t SECS_TO_100NS = 10000000; -static const int64_t SECS_TO_NS = 1000000000; -static const int64_t MSECS_TO_MIS = 1000; +// Rundown flags. +#define RUNTIME_SKU_CORECLR 0x2 +#define METHOD_FLAGS_DYNAMIC_METHOD 0x1 +#define METHOD_FLAGS_GENERIC_METHOD 0x2 +#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4 +#define METHOD_FLAGS_JITTED_METHOD 0x8 +#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10 -/* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ -#if defined (HAVE_CLOCK_MONOTONIC) && (defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)) -#undef HAVE_CLOCK_MONOTONIC -#endif +#define MODULE_FLAGS_NATIVE_MODULE 0x2 +#define MODULE_FLAGS_DYNAMIC_MODULE 0x4 +#define MODULE_FLAGS_MANIFEST_MODULE 0x8 -#ifndef HAVE_CLOCK_MONOTONIC -static const int64_t MISECS_TO_NS = 1000; -#endif +#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2 +#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4 +#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8 + +#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1 +#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2 + +/* + * Forward declares of all static functions. + */ static -void -time_base_info_lazy_init (void); +bool +resize_buffer ( + uint8_t **buffer, + size_t *size, + size_t current_size, + size_t new_size, + bool *fixed_buffer); static -int64_t -system_time_to_int64 ( - time_t sec, - long nsec); +bool +write_buffer ( + const uint8_t *value, + size_t value_size, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer); -#if HAVE_MACH_ABSOLUTE_TIME static -void -time_base_info_lazy_init (void) -{ - kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info); - if (result != KERN_SUCCESS) - memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info)); -} -#endif +bool +write_buffer_string_utf8_t ( + const ep_char8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer); -int64_t -ep_rt_mono_perf_counter_query (void) -{ -#if HAVE_MACH_ABSOLUTE_TIME - return (int64_t)mach_absolute_time (); -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - int result = clock_gettime (CLOCK_MONOTONIC, &ts); - if (result == 0) - return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec); -#else - #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." -#endif - return 0; -} +static +bool +write_runtime_info_dc_start ( + const uint16_t clr_instance_id, + const uint16_t sku_id, + const uint16_t bcl_major_version, + const uint16_t bcl_minor_version, + const uint16_t bcl_build_number, + const uint16_t bcl_qfe_number, + const uint16_t vm_major_version, + const uint16_t vm_minor_version, + const uint16_t vm_build_number, + const uint16_t vm_qfe_number, + const uint32_t startup_flags, + const uint8_t startup_mode, + const ep_char8_t *cmd_line, + const uint8_t * object_guid, + const ep_char8_t *runtime_dll_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); -int64_t -ep_rt_mono_perf_frequency_query (void) -{ -#if HAVE_MACH_ABSOLUTE_TIME - // (numer / denom) gives you the nanoseconds per tick, so the below code - // computes the number of ticks per second. We explicitly do the multiplication - // first in order to help minimize the error that is produced by integer division. - mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init); - if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0) - return 0; - return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer); -#elif HAVE_CLOCK_MONOTONIC - // clock_gettime () returns a result in terms of nanoseconds rather than a count. This - // means that we need to either always scale the result by the actual resolution (to - // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer - // the latter since it allows the highest throughput and should minimize error propagated - // to the user. - return (int64_t)(SECS_TO_NS); -#else - #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." -#endif - return 0; -} +static +bool +write_runtime_info_dc_start ( + const uint16_t clr_instance_id, + const uint16_t sku_id, + const uint16_t bcl_major_version, + const uint16_t bcl_minor_version, + const uint16_t bcl_build_number, + const uint16_t bcl_qfe_number, + const uint16_t vm_major_version, + const uint16_t vm_minor_version, + const uint16_t vm_build_number, + const uint16_t vm_qfe_number, + const uint32_t startup_flags, + const uint8_t startup_mode, + const ep_char8_t *cmd_line, + const uint8_t * object_guid, + const ep_char8_t *runtime_dll_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); -void -ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) -{ - time_t tt; -#if HAVE_GMTIME_R - struct tm ut; -#endif /* HAVE_GMTIME_R */ - struct tm *ut_ptr; - struct timeval time_val; - int timeofday_retval; +static +bool +write_event_dc_end_complete_v1 ( + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); - EP_ASSERT (system_time != NULL); +static +bool +write_event_method_dc_end_il_to_native_map ( + const uint64_t method_id, + const uint64_t rejit_id, + const uint8_t method_extent, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); - tt = time (NULL); +static +bool +write_event_method_dc_end_verbose_v1 ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); - /* We can't get millisecond resolution from time (), so we get it from gettimeofday () */ - timeofday_retval = gettimeofday (&time_val, NULL); +static +bool +write_event_module_dc_end_v2 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); -#if HAVE_GMTIME_R - ut_ptr = &ut; - if (gmtime_r (&tt, ut_ptr) == NULL) -#else /* HAVE_GMTIME_R */ - if ((ut_ptr = gmtime (&tt)) == NULL) -#endif /* HAVE_GMTIME_R */ - g_assert_not_reached (); +static +bool +write_event_module_dc_end_v2 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + const uint8_t *activity_id, + const uint8_t *related_activity_id); - uint16_t milliseconds = 0; - if (timeofday_retval != -1) { - int old_seconds; - int new_seconds; +static +bool +write_event_assembly_dc_end_v1 ( + const uint64_t assembly_id, + const uint64_t domain_id, + const uint64_t binding_id, + const uint32_t assembly_flags, + const ep_char8_t *fully_qualified_name, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); - milliseconds = time_val.tv_usec / MSECS_TO_MIS; +static +bool +write_event_domain_dc_end_v1 ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); - old_seconds = ut_ptr->tm_sec; - new_seconds = time_val.tv_sec % 60; +static +bool +fire_method_rundown_events_func ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + void *user_data); - /* just in case we reached the next second in the interval between time () and gettimeofday () */ - if (old_seconds != new_seconds) - milliseconds = 999; - } +static +bool +fire_assembly_rundown_events_func ( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data); - ep_system_time_set ( - system_time, - 1900 + ut_ptr->tm_year, - ut_ptr->tm_mon + 1, - ut_ptr->tm_wday, - ut_ptr->tm_mday, - ut_ptr->tm_hour, - ut_ptr->tm_min, - ut_ptr->tm_sec, - milliseconds); -} +static +bool +fire_domain_rundown_events_func ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data); static -inline +void +init_dotnet_runtime_rundown (void); + +static +bool +write_event_ee_startup_start_v1 ( + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +static +void +init_dotnet_runtime_private (void); + +static +void +eventpipe_fire_method_events ( + MonoJitInfo *ji, + MonoMethod *method, + EventPipeFireMethodEventsData *events_data); + +static +void +eventpipe_fire_method_events_func ( + MonoJitInfo *ji, + void *user_data); + +static +void +eventpipe_fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func); + +static +gboolean +eventpipe_execute_rundown ( + ep_rt_mono_fire_domain_rundown_events_func domain_events_func, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, + ep_rt_mono_fire_method_rundown_events_func methods_events_func); + +static +gboolean +eventpipe_walk_managed_stack_for_thread_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data); + +static +gboolean +eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data); + +static +void +profiler_eventpipe_thread_exited ( + MonoProfiler *prof, + uintptr_t tid); + +/* + * Forward declares of all private functions (accessed using extern in ep-rt-mono.h). + */ + +void +ep_rt_mono_init (void); + +void +ep_rt_mono_fini (void); + +bool +ep_rt_mono_rand_try_get_bytes ( + uint8_t *buffer, + size_t buffer_size); + +EventPipeThread * +ep_rt_mono_thread_get_or_create (void); + +void * +ep_rt_mono_thread_attach (bool background_thread); + +void +ep_rt_mono_thread_detach (void); + +void +ep_rt_mono_thread_exited (void); + int64_t -system_time_to_int64 ( - time_t sec, - long nsec) +ep_rt_mono_perf_counter_query (void); + +int64_t +ep_rt_mono_perf_frequency_query (void); + +void +ep_rt_mono_system_time_get (EventPipeSystemTime *system_time); + +int64_t +ep_rt_mono_system_timestamp_get (void); + +void +ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array); + +void +ep_rt_mono_init_providers_and_events (void); + +void +ep_rt_mono_fini_providers_and_events (void); + +bool +ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event); + +bool +ep_rt_mono_walk_managed_stack_for_thread ( + ep_rt_thread_handle_t thread, + EventPipeStackContents *stack_contents); + +bool +ep_rt_mono_method_get_simple_assembly_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len); + +bool +ep_rt_mono_method_get_full_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len); + +void +ep_rt_mono_execute_rundown (void); + +static +inline +uint16_t +clr_instance_get_id (void) { - return ((int64_t)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + (nsec / 100); + // Mono runtime id. + return 9; } -int64_t -ep_rt_mono_system_timestamp_get (void) +static +bool +resize_buffer ( + uint8_t **buffer, + size_t *size, + size_t current_size, + size_t new_size, + bool *fixed_buffer) { -#if HAVE_CLOCK_MONOTONIC - struct timespec time; - if (clock_gettime (CLOCK_REALTIME, &time) == 0) - return system_time_to_int64 (time.tv_sec, time.tv_nsec); -#else - struct timeval time; - if (gettimeofday (&time, NULL) == 0) - return system_time_to_int64 (time.tv_sec, time.tv_usec * MISECS_TO_NS); -#endif - else - return system_time_to_int64 (0, 0); + EP_ASSERT (buffer != NULL); + EP_ASSERT (size != NULL); + EP_ASSERT (fixed_buffer != NULL); + + new_size = (size_t)(new_size * 1.5); + if (new_size < *size) { + EP_ASSERT (!"Overflow"); + return false; + } + + if (new_size < 32) + new_size = 32; + + uint8_t *new_buffer; + new_buffer = ep_rt_byte_array_alloc (new_size); + ep_raise_error_if_nok (new_buffer != NULL); + + memcpy (new_buffer, *buffer, current_size); + + if (!*fixed_buffer) + ep_rt_byte_array_free (*buffer); + + *buffer = new_buffer; + *size = new_size; + *fixed_buffer = false; + + return true; + +ep_on_error: + return false; } -#endif -#ifndef HOST_WIN32 -#if defined(__APPLE__) -#if defined (TARGET_OSX) -G_BEGIN_DECLS -gchar ***_NSGetEnviron(void); -G_END_DECLS -#define environ (*_NSGetEnviron()) -#else -static char *_ep_rt_mono_environ[1] = { NULL }; -#define environ _ep_rt_mono_environ -#endif /* defined (TARGET_OSX) */ -#else -G_BEGIN_DECLS -extern char **environ; -G_END_DECLS -#endif /* defined (__APPLE__) */ -#endif /* !defined (HOST_WIN32) */ +static +bool +write_buffer ( + const uint8_t *value, + size_t value_size, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + EP_ASSERT (value != NULL); + EP_ASSERT (buffer != NULL); + EP_ASSERT (offset != NULL); + EP_ASSERT (size != NULL); + EP_ASSERT (fixed_buffer != NULL); -void -ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) + if ((value_size + *offset) > *size) + ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_size, fixed_buffer)); + + memcpy (*buffer + *offset, value, value_size); + *offset += value_size; + + return true; + +ep_on_error: + return false; +} + +static +bool +write_buffer_string_utf8_t ( + const ep_char8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) { - EP_ASSERT (env_array != NULL); -#ifdef HOST_WIN32 - LPWSTR envs = GetEnvironmentStringsW (); - if (envs) { - LPWSTR next = envs; - while (*next) { - ep_rt_env_array_utf16_append (env_array, ep_rt_utf16_string_dup (next)); - next += ep_rt_utf16_string_len (next) + 1; - } - FreeEnvironmentStringsW (envs); + if (!value) + return true; + + GFixedBufferCustomAllocatorData custom_alloc_data; + custom_alloc_data.buffer = *buffer + *offset; + custom_alloc_data.buffer_size = *size - *offset; + custom_alloc_data.req_buffer_size = 0; + + if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL)) { + ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + custom_alloc_data.req_buffer_size, fixed_buffer)); + custom_alloc_data.buffer = *buffer + *offset; + custom_alloc_data.buffer_size = *size - *offset; + custom_alloc_data.req_buffer_size = 0; + ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL) != NULL); } -#else - gchar **next = NULL; - for (next = environ; *next != NULL; ++next) - ep_rt_env_array_utf16_append (env_array, ep_rt_utf8_to_utf16_string (*next, -1)); -#endif -} -// Rundown flags. -#define RUNTIME_SKU_CORECLR 0x2 + *offset += custom_alloc_data.req_buffer_size; + return true; -// Rundown events. -EventPipeProvider *EventPipeProviderDotNETRuntimeRundown = NULL; -EventPipeEvent *EventPipeEventMethodDCEndVerbose_V1 = NULL; -EventPipeEvent *EventPipeEventDCEndInit_V1 = NULL; -EventPipeEvent *EventPipeEventDCEndComplete_V1 = NULL; -EventPipeEvent *EventPipeEventMethodDCEndILToNativeMap = NULL; -EventPipeEvent *EventPipeEventDomainModuleDCEnd_V1 = NULL; -EventPipeEvent *EventPipeEventModuleDCEnd_V2 = NULL; -EventPipeEvent *EventPipeEventAssemblyDCEnd_V1 = NULL; -EventPipeEvent *EventPipeEventAppDomainDCEnd_V1 = NULL; -EventPipeEvent *EventPipeEventRuntimeInformationDCStart = NULL; +ep_on_error: + return false; +} + +static +inline +bool +write_buffer_guid_t ( + const uint8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer (value, EP_GUID_SIZE, buffer, offset, size, fixed_buffer); +} -/* - * Forward declares of all static rundown functions. - */ +static +inline +bool +write_buffer_uint8_t ( + const uint8_t *value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer (value, sizeof (uint8_t), buffer, offset, size, fixed_buffer); +} static +inline bool -resize_buffer ( +write_buffer_uint16_t ( + const uint16_t *value, uint8_t **buffer, + size_t *offset, size_t *size, - size_t current_size, - size_t new_size, - bool *fixed_buffer); + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)value, sizeof (uint16_t), buffer, offset, size, fixed_buffer); +} static +inline bool -write_buffer ( - const uint8_t *value, - size_t value_size, +write_buffer_uint32_t ( + const uint32_t *value, uint8_t **buffer, size_t *offset, size_t *size, - bool *fixed_buffer); + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)value, sizeof (uint32_t), buffer, offset, size, fixed_buffer); +} static +inline bool -write_buffer_string_utf8_t ( - const ep_char8_t *value, +write_buffer_uint64_t ( + const uint64_t *value, uint8_t **buffer, size_t *offset, size_t *size, - bool *fixed_buffer); + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)value, sizeof (uint64_t), buffer, offset, size, fixed_buffer); +} static bool @@ -346,35 +691,119 @@ write_runtime_info_dc_start ( const uint8_t * object_guid, const ep_char8_t *runtime_dll_path, const uint8_t *activity_id, - const uint8_t *related_activity_id); + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventRuntimeInformationDCStart != NULL); + + if (!ep_event_is_enabled (EventPipeEventRuntimeInformationDCStart)) + return true; + + uint8_t stack_buffer [153]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&sku_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_major_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_minor_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_build_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&bcl_qfe_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_major_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_minor_version, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_build_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&vm_qfe_number, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&startup_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint8_t (&startup_mode, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (cmd_line, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_guid_t (object_guid, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (runtime_dll_path, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventRuntimeInformationDCStart, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} static bool -write_runtime_info_dc_start ( +write_event_dc_end_init_v1 ( const uint16_t clr_instance_id, - const uint16_t sku_id, - const uint16_t bcl_major_version, - const uint16_t bcl_minor_version, - const uint16_t bcl_build_number, - const uint16_t bcl_qfe_number, - const uint16_t vm_major_version, - const uint16_t vm_minor_version, - const uint16_t vm_build_number, - const uint16_t vm_qfe_number, - const uint32_t startup_flags, - const uint8_t startup_mode, - const ep_char8_t *cmd_line, - const uint8_t * object_guid, - const ep_char8_t *runtime_dll_path, const uint8_t *activity_id, - const uint8_t *related_activity_id); + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventDCEndInit_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventDCEndInit_V1)) + return true; + + uint8_t stack_buffer [32]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventDCEndInit_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} static bool write_event_dc_end_complete_v1 ( const uint16_t clr_instance_id, const uint8_t *activity_id, - const uint8_t *related_activity_id); + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventDCEndComplete_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventDCEndComplete_V1)) + return true; + + uint8_t stack_buffer [32]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventDCEndComplete_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} static bool @@ -387,88 +816,45 @@ write_event_method_dc_end_il_to_native_map ( const uint32_t *native_offsets, const uint16_t clr_instance_id, const uint8_t *activity_id, - const uint8_t *related_activity_id); + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventMethodDCEndILToNativeMap != NULL); -static -bool -write_event_method_dc_end_verbose_v1 ( - const uint64_t method_id, - const uint64_t module_id, - const uint64_t method_start_address, - const uint32_t method_size, - const uint32_t method_token, - const uint32_t method_flags, - const ep_char8_t *method_namespace, - const ep_char8_t *method_name, - const ep_char8_t *method_signature, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id); + if (!ep_event_is_enabled (EventPipeEventMethodDCEndILToNativeMap)) + return true; -static -bool -write_event_module_dc_end_v2 ( - const uint64_t module_id, - const uint64_t assembly_id, - const uint32_t module_flags, - const uint32_t reserved_1, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint16_t clr_instance_id, - const uint8_t *managed_pdb_signature, - const uint32_t managed_pdb_age, - const ep_char8_t *managed_pdb_build_path, - const uint8_t *native_pdb_signature, - const uint32_t native_pdb_age, - const ep_char8_t *native_pdb_build_path, - const uint8_t *activity_id, - const uint8_t *related_activity_id); + uint8_t stack_buffer [32]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; -static -bool -write_event_module_dc_end_v2 ( - const uint64_t module_id, - const uint64_t assembly_id, - const uint32_t module_flags, - const uint32_t reserved_1, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint16_t clr_instance_id, - const uint8_t *managed_pdb_signature, - const uint32_t managed_pdb_age, - const ep_char8_t *managed_pdb_build_path, - const uint8_t *native_pdb_signature, - const uint32_t native_pdb_age, - const ep_char8_t *native_pdb_build_path, - const uint8_t *activity_id, - const uint8_t *related_activity_id); + success &= write_buffer_uint64_t (&method_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&rejit_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint8_t (&method_extent, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer ((const uint8_t *)il_offsets, sizeof (const uint32_t) * (int32_t)count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer ((const uint8_t *)native_offsets, sizeof (const uint32_t) * (int32_t)count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); -static -bool -write_event_assembly_dc_end_v1 ( - const uint64_t assembly_id, - const uint64_t domain_id, - const uint64_t binding_id, - const uint32_t assembly_flags, - const ep_char8_t *fully_qualified_name, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id); + ep_raise_error_if_nok (success); -static -bool -write_event_domain_dc_end_v1 ( - const uint64_t domain_id, - const uint32_t domain_flags, - const ep_char8_t *domain_name, - const uint32_t domain_index, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id); + ep_write_event (EventPipeEventMethodDCEndILToNativeMap, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} static bool -fire_method_rundown_events_func ( +write_event_method_dc_end_verbose_v1 ( const uint64_t method_id, const uint64_t module_id, const uint64_t method_start_address, @@ -478,272 +864,232 @@ fire_method_rundown_events_func ( const ep_char8_t *method_namespace, const ep_char8_t *method_name, const ep_char8_t *method_signature, - const uint16_t count_of_map_entries, - const uint32_t *il_offsets, - const uint32_t *native_offsets, - void *user_data); + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (EventPipeEventMethodDCEndVerbose_V1 != NULL); + + if (!ep_event_is_enabled (EventPipeEventMethodDCEndVerbose_V1)) + return true; + + uint8_t stack_buffer [230]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&method_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&method_start_address, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&method_size, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&method_token, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&method_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (method_namespace, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (method_name, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (method_signature, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventMethodDCEndVerbose_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); +} static bool -fire_assembly_rundown_events_func ( - const uint64_t domain_id, - const uint64_t assembly_id, - const uint32_t assembly_flags, - const uint32_t binding_id, - const ep_char8_t *assembly_name, +write_event_module_dc_end_v2 ( const uint64_t module_id, + const uint64_t assembly_id, const uint32_t module_flags, - const uint32_t reserved_flags, + const uint32_t reserved_1, const ep_char8_t *module_il_path, const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, const uint8_t *managed_pdb_signature, const uint32_t managed_pdb_age, const ep_char8_t *managed_pdb_build_path, const uint8_t *native_pdb_signature, const uint32_t native_pdb_age, const ep_char8_t *native_pdb_build_path, - void *user_data); - -static -bool -fire_domain_rundown_events_func ( - const uint64_t domain_id, - const uint32_t domain_flags, - const ep_char8_t *domain_name, - const uint32_t domain_index, - void *user_data); - -static -void -init_dotnet_runtime_rundown (void); - -static -inline -uint16_t -clr_instance_get_id (void) -{ - // Mono runtime id. - return 9; -} - -static -bool -resize_buffer ( - uint8_t **buffer, - size_t *size, - size_t current_size, - size_t new_size, - bool *fixed_buffer) + const uint8_t *activity_id, + const uint8_t *related_activity_id) { - EP_ASSERT (buffer != NULL); - EP_ASSERT (size != NULL); - EP_ASSERT (fixed_buffer != NULL); - - new_size = (size_t)(new_size * 1.5); - if (new_size < *size) { - EP_ASSERT (!"Overflow"); - return false; - } + EP_ASSERT (EventPipeEventModuleDCEnd_V2 != NULL); - if (new_size < 32) - new_size = 32; + if (!ep_event_is_enabled (EventPipeEventModuleDCEnd_V2)) + return true; - uint8_t *new_buffer; - new_buffer = ep_rt_byte_array_alloc (new_size); - ep_raise_error_if_nok (new_buffer != NULL); + uint8_t stack_buffer [290]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; - memcpy (new_buffer, *buffer, current_size); + success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&module_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&reserved_1, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_il_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_native_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_guid_t (managed_pdb_signature, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&managed_pdb_age, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (managed_pdb_build_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_guid_t (native_pdb_signature, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&native_pdb_age, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (native_pdb_build_path, &buffer, &offset, &size, &fixed_buffer); - if (!*fixed_buffer) - ep_rt_byte_array_free (*buffer); + ep_raise_error_if_nok (success); - *buffer = new_buffer; - *size = new_size; - *fixed_buffer = false; + ep_write_event (EventPipeEventModuleDCEnd_V2, buffer, (uint32_t)offset, activity_id, related_activity_id); - return true; +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; ep_on_error: - return false; + EP_ASSERT (!success); + ep_exit_error_handler (); } static bool -write_buffer ( - const uint8_t *value, - size_t value_size, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) +write_event_domain_module_dc_end_v1 ( + const uint64_t module_id, + const uint64_t assembly_id, + const uint64_t domain_id, + const uint32_t module_flags, + const uint32_t reserved_1, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) { - EP_ASSERT (value != NULL); - EP_ASSERT (buffer != NULL); - EP_ASSERT (offset != NULL); - EP_ASSERT (size != NULL); - EP_ASSERT (fixed_buffer != NULL); - - if ((value_size + *offset) > *size) - ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + value_size, fixed_buffer)); - - memcpy (*buffer + *offset, value, value_size); - *offset += value_size; - - return true; - -ep_on_error: - return false; -} + EP_ASSERT (EventPipeEventDomainModuleDCEnd_V1 != NULL); -static -bool -write_buffer_string_utf8_t ( - const ep_char8_t *value, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) -{ - if (!value) + if (!ep_event_is_enabled (EventPipeEventDomainModuleDCEnd_V1)) return true; - GFixedBufferCustomAllocatorData custom_alloc_data; - custom_alloc_data.buffer = *buffer + *offset; - custom_alloc_data.buffer_size = *size - *offset; - custom_alloc_data.req_buffer_size = 0; - - if (!g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL)) { - ep_raise_error_if_nok (resize_buffer (buffer, size, *offset, *size + custom_alloc_data.req_buffer_size, fixed_buffer)); - custom_alloc_data.buffer = *buffer + *offset; - custom_alloc_data.buffer_size = *size - *offset; - custom_alloc_data.req_buffer_size = 0; - ep_raise_error_if_nok (g_utf8_to_utf16_custom_alloc (value, -1, NULL, NULL, g_fixed_buffer_custom_allocator, &custom_alloc_data, NULL) != NULL); - } + uint8_t stack_buffer [162]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; - *offset += custom_alloc_data.req_buffer_size; - return true; + success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&module_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&reserved_1, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_il_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (module_native_path, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); -ep_on_error: - return false; -} + ep_raise_error_if_nok (success); -static -inline -bool -write_buffer_guid_t ( - const uint8_t *value, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) -{ - return write_buffer (value, EP_GUID_SIZE, buffer, offset, size, fixed_buffer); -} + ep_write_event (EventPipeEventDomainModuleDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); -static -inline -bool -write_buffer_uint8_t ( - const uint8_t *value, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) -{ - return write_buffer (value, sizeof (uint8_t), buffer, offset, size, fixed_buffer); -} +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; -static -inline -bool -write_buffer_uint16_t ( - const uint16_t *value, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) -{ - return write_buffer ((const uint8_t *)value, sizeof (uint16_t), buffer, offset, size, fixed_buffer); +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); } static -inline bool -write_buffer_uint32_t ( - const uint32_t *value, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) +write_event_assembly_dc_end_v1 ( + const uint64_t assembly_id, + const uint64_t domain_id, + const uint64_t binding_id, + const uint32_t assembly_flags, + const ep_char8_t *fully_qualified_name, + const uint16_t clr_instance_id, + const uint8_t *activity_id, + const uint8_t *related_activity_id) { - return write_buffer ((const uint8_t *)value, sizeof (uint32_t), buffer, offset, size, fixed_buffer); -} + EP_ASSERT (EventPipeEventAssemblyDCEnd_V1 != NULL); -static -inline -bool -write_buffer_uint64_t ( - const uint64_t *value, - uint8_t **buffer, - size_t *offset, - size_t *size, - bool *fixed_buffer) -{ - return write_buffer ((const uint8_t *)value, sizeof (uint64_t), buffer, offset, size, fixed_buffer); + if (!ep_event_is_enabled (EventPipeEventAssemblyDCEnd_V1)) + return true; + + uint8_t stack_buffer [94]; + uint8_t *buffer = stack_buffer; + size_t offset = 0; + size_t size = sizeof (stack_buffer); + bool fixed_buffer = true; + bool success = true; + + success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint64_t (&binding_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&assembly_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (fully_qualified_name, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + + ep_raise_error_if_nok (success); + + ep_write_event (EventPipeEventAssemblyDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + +ep_on_exit: + if (!fixed_buffer) + ep_rt_byte_array_free (buffer); + return success; + +ep_on_error: + EP_ASSERT (!success); + ep_exit_error_handler (); } static bool -write_runtime_info_dc_start ( +write_event_domain_dc_end_v1 ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, const uint16_t clr_instance_id, - const uint16_t sku_id, - const uint16_t bcl_major_version, - const uint16_t bcl_minor_version, - const uint16_t bcl_build_number, - const uint16_t bcl_qfe_number, - const uint16_t vm_major_version, - const uint16_t vm_minor_version, - const uint16_t vm_build_number, - const uint16_t vm_qfe_number, - const uint32_t startup_flags, - const uint8_t startup_mode, - const ep_char8_t *cmd_line, - const uint8_t * object_guid, - const ep_char8_t *runtime_dll_path, const uint8_t *activity_id, const uint8_t *related_activity_id) { - EP_ASSERT (EventPipeEventRuntimeInformationDCStart != NULL); + EP_ASSERT (EventPipeEventAppDomainDCEnd_V1 != NULL); - if (!ep_event_is_enabled (EventPipeEventRuntimeInformationDCStart)) + if (!ep_event_is_enabled (EventPipeEventAppDomainDCEnd_V1)) return true; - uint8_t stack_buffer [153]; + uint8_t stack_buffer [82]; uint8_t *buffer = stack_buffer; size_t offset = 0; size_t size = sizeof (stack_buffer); bool fixed_buffer = true; bool success = true; + success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&domain_flags, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_string_utf8_t (domain_name, &buffer, &offset, &size, &fixed_buffer); + success &= write_buffer_uint32_t (&domain_index, &buffer, &offset, &size, &fixed_buffer); success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&sku_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&bcl_major_version, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&bcl_minor_version, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&bcl_build_number, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&bcl_qfe_number, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&vm_major_version, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&vm_minor_version, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&vm_build_number, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&vm_qfe_number, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&startup_flags, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint8_t (&startup_mode, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (cmd_line, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_guid_t (object_guid, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (runtime_dll_path, &buffer, &offset, &size, &fixed_buffer); ep_raise_error_if_nok (success); - ep_write_event (EventPipeEventRuntimeInformationDCStart, buffer, (uint32_t)offset, activity_id, related_activity_id); + ep_write_event (EventPipeEventAppDomainDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); ep_on_exit: if (!fixed_buffer) @@ -757,14 +1103,14 @@ write_runtime_info_dc_start ( static bool -write_event_dc_end_init_v1 ( +write_event_ee_startup_start_v1 ( const uint16_t clr_instance_id, const uint8_t *activity_id, const uint8_t *related_activity_id) { - EP_ASSERT (EventPipeEventDCEndInit_V1 != NULL); + EP_ASSERT (EventPipeEventEEStartupStart_V1 != NULL); - if (!ep_event_is_enabled (EventPipeEventDCEndInit_V1)) + if (!ep_event_is_enabled (EventPipeEventEEStartupStart_V1)) return true; uint8_t stack_buffer [32]; @@ -778,7 +1124,7 @@ write_event_dc_end_init_v1 ( ep_raise_error_if_nok (success); - ep_write_event (EventPipeEventDCEndInit_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + ep_write_event (EventPipeEventEEStartupStart_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); ep_on_exit: if (!fixed_buffer) @@ -790,503 +1136,848 @@ write_event_dc_end_init_v1 ( ep_exit_error_handler (); } +// Mapping FireEtw* CoreClr functions. +#define FireEtwRuntimeInformationDCStart(...) write_runtime_info_dc_start(__VA_ARGS__,NULL,NULL) +#define FireEtwDCEndInit_V1(...) write_event_dc_end_init_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwMethodDCEndILToNativeMap(...) write_event_method_dc_end_il_to_native_map(__VA_ARGS__,NULL,NULL) +#define FireEtwMethodDCEndVerbose_V1(...) write_event_method_dc_end_verbose_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwModuleDCEnd_V2(...) write_event_module_dc_end_v2(__VA_ARGS__,NULL,NULL) +#define FireEtwDomainModuleDCEnd_V1(...) write_event_domain_module_dc_end_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwAssemblyDCEnd_V1(...) write_event_assembly_dc_end_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwAppDomainDCEnd_V1(...) write_event_domain_dc_end_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwDCEndComplete_V1(...) write_event_dc_end_complete_v1(__VA_ARGS__,NULL,NULL) +#define FireEtwEEStartupStart_V1(...) write_event_ee_startup_start_v1(__VA_ARGS__,NULL,NULL) + +static +bool +fire_method_rundown_events_func ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + void *user_data) +{ + FireEtwMethodDCEndILToNativeMap ( + method_id, + 0, + 0, + count_of_map_entries, + il_offsets, + native_offsets, + clr_instance_get_id ()); + + FireEtwMethodDCEndVerbose_V1 ( + method_id, + module_id, + method_start_address, + method_size, + method_token, + method_flags, + method_namespace, + method_name, + method_signature, + clr_instance_get_id ()); + + return true; +} + +static +bool +fire_assembly_rundown_events_func ( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data) +{ + FireEtwModuleDCEnd_V2 ( + module_id, + assembly_id, + module_flags, + reserved_flags, + module_il_path, + module_native_path, + clr_instance_get_id (), + managed_pdb_signature, + managed_pdb_age, + managed_pdb_build_path, + native_pdb_signature, + native_pdb_age, + native_pdb_build_path); + + FireEtwDomainModuleDCEnd_V1 ( + module_id, + assembly_id, + domain_id, + module_flags, + reserved_flags, + module_il_path, + module_native_path, + clr_instance_get_id ()); + + FireEtwAssemblyDCEnd_V1 ( + assembly_id, + domain_id, + binding_id, + assembly_flags, + assembly_name, + clr_instance_get_id ()); + + return true; +} + +static +bool +fire_domain_rundown_events_func ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data) +{ + return FireEtwAppDomainDCEnd_V1 ( + domain_id, + domain_flags, + domain_name, + domain_index, + clr_instance_get_id ()); +} + static -bool -write_event_dc_end_complete_v1 ( - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +void +init_dotnet_runtime_rundown (void) { - EP_ASSERT (EventPipeEventDCEndComplete_V1 != NULL); + //TODO: Add callback method to enable/disable more native events getting into EventPipe (when enabled). + EP_ASSERT (EventPipeProviderDotNETRuntimeRundown == NULL); + EventPipeProviderDotNETRuntimeRundown = ep_create_provider (ep_config_get_rundown_provider_name_utf8 (), NULL, NULL, NULL); - if (!ep_event_is_enabled (EventPipeEventDCEndComplete_V1)) - return true; + EP_ASSERT (EventPipeEventMethodDCEndVerbose_V1 == NULL); + EventPipeEventMethodDCEndVerbose_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 144, 48, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); - uint8_t stack_buffer [32]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; + EP_ASSERT (EventPipeEventDCEndComplete_V1 == NULL); + EventPipeEventDCEndComplete_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 146, 131128, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + EP_ASSERT (EventPipeEventDCEndInit_V1 == NULL); + EventPipeEventDCEndInit_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 148, 131128, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); - ep_raise_error_if_nok (success); + EP_ASSERT (EventPipeEventMethodDCEndILToNativeMap == NULL); + EventPipeEventMethodDCEndILToNativeMap = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 150, 131072, 0, EP_EVENT_LEVEL_VERBOSE, true, NULL, 0); - ep_write_event (EventPipeEventDCEndComplete_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + EP_ASSERT (EventPipeEventDomainModuleDCEnd_V1 == NULL); + EventPipeEventDomainModuleDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 152, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; + EP_ASSERT (EventPipeEventModuleDCEnd_V2 == NULL); + EventPipeEventModuleDCEnd_V2 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 154, 536870920, 2, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); + EP_ASSERT (EventPipeEventAssemblyDCEnd_V1 == NULL); + EventPipeEventAssemblyDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 156, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventAppDomainDCEnd_V1 == NULL); + EventPipeEventAppDomainDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 158, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + + EP_ASSERT (EventPipeEventRuntimeInformationDCStart == NULL); + EventPipeEventRuntimeInformationDCStart = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 187, 0, 0, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); } static -bool -write_event_method_dc_end_il_to_native_map ( - const uint64_t method_id, - const uint64_t rejit_id, - const uint8_t method_extent, - const uint16_t count_of_map_entries, - const uint32_t *il_offsets, - const uint32_t *native_offsets, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +void +init_dotnet_runtime_private (void) { - EP_ASSERT (EventPipeEventMethodDCEndILToNativeMap != NULL); - - if (!ep_event_is_enabled (EventPipeEventMethodDCEndILToNativeMap)) - return true; - - uint8_t stack_buffer [32]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; - - success &= write_buffer_uint64_t (&method_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&rejit_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint8_t (&method_extent, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer ((const uint8_t *)il_offsets, sizeof (const uint32_t) * (int32_t)count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer ((const uint8_t *)native_offsets, sizeof (const uint32_t) * (int32_t)count_of_map_entries, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); - - ep_raise_error_if_nok (success); - - ep_write_event (EventPipeEventMethodDCEndILToNativeMap, buffer, (uint32_t)offset, activity_id, related_activity_id); - -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; + //TODO: Add callback method to enable/disable more native events getting into EventPipe (when enabled). + EP_ASSERT (EventPipeProviderDotNETRuntimePrivate == NULL); + EventPipeProviderDotNETRuntimePrivate = ep_create_provider (ep_config_get_private_provider_name_utf8 (), NULL, NULL, NULL); -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); + EP_ASSERT (EventPipeEventEEStartupStart_V1 == NULL); + EventPipeEventEEStartupStart_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimePrivate, 80, 2147483648, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); } static -bool -write_event_method_dc_end_verbose_v1 ( - const uint64_t method_id, - const uint64_t module_id, - const uint64_t method_start_address, - const uint32_t method_size, - const uint32_t method_token, - const uint32_t method_flags, - const ep_char8_t *method_namespace, - const ep_char8_t *method_name, - const ep_char8_t *method_signature, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +void +eventpipe_fire_method_events ( + MonoJitInfo *ji, + MonoMethod *method, + EventPipeFireMethodEventsData *events_data) { - EP_ASSERT (EventPipeEventMethodDCEndVerbose_V1 != NULL); + EP_ASSERT (ji != NULL); + EP_ASSERT (events_data->domain != NULL); + EP_ASSERT (events_data->method_events_func != NULL); + + uint64_t method_id = 0; + uint64_t module_id = 0; + uint64_t method_code_start = (uint64_t)ji->code_start; + uint32_t method_code_size = (uint32_t)ji->code_size; + uint32_t method_token = 0; + uint32_t method_flags = 0; + uint8_t kind = MONO_CLASS_DEF; + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + + if (method) { + method_id = (uint64_t)method; + method_token = method->token; + + if (mono_jit_info_get_generic_sharing_context (ji)) + method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; + + if (method->dynamic) + method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; + + if (!ji->from_aot && !ji->from_llvm) { + method_flags |= METHOD_FLAGS_JITTED_METHOD; + if (method->wrapper_type != MONO_WRAPPER_NONE) + method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; + } - if (!ep_event_is_enabled (EventPipeEventMethodDCEndVerbose_V1)) - return true; + if (method->is_generic || method->is_inflated) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; - uint8_t stack_buffer [230]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; + method_name = method->name; + method_signature = mono_signature_full_name (method->signature); - success &= write_buffer_uint64_t (&method_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&method_start_address, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&method_size, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&method_token, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&method_flags, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (method_namespace, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (method_name, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (method_signature, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + if (method->klass) { + module_id = (uint64_t)m_class_get_image (method->klass); + kind = m_class_get_class_kind (method->klass); + if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); + } + } - ep_raise_error_if_nok (success); + uint16_t offset_entries = 0; + uint32_t *il_offsets = NULL; + uint32_t *native_offsets = NULL; + + MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL; + if (debug_info) { + offset_entries = debug_info->num_line_numbers; + size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); + if (!events_data->buffer || needed_size > events_data->buffer_size) { + g_free (events_data->buffer); + events_data->buffer_size = (size_t)(needed_size * 1.5); + events_data->buffer = g_new (uint8_t, events_data->buffer_size); + } - ep_write_event (EventPipeEventMethodDCEndVerbose_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + if (events_data->buffer) { + il_offsets = (uint32_t*)events_data->buffer; + native_offsets = il_offsets + offset_entries; -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; + for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { + il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; + native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; + } + } -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); + mono_debug_free_method_jit_info (debug_info); + } + + if (events_data->buffer && !il_offsets && !native_offsets) { + // No IL offset -> Native offset mapping available. Put all code on IL offset 0. + EP_ASSERT (events_data->buffer_size >= sizeof (uint32_t) * 2); + offset_entries = 1; + il_offsets = (uint32_t*)events_data->buffer; + native_offsets = il_offsets + offset_entries; + il_offsets [0] = 0; + native_offsets [0] = (uint32_t)ji->code_size; + } + + events_data->method_events_func ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags, + (ep_char8_t *)method_namespace, + (ep_char8_t *)method_name, + (ep_char8_t *)method_signature, + offset_entries, + il_offsets, + native_offsets, + NULL); + + g_free (method_namespace); + g_free (method_signature); } static -bool -write_event_module_dc_end_v2 ( - const uint64_t module_id, - const uint64_t assembly_id, - const uint32_t module_flags, - const uint32_t reserved_1, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint16_t clr_instance_id, - const uint8_t *managed_pdb_signature, - const uint32_t managed_pdb_age, - const ep_char8_t *managed_pdb_build_path, - const uint8_t *native_pdb_signature, - const uint32_t native_pdb_age, - const ep_char8_t *native_pdb_build_path, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +void +eventpipe_fire_method_events_func ( + MonoJitInfo *ji, + void *user_data) { - EP_ASSERT (EventPipeEventModuleDCEnd_V2 != NULL); + EventPipeFireMethodEventsData *events_data = (EventPipeFireMethodEventsData *)user_data; + EP_ASSERT (events_data != NULL); - if (!ep_event_is_enabled (EventPipeEventModuleDCEnd_V2)) - return true; - - uint8_t stack_buffer [290]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; + if (ji && !ji->is_trampoline && !ji->async) { + MonoMethod *method = jinfo_get_method (ji); + if (method && !m_method_is_wrapper (method)) + eventpipe_fire_method_events (ji, method, events_data); + } +} - success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&module_flags, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&reserved_1, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (module_il_path, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (module_native_path, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_guid_t (managed_pdb_signature, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&managed_pdb_age, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (managed_pdb_build_path, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_guid_t (native_pdb_signature, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&native_pdb_age, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (native_pdb_build_path, &buffer, &offset, &size, &fixed_buffer); +static +void +eventpipe_fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func) +{ + EP_ASSERT (domain != NULL); + EP_ASSERT (assembly != NULL); + EP_ASSERT (assembly_events_func != NULL); + + uint64_t domain_id = (uint64_t)domain; + uint64_t module_id = (uint64_t)assembly->image; + uint64_t assembly_id = (uint64_t)assembly; + + // TODO: Extract all module IL/Native paths and pdb metadata when available. + const char *module_il_path = ""; + const char *module_il_pdb_path = ""; + const char *module_native_path = ""; + const char *module_native_pdb_path = ""; + uint8_t signature [EP_GUID_SIZE] = { 0 }; + uint32_t module_il_pdb_age = 0; + uint32_t module_native_pdb_age = 0; + + uint32_t reserved_flags = 0; + uint64_t binding_id = 0; + + // Native methods are part of JIT table and already emitted. + // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? + + // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. + uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; + if (assembly->image) { + if (assembly->image->dynamic) + module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; + if (assembly->image->aot_module) + module_flags |= MODULE_FLAGS_NATIVE_MODULE; + + module_il_path = assembly->image->filename ? assembly->image->filename : ""; + } - ep_raise_error_if_nok (success); + uint32_t assembly_flags = 0; + if (assembly->dynamic) + assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; - ep_write_event (EventPipeEventModuleDCEnd_V2, buffer, (uint32_t)offset, activity_id, related_activity_id); + if (assembly->image && assembly->image->aot_module) { + assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; + } -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; + char *assembly_name = mono_stringify_assembly_name (&assembly->aname); -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); + assembly_events_func ( + domain_id, + assembly_id, + assembly_flags, + binding_id, + (const ep_char8_t*)assembly_name, + module_id, + module_flags, + reserved_flags, + (const ep_char8_t *)module_il_path, + (const ep_char8_t *)module_native_path, + signature, + module_il_pdb_age, + (const ep_char8_t *)module_il_pdb_path, + signature, + module_native_pdb_age, + (const ep_char8_t *)module_native_pdb_path, + NULL); + + g_free (assembly_name); } static -bool -write_event_domain_module_dc_end_v1 ( - const uint64_t module_id, - const uint64_t assembly_id, - const uint64_t domain_id, - const uint32_t module_flags, - const uint32_t reserved_1, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +gboolean +eventpipe_execute_rundown ( + ep_rt_mono_fire_domain_rundown_events_func domain_events_func, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, + ep_rt_mono_fire_method_rundown_events_func method_events_func) { - EP_ASSERT (EventPipeEventDomainModuleDCEnd_V1 != NULL); + EP_ASSERT (domain_events_func != NULL); + EP_ASSERT (assembly_events_func != NULL); + EP_ASSERT (method_events_func != NULL); + + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + if (root_domain) { + uint64_t domain_id = (uint64_t)root_domain; + + // Iterate all functions in use (both JIT and AOT). + EventPipeFireMethodEventsData events_data; + events_data.domain = root_domain; + events_data.buffer_size = 1024 * sizeof(uint32_t); + events_data.buffer = g_new (uint8_t, events_data.buffer_size); + events_data.method_events_func = method_events_func; + mono_jit_info_table_foreach_internal (eventpipe_fire_method_events_func, &events_data); + g_free (events_data.buffer); + + // Iterate all assemblies in domain. + GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies (); + if (assemblies) { + for (int i = 0; i < assemblies->len; ++i) { + MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); + if (assembly) + eventpipe_fire_assembly_events (root_domain, assembly, assembly_events_func); + } + g_ptr_array_free (assemblies, TRUE); + } - if (!ep_event_is_enabled (EventPipeEventDomainModuleDCEnd_V1)) - return true; + uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; + const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : ""; + uint32_t domain_index = 1; - uint8_t stack_buffer [162]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; + domain_events_func ( + domain_id, + domain_flags, + (const ep_char8_t *)domain_name, + domain_index, + NULL); + } - success &= write_buffer_uint64_t (&module_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&module_flags, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&reserved_1, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (module_il_path, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (module_native_path, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + return TRUE; +} - ep_raise_error_if_nok (success); +static +gboolean +eventpipe_walk_managed_stack_for_thread_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data) +{ + EP_ASSERT (frame != NULL); + EP_ASSERT (data != NULL); + + switch (frame->type) { + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: + case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX: + return FALSE; + case FRAME_TYPE_MANAGED: + case FRAME_TYPE_INTERP: + if (!frame->ji) + return FALSE; + MonoMethod *method = frame->ji->async ? NULL : frame->actual_method; + if (method && !m_method_is_wrapper (method)) + ep_stack_contents_append ((EventPipeStackContents *)data, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method); + return ep_stack_contents_get_length ((EventPipeStackContents *)data) >= EP_MAX_STACK_DEPTH; + default: + EP_UNREACHABLE ("eventpipe_walk_managed_stack_for_thread_func"); + return FALSE; + } +} - ep_write_event (EventPipeEventDomainModuleDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); +static +gboolean +eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data) +{ + EP_ASSERT (frame != NULL); + EP_ASSERT (data != NULL); -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; + EventPipeSampleProfileData *sample_data = (EventPipeSampleProfileData *)data; -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); + if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) { + if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; + else + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + } + + return eventpipe_walk_managed_stack_for_thread_func (frame, ctx, &sample_data->stack_contents); } static -bool -write_event_assembly_dc_end_v1 ( - const uint64_t assembly_id, - const uint64_t domain_id, - const uint64_t binding_id, - const uint32_t assembly_flags, - const ep_char8_t *fully_qualified_name, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +void +profiler_eventpipe_thread_exited ( + MonoProfiler *prof, + uintptr_t tid) { - EP_ASSERT (EventPipeEventAssemblyDCEnd_V1 != NULL); + void ep_rt_mono_thread_exited (void); + ep_rt_mono_thread_exited (); +} - if (!ep_event_is_enabled (EventPipeEventAssemblyDCEnd_V1)) - return true; +void +ep_rt_mono_init (void) +{ + mono_native_tls_alloc (&_ep_rt_mono_thread_holder_tls_id, NULL); - uint8_t stack_buffer [94]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; + mono_100ns_ticks (); + mono_rand_open (); + _ep_rt_mono_rand_provider = mono_rand_init (NULL, 0); - success &= write_buffer_uint64_t (&assembly_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint64_t (&binding_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&assembly_flags, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (fully_qualified_name, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); + _ep_rt_mono_initialized = TRUE; - ep_raise_error_if_nok (success); + MonoProfilerHandle profiler = mono_profiler_create (NULL); + mono_profiler_set_thread_stopped_callback (profiler, profiler_eventpipe_thread_exited); +} - ep_write_event (EventPipeEventAssemblyDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); +void +ep_rt_mono_fini (void) +{ + if (_ep_rt_mono_sampled_thread_callstacks) + g_array_free (_ep_rt_mono_sampled_thread_callstacks, TRUE); -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; + if (_ep_rt_mono_initialized) + mono_rand_close (_ep_rt_mono_rand_provider); -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); + _ep_rt_mono_sampled_thread_callstacks = NULL; + _ep_rt_mono_rand_provider = NULL; + _ep_rt_mono_initialized = FALSE; } -static bool -write_event_domain_dc_end_v1 ( - const uint64_t domain_id, - const uint32_t domain_flags, - const ep_char8_t *domain_name, - const uint32_t domain_index, - const uint16_t clr_instance_id, - const uint8_t *activity_id, - const uint8_t *related_activity_id) +ep_rt_mono_rand_try_get_bytes ( + uint8_t *buffer, + size_t buffer_size) { - EP_ASSERT (EventPipeEventAppDomainDCEnd_V1 != NULL); - - if (!ep_event_is_enabled (EventPipeEventAppDomainDCEnd_V1)) - return true; + EP_ASSERT (_ep_rt_mono_rand_provider != NULL); - uint8_t stack_buffer [82]; - uint8_t *buffer = stack_buffer; - size_t offset = 0; - size_t size = sizeof (stack_buffer); - bool fixed_buffer = true; - bool success = true; + ERROR_DECL (error); + return mono_rand_try_get_bytes (&_ep_rt_mono_rand_provider, (guchar *)buffer, (gssize)buffer_size, error); +} - success &= write_buffer_uint64_t (&domain_id, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&domain_flags, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_string_utf8_t (domain_name, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint32_t (&domain_index, &buffer, &offset, &size, &fixed_buffer); - success &= write_buffer_uint16_t (&clr_instance_id, &buffer, &offset, &size, &fixed_buffer); +EventPipeThread * +ep_rt_mono_thread_get_or_create (void) +{ + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); + if (!thread_holder) { + thread_holder = thread_holder_alloc_func (); + mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, thread_holder); + } + return ep_thread_holder_get_thread (thread_holder); +} - ep_raise_error_if_nok (success); +void * +ep_rt_mono_thread_attach (bool background_thread) +{ + MonoThread *thread = NULL; + + // NOTE, under netcore, only root domain exists. + if (!mono_thread_current ()) { + thread = mono_thread_internal_attach (mono_get_root_domain ()); + if (background_thread && thread) { + mono_thread_set_state (thread, ThreadState_Background); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE); + } + } - ep_write_event (EventPipeEventAppDomainDCEnd_V1, buffer, (uint32_t)offset, activity_id, related_activity_id); + return thread; +} -ep_on_exit: - if (!fixed_buffer) - ep_rt_byte_array_free (buffer); - return success; +void +ep_rt_mono_thread_detach (void) +{ + MonoThread *current_thread = mono_thread_current (); + if (current_thread) + mono_thread_internal_detach (current_thread); +} -ep_on_error: - EP_ASSERT (!success); - ep_exit_error_handler (); +void +ep_rt_mono_thread_exited (void) +{ + if (_ep_rt_mono_initialized) { + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); + if (thread_holder) + thread_holder_free_func (thread_holder); + mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, NULL); + } } -// Mapping FireEtw* CoreClr functions. -#define FireEtwRuntimeInformationDCStart(...) write_runtime_info_dc_start(__VA_ARGS__,NULL,NULL) -#define FireEtwDCEndInit_V1(...) write_event_dc_end_init_v1(__VA_ARGS__,NULL,NULL) -#define FireEtwMethodDCEndILToNativeMap(...) write_event_method_dc_end_il_to_native_map(__VA_ARGS__,NULL,NULL) -#define FireEtwMethodDCEndVerbose_V1(...) write_event_method_dc_end_verbose_v1(__VA_ARGS__,NULL,NULL) -#define FireEtwModuleDCEnd_V2(...) write_event_module_dc_end_v2(__VA_ARGS__,NULL,NULL) -#define FireEtwDomainModuleDCEnd_V1(...) write_event_domain_module_dc_end_v1(__VA_ARGS__,NULL,NULL) -#define FireEtwAssemblyDCEnd_V1(...) write_event_assembly_dc_end_v1(__VA_ARGS__,NULL,NULL) -#define FireEtwAppDomainDCEnd_V1(...) write_event_domain_dc_end_v1(__VA_ARGS__,NULL,NULL) -#define FireEtwDCEndComplete_V1(...) write_event_dc_end_complete_v1(__VA_ARGS__,NULL,NULL) +#ifdef HOST_WIN32 +int64_t +ep_rt_mono_perf_counter_query (void) +{ + LARGE_INTEGER value; + if (QueryPerformanceCounter (&value)) + return (int64_t)value.QuadPart; + else + return 0; +} -static -bool -fire_method_rundown_events_func ( - const uint64_t method_id, - const uint64_t module_id, - const uint64_t method_start_address, - const uint32_t method_size, - const uint32_t method_token, - const uint32_t method_flags, - const ep_char8_t *method_namespace, - const ep_char8_t *method_name, - const ep_char8_t *method_signature, - const uint16_t count_of_map_entries, - const uint32_t *il_offsets, - const uint32_t *native_offsets, - void *user_data) +int64_t +ep_rt_mono_perf_frequency_query (void) { - FireEtwMethodDCEndILToNativeMap ( - method_id, - 0, - 0, - count_of_map_entries, - il_offsets, - native_offsets, - clr_instance_get_id ()); + LARGE_INTEGER value; + if (QueryPerformanceFrequency (&value)) + return (int64_t)value.QuadPart; + else + return 0; +} - FireEtwMethodDCEndVerbose_V1 ( - method_id, - module_id, - method_start_address, - method_size, - method_token, - method_flags, - method_namespace, - method_name, - method_signature, - clr_instance_get_id ()); +void +ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) +{ + SYSTEMTIME value; + GetSystemTime (&value); - return true; + EP_ASSERT (system_time != NULL); + ep_system_time_set ( + system_time, + value.wYear, + value.wMonth, + value.wDayOfWeek, + value.wDay, + value.wHour, + value.wMinute, + value.wSecond, + value.wMilliseconds); } -static -bool -fire_assembly_rundown_events_func ( - const uint64_t domain_id, - const uint64_t assembly_id, - const uint32_t assembly_flags, - const uint32_t binding_id, - const ep_char8_t *assembly_name, - const uint64_t module_id, - const uint32_t module_flags, - const uint32_t reserved_flags, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint8_t *managed_pdb_signature, - const uint32_t managed_pdb_age, - const ep_char8_t *managed_pdb_build_path, - const uint8_t *native_pdb_signature, - const uint32_t native_pdb_age, - const ep_char8_t *native_pdb_build_path, - void *user_data) +int64_t +ep_rt_mono_system_timestamp_get (void) { - FireEtwModuleDCEnd_V2 ( - module_id, - assembly_id, - module_flags, - reserved_flags, - module_il_path, - module_native_path, - clr_instance_get_id (), - managed_pdb_signature, - managed_pdb_age, - managed_pdb_build_path, - native_pdb_signature, - native_pdb_age, - native_pdb_build_path); + FILETIME value; + GetSystemTimeAsFileTime (&value); + return (int64_t)((((uint64_t)value.dwHighDateTime) << 32) | (uint64_t)value.dwLowDateTime); +} +#else +#include +#include +#include +#include + +#if HAVE_SYS_TIME_H +#include +#endif // HAVE_SYS_TIME_H + +#if HAVE_MACH_ABSOLUTE_TIME +#include +static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; +static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0}; +#endif + +#ifdef HAVE_LOCALTIME_R +#define HAVE_GMTIME_R 1 +#endif + +static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; +static const int64_t SECS_TO_100NS = 10000000; +static const int64_t SECS_TO_NS = 1000000000; +static const int64_t MSECS_TO_MIS = 1000; + +/* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ +#if defined (HAVE_CLOCK_MONOTONIC) && (defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)) +#undef HAVE_CLOCK_MONOTONIC +#endif + +#ifndef HAVE_CLOCK_MONOTONIC +static const int64_t MISECS_TO_NS = 1000; +#endif - FireEtwDomainModuleDCEnd_V1 ( - module_id, - assembly_id, - domain_id, - module_flags, - reserved_flags, - module_il_path, - module_native_path, - clr_instance_get_id ()); +static +void +time_base_info_lazy_init (void); - FireEtwAssemblyDCEnd_V1 ( - assembly_id, - domain_id, - binding_id, - assembly_flags, - assembly_name, - clr_instance_get_id ()); +static +int64_t +system_time_to_int64 ( + time_t sec, + long nsec); - return true; +#if HAVE_MACH_ABSOLUTE_TIME +static +void +time_base_info_lazy_init (void) +{ + kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info); + if (result != KERN_SUCCESS) + memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info)); } +#endif -static -bool -fire_domain_rundown_events_func ( - const uint64_t domain_id, - const uint32_t domain_flags, - const ep_char8_t *domain_name, - const uint32_t domain_index, - void *user_data) +int64_t +ep_rt_mono_perf_counter_query (void) { - return FireEtwAppDomainDCEnd_V1 ( - domain_id, - domain_flags, - domain_name, - domain_index, - clr_instance_get_id ()); +#if HAVE_MACH_ABSOLUTE_TIME + return (int64_t)mach_absolute_time (); +#elif HAVE_CLOCK_MONOTONIC + struct timespec ts; + int result = clock_gettime (CLOCK_MONOTONIC, &ts); + if (result == 0) + return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec); +#else + #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." +#endif + return 0; +} + +int64_t +ep_rt_mono_perf_frequency_query (void) +{ +#if HAVE_MACH_ABSOLUTE_TIME + // (numer / denom) gives you the nanoseconds per tick, so the below code + // computes the number of ticks per second. We explicitly do the multiplication + // first in order to help minimize the error that is produced by integer division. + mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init); + if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0) + return 0; + return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer); +#elif HAVE_CLOCK_MONOTONIC + // clock_gettime () returns a result in terms of nanoseconds rather than a count. This + // means that we need to either always scale the result by the actual resolution (to + // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer + // the latter since it allows the highest throughput and should minimize error propagated + // to the user. + return (int64_t)(SECS_TO_NS); +#else + #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." +#endif + return 0; } -static void -init_dotnet_runtime_rundown (void) +ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) { - //TODO: Add callback method to enable/disable more native events getting into EventPipe (when enabled). - EP_ASSERT (EventPipeProviderDotNETRuntimeRundown == NULL); - EventPipeProviderDotNETRuntimeRundown = ep_create_provider (ep_config_get_rundown_provider_name_utf8 (), NULL, NULL, NULL); + time_t tt; +#if HAVE_GMTIME_R + struct tm ut; +#endif /* HAVE_GMTIME_R */ + struct tm *ut_ptr; + struct timeval time_val; + int timeofday_retval; - EP_ASSERT (EventPipeEventMethodDCEndVerbose_V1 == NULL); - EventPipeEventMethodDCEndVerbose_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 144, 48, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + EP_ASSERT (system_time != NULL); - EP_ASSERT (EventPipeEventDCEndComplete_V1 == NULL); - EventPipeEventDCEndComplete_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 146, 131128, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + tt = time (NULL); - EP_ASSERT (EventPipeEventDCEndInit_V1 == NULL); - EventPipeEventDCEndInit_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 148, 131128, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + /* We can't get millisecond resolution from time (), so we get it from gettimeofday () */ + timeofday_retval = gettimeofday (&time_val, NULL); - EP_ASSERT (EventPipeEventMethodDCEndILToNativeMap == NULL); - EventPipeEventMethodDCEndILToNativeMap = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 150, 131072, 0, EP_EVENT_LEVEL_VERBOSE, true, NULL, 0); +#if HAVE_GMTIME_R + ut_ptr = &ut; + if (gmtime_r (&tt, ut_ptr) == NULL) +#else /* HAVE_GMTIME_R */ + if ((ut_ptr = gmtime (&tt)) == NULL) +#endif /* HAVE_GMTIME_R */ + EP_UNREACHABLE (); - EP_ASSERT (EventPipeEventDomainModuleDCEnd_V1 == NULL); - EventPipeEventDomainModuleDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 152, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + uint16_t milliseconds = 0; + if (timeofday_retval != -1) { + int old_seconds; + int new_seconds; - EP_ASSERT (EventPipeEventModuleDCEnd_V2 == NULL); - EventPipeEventModuleDCEnd_V2 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 154, 536870920, 2, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + milliseconds = time_val.tv_usec / MSECS_TO_MIS; - EP_ASSERT (EventPipeEventAssemblyDCEnd_V1 == NULL); - EventPipeEventAssemblyDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 156, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + old_seconds = ut_ptr->tm_sec; + new_seconds = time_val.tv_sec % 60; - EP_ASSERT (EventPipeEventAppDomainDCEnd_V1 == NULL); - EventPipeEventAppDomainDCEnd_V1 = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 158, 8, 1, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + /* just in case we reached the next second in the interval between time () and gettimeofday () */ + if (old_seconds != new_seconds) + milliseconds = 999; + } - EP_ASSERT (EventPipeEventRuntimeInformationDCStart == NULL); - EventPipeEventRuntimeInformationDCStart = ep_provider_add_event (EventPipeProviderDotNETRuntimeRundown, 187, 0, 0, EP_EVENT_LEVEL_INFORMATIONAL, true, NULL, 0); + ep_system_time_set ( + system_time, + 1900 + ut_ptr->tm_year, + ut_ptr->tm_mon + 1, + ut_ptr->tm_wday, + ut_ptr->tm_mday, + ut_ptr->tm_hour, + ut_ptr->tm_min, + ut_ptr->tm_sec, + milliseconds); +} + +static +inline +int64_t +system_time_to_int64 ( + time_t sec, + long nsec) +{ + return ((int64_t)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + (nsec / 100); +} + +int64_t +ep_rt_mono_system_timestamp_get (void) +{ +#if HAVE_CLOCK_MONOTONIC + struct timespec time; + if (clock_gettime (CLOCK_REALTIME, &time) == 0) + return system_time_to_int64 (time.tv_sec, time.tv_nsec); +#else + struct timeval time; + if (gettimeofday (&time, NULL) == 0) + return system_time_to_int64 (time.tv_sec, time.tv_usec * MISECS_TO_NS); +#endif + else + return system_time_to_int64 (0, 0); +} +#endif + +#ifndef HOST_WIN32 +#if defined(__APPLE__) +#if defined (TARGET_OSX) +G_BEGIN_DECLS +gchar ***_NSGetEnviron(void); +G_END_DECLS +#define environ (*_NSGetEnviron()) +#else +static char *_ep_rt_mono_environ[1] = { NULL }; +#define environ _ep_rt_mono_environ +#endif /* defined (TARGET_OSX) */ +#else +G_BEGIN_DECLS +extern char **environ; +G_END_DECLS +#endif /* defined (__APPLE__) */ +#endif /* !defined (HOST_WIN32) */ + +void +ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) +{ + EP_ASSERT (env_array != NULL); +#ifdef HOST_WIN32 + LPWSTR envs = GetEnvironmentStringsW (); + if (envs) { + LPWSTR next = envs; + while (*next) { + ep_rt_env_array_utf16_append (env_array, ep_rt_utf16_string_dup (next)); + next += ep_rt_utf16_string_len (next) + 1; + } + FreeEnvironmentStringsW (envs); + } +#else + gchar **next = NULL; + for (next = environ; *next != NULL; ++next) + ep_rt_env_array_utf16_append (env_array, ep_rt_utf8_to_utf16_string (*next, -1)); +#endif } void ep_rt_mono_init_providers_and_events (void) { init_dotnet_runtime_rundown (); + init_dotnet_runtime_private (); } void @@ -1296,9 +1987,125 @@ ep_rt_mono_fini_providers_and_events (void) // Deallocating providers/events here might cause AV if a WriteEvent // was to occur. Thus, we are not doing this cleanup. + // ep_delete_provider (EventPipeProviderDotNETRuntimePrivate); // ep_delete_provider (EventPipeProviderDotNETRuntimeRundown); } +bool +ep_rt_mono_walk_managed_stack_for_thread ( + ep_rt_thread_handle_t thread, + EventPipeStackContents *stack_contents) +{ + EP_ASSERT (thread != NULL && stack_contents != NULL); + + if (thread == ep_rt_thread_get_handle ()) + mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (eventpipe_walk_managed_stack_for_thread_func, NULL, MONO_UNWIND_SIGNAL_SAFE, stack_contents); + else + mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_walk_managed_stack_for_thread_func, mono_thread_info_get_suspend_state (thread), MONO_UNWIND_SIGNAL_SAFE, stack_contents); + + return true; +} + +bool +ep_rt_mono_method_get_simple_assembly_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len) +{ + EP_ASSERT (method != NULL); + EP_ASSERT (name != NULL); + + MonoClass *method_class = mono_method_get_class (method); + MonoImage *method_image = method_class ? mono_class_get_image (method_class) : NULL; + const ep_char8_t *assembly_name = method_image ? mono_image_get_name (method_image) : NULL; + + if (!assembly_name) + return false; + + g_strlcpy (name, assembly_name, name_len); + return true; +} + +bool +ep_rt_mono_method_get_full_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len) +{ + EP_ASSERT (method != NULL); + EP_ASSERT (name != NULL); + + char *full_method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL); + if (!full_method_name) + return false; + + g_strlcpy (name, full_method_name, name_len); + + g_free (full_method_name); + return true; +} + +bool +ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event) +{ + // Follows CoreClr implementation of sample profiler. Generic invasive/expensive way to do CPU sample profiling relying on STW and stackwalks. + // TODO: Investigate alternatives on platforms supporting Signals/SuspendThread (see Mono profiler) or CPU PMU's (see ETW/perf_event_open). + + // Sample profiler only runs on one thread, no need to synchorinize. + if (!_ep_rt_mono_sampled_thread_callstacks) + _ep_rt_mono_sampled_thread_callstacks = g_array_sized_new (FALSE, FALSE, sizeof (EventPipeSampleProfileData), _ep_rt_mono_max_sampled_thread_count); + + // Make sure there is room based on previous max number of sampled threads. + // NOTE, there is a chance there are more threads than max, if that's the case we will + // miss those threads in this sample, but will be included in next when max has been adjusted. + g_array_set_size (_ep_rt_mono_sampled_thread_callstacks, _ep_rt_mono_max_sampled_thread_count); + + uint32_t filtered_thread_count = 0; + uint32_t sampled_thread_count = 0; + + mono_stop_world (MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE); + + // Record all info needed in sample events while runtime is suspended, must be async safe. + FOREACH_THREAD_SAFE_EXCLUDE (thread_info, MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE) { + if (!mono_thread_info_is_running (thread_info)) { + MonoThreadUnwindState *thread_state = mono_thread_info_get_suspend_state (thread_info); + if (thread_state->valid) { + if (sampled_thread_count < _ep_rt_mono_max_sampled_thread_count) { + EventPipeSampleProfileData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileData, sampled_thread_count); + data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info)); + data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx); + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR; + ep_stack_contents_reset (&data->stack_contents); + mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_sample_profiler_walk_managed_stack_for_thread_func, thread_state, MONO_UNWIND_SIGNAL_SAFE, data); + sampled_thread_count++; + } + } + } + filtered_thread_count++; + } FOREACH_THREAD_SAFE_END + + mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE); + + // Fire sample event for threads. Must be done after runtime is resumed since it's not async safe. + // Since we can't keep thread info around after runtime as been suspended, use an empty + // adapter instance and only set recorded tid as parameter inside adapter. + THREAD_INFO_TYPE adapter = { { 0 } }; + for (uint32_t i = 0; i < sampled_thread_count; ++i) { + EventPipeSampleProfileData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileData, i); + if (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length(&data->stack_contents) > 0) { + mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id)); + ep_write_sample_profile_event (sampling_thread, sampling_event, &adapter, &data->stack_contents, (uint8_t *)&data->payload_data, sizeof (data->payload_data)); + } + } + + // Current thread count will be our next maximum sampled threads. + _ep_rt_mono_max_sampled_thread_count = filtered_thread_count; + + return true; +} + void ep_rt_mono_execute_rundown (void) { @@ -1331,8 +2138,7 @@ ep_rt_mono_execute_rundown (void) FireEtwDCEndInit_V1 (clr_instance_get_id ()); - EP_ASSERT (_ep_rt_mono_func_table.ep_rt_mono_execute_rundown != NULL); - _ep_rt_mono_func_table.ep_rt_mono_execute_rundown ( + eventpipe_execute_rundown ( fire_domain_rundown_events_func, fire_assembly_rundown_events_func, fire_method_rundown_events_func); @@ -1340,6 +2146,12 @@ ep_rt_mono_execute_rundown (void) FireEtwDCEndComplete_V1 (clr_instance_get_id ()); } +bool +ep_rt_mono_write_event_ee_startup_start (void) +{ + return FireEtwEEStartupStart_V1 (clr_instance_get_id ()); +} + #endif /* ENABLE_PERFTRACING */ MONO_EMPTY_SOURCE_FILE(eventpipe_rt_mono); diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index e8590d9bbdafbb..fd8c94cd766cb7 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -10,6 +10,7 @@ #include #include #include + #include #include #include @@ -17,11 +18,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include #undef EP_ARRAY_SIZE #define EP_ARRAY_SIZE(expr) G_N_ELEMENTS(expr) @@ -347,166 +348,12 @@ prefix_name ## _rt_ ## type_name ## _ ## func_name #define EP_RT_DEFINE_HASH_MAP_ITERATOR(hash_map_name, hash_map_type, iterator_type, key_type, value_type) \ EP_RT_DEFINE_HASH_MAP_ITERATOR_PREFIX(ep, hash_map_name, hash_map_type, iterator_type, key_type, value_type) -// Rundown callbacks. -typedef -bool -(*ep_rt_mono_fire_method_rundown_events_func)( - const uint64_t method_id, - const uint64_t module_id, - const uint64_t method_start_address, - const uint32_t method_size, - const uint32_t method_token, - const uint32_t method_flags, - const ep_char8_t *method_namespace, - const ep_char8_t *method_name, - const ep_char8_t *method_signature, - const uint16_t count_of_map_entries, - const uint32_t *il_offsets, - const uint32_t *native_offsets, - void *user_data); - -typedef -bool -(*ep_rt_mono_fire_assembly_rundown_events_func)( - const uint64_t domain_id, - const uint64_t assembly_id, - const uint32_t assembly_flags, - const uint32_t binding_id, - const ep_char8_t *assembly_name, - const uint64_t module_id, - const uint32_t module_flags, - const uint32_t reserved_flags, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint8_t *managed_pdb_signature, - const uint32_t managed_pdb_age, - const ep_char8_t *managed_pdb_build_path, - const uint8_t *native_pdb_signature, - const uint32_t native_pdb_age, - const ep_char8_t *native_pdb_build_path, - void *user_data); - -typedef -bool -(*ep_rt_mono_fire_domain_rundown_events_func)( - const uint64_t domain_id, - const uint32_t domain_flags, - const ep_char8_t *domain_name, - const uint32_t domain_index, - void *user_data); - -typedef EventPipeThreadHolder * (*ep_rt_thread_holder_alloc_func)(void); -typedef void (*ep_rt_thread_holder_free_func)(EventPipeThreadHolder *thread_holder); - -typedef int (*ep_rt_mono_cpu_count_func)(void); -typedef int (*ep_rt_mono_process_current_pid_func)(void); -typedef MonoNativeThreadId (*ep_rt_mono_native_thread_id_get_func)(void); -typedef gboolean (*ep_rt_mono_native_thread_id_equals_func)(MonoNativeThreadId, MonoNativeThreadId); -typedef gboolean (*ep_rt_mono_runtime_is_shutting_down_func)(void); -typedef gboolean (*ep_rt_mono_rand_try_get_bytes_func)(guchar *buffer, gssize buffer_size, MonoError *error); -typedef EventPipeThread * (*ep_rt_mono_thread_get_func)(void); -typedef EventPipeThread * (*ep_rt_mono_thread_get_or_create_func)(void); -typedef void (*ep_rt_mono_thread_exited_func)(void); -typedef gint (*ep_rt_mono_thread_info_sleep_func)(guint32 ms, gboolean *alerted); -typedef gboolean (*ep_rt_mono_thread_info_yield_func)(void); -typedef gpointer (*ep_rt_mono_w32file_create_func)(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs); -typedef gboolean (*ep_rt_mono_w32file_write_func)(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error); -typedef gboolean (*ep_rt_mono_w32file_close_func)(gpointer handle); -typedef gpointer (*ep_rt_mono_w32event_create_func)(gboolean manual, gboolean initial); -typedef gboolean (*ep_rt_mono_w32event_close_func)(gpointer handle); -typedef void (*ep_rt_mono_w32event_set_func)(gpointer handle); -typedef MonoW32HandleWaitRet (*ep_rt_mono_w32handle_wait_one_func)(gpointer handle, guint32 timeout, gboolean alertable); -typedef void* (*ep_rt_mono_valloc_func)(void *addr, size_t length, int flags, MonoMemAccountType type); -typedef int (*ep_rt_mono_vfree_func)(void *addr, size_t length, MonoMemAccountType type); -typedef int (*ep_rt_mono_valloc_granule_func)(void); -typedef gboolean (*ep_rt_mono_thread_platform_create_thread_func)(ep_rt_thread_start_func thread_func, gpointer thread_data, gsize * const stack_size, ep_rt_thread_id_t *thread_id); -typedef gpointer (*ep_rt_mono_thread_attach_func)(gboolean); -typedef void (*ep_rt_mono_thread_detach_func)(void); -typedef char* (*ep_rt_mono_get_os_cmd_line_func)(void); -typedef char* (*ep_rt_mono_get_managed_cmd_line_func)(void); -typedef gboolean (*ep_rt_mono_execute_rundown_func)(ep_rt_mono_fire_domain_rundown_events_func domain_events_func, ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, ep_rt_mono_fire_method_rundown_events_func methods_events_func); -typedef gboolean (*ep_rt_mono_walk_managed_stack_for_thread_func)(ep_rt_thread_handle_t thread, EventPipeStackContents *stack_contents); -typedef gboolean (*ep_rt_mono_sample_profiler_write_sampling_event_for_threads_func)(ep_rt_thread_handle_t sampling_thread, EventPipeEvent *sampling_event); -typedef gboolean (*ep_rt_mono_method_get_simple_assembly_name_func)(ep_rt_method_desc_t *method, ep_char8_t *name, size_t name_len); -typedef gboolean (*ep_rt_mono_method_get_full_name_func)(ep_rt_method_desc_t *method, ep_char8_t *name, size_t name_len); - -typedef struct _EventPipeMonoFuncTable { - ep_rt_mono_process_current_pid_func ep_rt_mono_process_current_pid; - ep_rt_mono_cpu_count_func ep_rt_mono_cpu_count; - ep_rt_mono_native_thread_id_get_func ep_rt_mono_native_thread_id_get; - ep_rt_mono_native_thread_id_equals_func ep_rt_mono_native_thread_id_equals; - ep_rt_mono_runtime_is_shutting_down_func ep_rt_mono_runtime_is_shutting_down; - ep_rt_mono_rand_try_get_bytes_func ep_rt_mono_rand_try_get_bytes; - ep_rt_mono_thread_get_func ep_rt_mono_thread_get; - ep_rt_mono_thread_get_or_create_func ep_rt_mono_thread_get_or_create; - ep_rt_mono_thread_exited_func ep_rt_mono_thread_exited; - ep_rt_mono_thread_info_sleep_func ep_rt_mono_thread_info_sleep; - ep_rt_mono_thread_info_yield_func ep_rt_mono_thread_info_yield; - ep_rt_mono_w32file_create_func ep_rt_mono_w32file_create; - ep_rt_mono_w32file_write_func ep_rt_mono_w32file_write; - ep_rt_mono_w32file_close_func ep_rt_mono_w32file_close; - ep_rt_mono_w32event_create_func ep_rt_mono_w32event_create; - ep_rt_mono_w32event_close_func ep_rt_mono_w32event_close; - ep_rt_mono_w32event_set_func ep_rt_mono_w32event_set; - ep_rt_mono_w32handle_wait_one_func ep_rt_mono_w32hadle_wait_one; - ep_rt_mono_valloc_func ep_rt_mono_valloc; - ep_rt_mono_vfree_func ep_rt_mono_vfree; - ep_rt_mono_valloc_granule_func ep_rt_mono_valloc_granule; - ep_rt_mono_thread_platform_create_thread_func ep_rt_mono_thread_platform_create_thread; - ep_rt_mono_thread_attach_func ep_rt_mono_thread_attach; - ep_rt_mono_thread_detach_func ep_rt_mono_thread_detach; - ep_rt_mono_get_os_cmd_line_func ep_rt_mono_get_os_cmd_line; - ep_rt_mono_get_managed_cmd_line_func ep_rt_mono_get_managed_cmd_line; - ep_rt_mono_execute_rundown_func ep_rt_mono_execute_rundown; - ep_rt_mono_walk_managed_stack_for_thread_func ep_rt_mono_walk_managed_stack_for_thread; - ep_rt_mono_sample_profiler_write_sampling_event_for_threads_func ep_rt_mono_sample_profiler_write_sampling_event_for_threads; - ep_rt_mono_method_get_simple_assembly_name_func ep_rt_mono_method_get_simple_assembly_name; - ep_rt_mono_method_get_full_name_func ep_rt_mono_method_get_full_name; -} EventPipeMonoFuncTable; - -int64_t -ep_rt_mono_perf_counter_query (void); - -int64_t -ep_rt_mono_perf_frequency_query (void); - -void -ep_rt_mono_system_time_get (EventPipeSystemTime *system_time); - -int64_t -ep_rt_mono_system_timestamp_get (void); - -void -ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array); - -void -ep_rt_mono_init_providers_and_events (void); - -void -ep_rt_mono_fini_providers_and_events (void); - -void -ep_rt_mono_execute_rundown (void); - -static -inline -EventPipeMonoFuncTable * -ep_rt_mono_func_table_get (void) -{ - extern EventPipeMonoFuncTable _ep_rt_mono_func_table; - return &_ep_rt_mono_func_table; -} - static inline char * os_command_line_get (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return mono_get_os_cmd_line (); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_get_os_cmd_line (); -#endif } static @@ -550,11 +397,7 @@ inline char * managed_command_line_get (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return mono_runtime_get_managed_cmd_line (); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_get_managed_cmd_line (); -#endif } static @@ -602,17 +445,6 @@ ep_rt_mono_config_lock_get (void) return &_ep_rt_mono_config_lock; } -MONO_PROFILER_API -void -mono_eventpipe_init ( - EventPipeMonoFuncTable *table, - ep_rt_thread_holder_alloc_func thread_holder_alloc_func, - ep_rt_thread_holder_free_func thread_holder_free_func); - -MONO_PROFILER_API -void -mono_eventpipe_fini (void); - /* * Helpers */ @@ -644,11 +476,7 @@ inline MonoNativeThreadId ep_rt_mono_native_thread_id_get (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return mono_native_thread_id_get (); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_native_thread_id_get (); -#endif } static @@ -656,27 +484,7 @@ inline gboolean ep_rt_mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return mono_native_thread_id_equals (id1, id2); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_native_thread_id_equals (id1, id2); -#endif -} - -static -inline -gboolean -ep_rt_mono_rand_try_get_bytes (guchar *buffer, gssize buffer_size, MonoError *error) -{ - return ep_rt_mono_func_table_get ()->ep_rt_mono_rand_try_get_bytes (buffer, buffer_size, error); -} - -static -inline -void -ep_rt_mono_thread_exited (void) -{ - ep_rt_mono_func_table_get ()->ep_rt_mono_thread_exited (); } static @@ -684,11 +492,8 @@ inline gpointer ep_rt_mono_w32file_create (const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + //TODO, replace with low level PAL implementation. return mono_w32file_create (name, fileaccess, sharemode, createmode, attrs); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_w32file_create (name, fileaccess, sharemode, createmode, attrs); -#endif } static @@ -696,11 +501,8 @@ inline gboolean ep_rt_mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + //TODO, replace with low level PAL implementation. return mono_w32file_write (handle, buffer, numbytes, byteswritten, win32error); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_w32file_write (handle, buffer, numbytes, byteswritten, win32error); -#endif } static @@ -708,11 +510,8 @@ inline gboolean ep_rt_mono_w32file_close (gpointer handle) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + //TODO, replace with low level PAL implementation. return mono_w32file_close (handle); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_w32file_close (handle); -#endif } static @@ -720,7 +519,8 @@ inline void ep_rt_mono_thread_setup (bool background_thread) { - ep_rt_mono_func_table_get ()->ep_rt_mono_thread_attach (background_thread); + extern void * ep_rt_mono_thread_attach (bool background_thread); + ep_rt_mono_thread_attach (background_thread); } static @@ -728,7 +528,8 @@ inline void ep_rt_mono_thread_teardown (void) { - ep_rt_mono_func_table_get ()->ep_rt_mono_thread_detach (); + extern void ep_rt_mono_thread_detach (void); + ep_rt_mono_thread_detach (); } /* @@ -803,7 +604,9 @@ inline void ep_rt_init (void) { - mono_eventpipe_init (ep_rt_mono_func_table_get (), thread_holder_alloc_func, thread_holder_free_func); + extern void ep_rt_mono_init (void); + ep_rt_mono_init (); + ep_rt_spin_lock_alloc (ep_rt_mono_config_lock_get ()); } @@ -816,7 +619,9 @@ ep_rt_shutdown (void) mono_lazy_cleanup (os_command_line_get_init (), os_command_line_lazy_clean); ep_rt_spin_lock_free (ep_rt_mono_config_lock_get ()); - mono_eventpipe_fini (); + + extern void ep_rt_mono_fini (void); + ep_rt_mono_fini (); } static @@ -860,7 +665,8 @@ ep_rt_walk_managed_stack_for_thread ( ep_rt_thread_handle_t thread, EventPipeStackContents *stack_contents) { - return (ep_rt_mono_func_table_get ()->ep_rt_mono_walk_managed_stack_for_thread (thread, stack_contents) == TRUE) ? true : false; + extern bool ep_rt_mono_walk_managed_stack_for_thread (ep_rt_thread_handle_t thread, EventPipeStackContents *stack_contents); + return ep_rt_mono_walk_managed_stack_for_thread (thread, stack_contents); } static @@ -871,7 +677,8 @@ ep_rt_method_get_simple_assembly_name ( ep_char8_t *name, size_t name_len) { - return (ep_rt_mono_func_table_get ()->ep_rt_mono_method_get_simple_assembly_name (method, name, name_len) == TRUE) ? true : false; + extern bool ep_rt_mono_method_get_simple_assembly_name (ep_rt_method_desc_t *method, ep_char8_t *name, size_t name_len); + return ep_rt_mono_method_get_simple_assembly_name (method, name, name_len); } static @@ -882,7 +689,8 @@ ep_rt_method_get_full_name ( ep_char8_t *name, size_t name_len) { - return (ep_rt_mono_func_table_get ()->ep_rt_mono_method_get_full_name (method, name, name_len) == TRUE) ? true : false; + extern bool ep_rt_mono_method_get_full_name (ep_rt_method_desc_t *method, ep_char8_t *name, size_t name_len); + return ep_rt_mono_method_get_full_name (method, name, name_len); } static @@ -898,6 +706,7 @@ inline void ep_rt_init_providers_and_events (void) { + extern void ep_rt_mono_init_providers_and_events (void); ep_rt_mono_init_providers_and_events (); } @@ -1089,7 +898,8 @@ static void ep_rt_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_handle_t sampling_thread, EventPipeEvent *sampling_event) { - ep_rt_mono_func_table_get ()->ep_rt_mono_sample_profiler_write_sampling_event_for_threads (sampling_thread, sampling_event); + extern bool ep_rt_mono_sample_profiler_write_sampling_event_for_threads (ep_rt_thread_handle_t sampling_thread, EventPipeEvent *sampling_event); + ep_rt_mono_sample_profiler_write_sampling_event_for_threads (sampling_thread, sampling_event); } static @@ -1196,12 +1006,9 @@ ep_rt_wait_event_alloc ( bool manual, bool initial) { + //TODO, replace with low level PAL implementation. EP_ASSERT (wait_event != NULL); -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME wait_event->event = mono_w32event_create (manual, initial); -#else - wait_event->event = ep_rt_mono_func_table_get ()->ep_rt_mono_w32event_create (manual, initial); -#endif } static @@ -1209,12 +1016,9 @@ inline void ep_rt_wait_event_free (ep_rt_wait_event_handle_t *wait_event) { + //TODO, replace with low level PAL implementation. if (wait_event != NULL && wait_event->event != NULL) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME mono_w32event_close (wait_event->event); -#else - ep_rt_mono_func_table_get ()->ep_rt_mono_w32event_close (wait_event->event); -#endif wait_event->event = NULL; } } @@ -1224,12 +1028,9 @@ inline bool ep_rt_wait_event_set (ep_rt_wait_event_handle_t *wait_event) { + //TODO, replace with low level PAL implementation. EP_ASSERT (wait_event != NULL && wait_event->event != NULL); -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME mono_w32event_set (wait_event->event); -#else - ep_rt_mono_func_table_get ()->ep_rt_mono_w32event_set (wait_event->event); -#endif return true; } @@ -1241,12 +1042,9 @@ ep_rt_wait_event_wait ( uint32_t timeout, bool alertable) { + //TODO, replace with low level PAL implementation. EP_ASSERT (wait_event != NULL && wait_event->event != NULL); -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (int32_t)mono_w32handle_wait_one (wait_event->event, timeout, alertable); -#else - return (int32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_w32hadle_wait_one (wait_event->event, timeout, alertable); -#endif } static @@ -1290,11 +1088,7 @@ inline bool ep_rt_process_detach (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (mono_runtime_is_shutting_down () == TRUE) ? true : false; -#else - return (ep_rt_mono_func_table_get ()->ep_rt_mono_runtime_is_shutting_down () == TRUE) ? true : false; -#endif } static @@ -1315,8 +1109,8 @@ ep_rt_create_activity_id ( EP_ASSERT (activity_id != NULL); EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); - ERROR_DECL (error); - ep_rt_mono_rand_try_get_bytes ((guchar *)activity_id, EP_ACTIVITY_ID_SIZE, error); + extern bool ep_rt_mono_rand_try_get_bytes (uint8_t *buffer,size_t buffer_size); + ep_rt_mono_rand_try_get_bytes ((guchar *)activity_id, EP_ACTIVITY_ID_SIZE); const uint16_t version_mask = 0xF000; const uint16_t random_guid_version = 0x4000; @@ -1347,7 +1141,7 @@ inline bool ep_rt_is_running (void) { - return ep_rt_process_detach (); + return !ep_rt_process_detach (); } static @@ -1357,8 +1151,10 @@ ep_rt_execute_rundown (void) { if (ep_rt_config_value_get_rundown () > 0) { // Ask the runtime to emit rundown events. - if (/*is_running &&*/ !ep_rt_process_shutdown ()) + if (/*is_running &&*/ !ep_rt_process_shutdown ()) { + extern void ep_rt_mono_execute_rundown (void); ep_rt_mono_execute_rundown (); + } } } @@ -1431,11 +1227,7 @@ ep_rt_thread_create ( thread_params->thread_params.thread_func = thread_func; thread_params->thread_params.thread_params = params; thread_params->background_thread = true; -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (mono_thread_platform_create_thread (ep_rt_thread_mono_start_func, thread_params, NULL, (ep_rt_thread_id_t *)id) == TRUE) ? true : false; -#else - return (ep_rt_mono_func_table_get ()->ep_rt_mono_thread_platform_create_thread (ep_rt_thread_mono_start_func, thread_params, NULL, (ep_rt_thread_id_t *)id) == TRUE) ? true : false; -#endif } return false; @@ -1454,11 +1246,7 @@ inline uint32_t ep_rt_current_process_get_id (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (uint32_t)mono_process_current_pid (); -#else - return (uint32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_process_current_pid (); -#endif } static @@ -1474,11 +1262,7 @@ inline uint32_t ep_rt_processors_get_count (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (uint32_t)mono_cpu_count (); -#else - return (uint32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_cpu_count (); -#endif } static @@ -1486,11 +1270,7 @@ inline ep_rt_thread_id_t ep_rt_current_thread_get_id (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return mono_native_thread_id_get (); -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_native_thread_id_get (); -#endif } static @@ -1498,6 +1278,7 @@ inline int64_t ep_rt_perf_counter_query (void) { + extern int64_t ep_rt_mono_perf_counter_query (void); return ep_rt_mono_perf_counter_query (); } @@ -1506,6 +1287,7 @@ inline int64_t ep_rt_perf_frequency_query (void) { + extern int64_t ep_rt_mono_perf_frequency_query (void); return ep_rt_mono_perf_frequency_query (); } @@ -1514,6 +1296,7 @@ inline void ep_rt_system_time_get (EventPipeSystemTime *system_time) { + extern void ep_rt_mono_system_time_get (EventPipeSystemTime *system_time); ep_rt_mono_system_time_get (system_time); } @@ -1522,6 +1305,7 @@ inline int64_t ep_rt_system_timestamp_get (void) { + extern int64_t ep_rt_mono_system_timestamp_get (void); return ep_rt_mono_system_timestamp_get (); } @@ -1530,11 +1314,7 @@ inline int32_t ep_rt_system_get_alloc_granularity (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (int32_t)mono_valloc_granule (); -#else - return (int32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_valloc_granule (); -#endif } static @@ -1602,11 +1382,8 @@ inline uint8_t * ep_rt_valloc0 (size_t buffer_size) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME uint8_t *buffer = (uint8_t *)mono_valloc (NULL, buffer_size, MONO_MMAP_READ | MONO_MMAP_WRITE, MONO_MEM_ACCOUNT_PROFILER); -#else - uint8_t *buffer = (uint8_t *)ep_rt_mono_func_table_get ()->ep_rt_mono_valloc (NULL, buffer_size, MONO_MMAP_READ | MONO_MMAP_WRITE, MONO_MEM_ACCOUNT_PROFILER); -#endif + if (buffer) memset (buffer, 0, buffer_size); return buffer; @@ -1620,11 +1397,7 @@ ep_rt_vfree ( size_t buffer_size) { if (buffer) -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME mono_vfree (buffer, buffer_size, MONO_MEM_ACCOUNT_PROFILER); -#else - ep_rt_mono_func_table_get ()->ep_rt_mono_vfree (buffer, buffer_size, MONO_MEM_ACCOUNT_PROFILER); -#endif } static @@ -1663,6 +1436,7 @@ inline void ep_rt_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) { + extern void ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array); ep_rt_mono_os_environment_get_utf16 (env_array); } @@ -1706,13 +1480,43 @@ ep_rt_lock_requires_lock_not_held (const ep_rt_lock_handle_t *lock) * SpinLock. */ +#ifdef EP_CHECKED_BUILD +static +inline +void +ep_rt_spin_lock_set_owning_thread_id ( + ep_rt_spin_lock_handle_t *spin_lock, + MonoNativeThreadId thread_id) +{ + if (sizeof (spin_lock->owning_thread_id) == sizeof (uint32_t)) + ep_rt_volatile_store_uint32_t ((uint32_t *)&spin_lock->owning_thread_id, MONO_NATIVE_THREAD_ID_TO_UINT (thread_id)); + else if (sizeof (spin_lock->owning_thread_id) == sizeof (uint64_t)) + ep_rt_volatile_store_uint64_t ((uint64_t *)&spin_lock->owning_thread_id, MONO_NATIVE_THREAD_ID_TO_UINT (thread_id)); + else + spin_lock->owning_thread_id = thread_id; +} + +static +inline +MonoNativeThreadId +ep_rt_spin_lock_get_owning_thread_id (const ep_rt_spin_lock_handle_t *spin_lock) +{ + if (sizeof (spin_lock->owning_thread_id) == sizeof (uint32_t)) + return MONO_UINT_TO_NATIVE_THREAD_ID (ep_rt_volatile_load_uint32_t ((const uint32_t *)&spin_lock->owning_thread_id)); + else if (sizeof (spin_lock->owning_thread_id) == sizeof (uint64_t)) + return MONO_UINT_TO_NATIVE_THREAD_ID (ep_rt_volatile_load_uint64_t ((const uint64_t *)&spin_lock->owning_thread_id)); + else + return spin_lock->owning_thread_id; +} +#endif + static inline void ep_rt_spin_lock_alloc (ep_rt_spin_lock_handle_t *spin_lock) { #ifdef EP_CHECKED_BUILD - spin_lock->lock_is_held = false; + ep_rt_spin_lock_set_owning_thread_id (spin_lock, MONO_UINT_TO_NATIVE_THREAD_ID (0)); #endif spin_lock->lock = g_new0 (MonoCoopMutex, 1); if (spin_lock->lock) @@ -1739,8 +1543,7 @@ ep_rt_spin_lock_aquire (ep_rt_spin_lock_handle_t *spin_lock) if (spin_lock && spin_lock->lock) { mono_coop_mutex_lock (spin_lock->lock); #ifdef EP_CHECKED_BUILD - spin_lock->owning_thread_id = ep_rt_mono_native_thread_id_get (); - spin_lock->lock_is_held = true; + ep_rt_spin_lock_set_owning_thread_id (spin_lock, ep_rt_mono_native_thread_id_get ()); #endif } return true; @@ -1753,8 +1556,7 @@ ep_rt_spin_lock_release (ep_rt_spin_lock_handle_t *spin_lock) { if (spin_lock && spin_lock->lock) { #ifdef EP_CHECKED_BUILD - spin_lock->lock_is_held = false; - spin_lock->owning_thread_id = MONO_UINT_TO_NATIVE_THREAD_ID (0); + ep_rt_spin_lock_set_owning_thread_id (spin_lock, MONO_UINT_TO_NATIVE_THREAD_ID (0)); #endif mono_coop_mutex_unlock (spin_lock->lock); } @@ -1767,7 +1569,7 @@ inline void ep_rt_spin_lock_requires_lock_held (const ep_rt_spin_lock_handle_t *spin_lock) { - g_assert (spin_lock->lock_is_held && ep_rt_mono_native_thread_id_equals (spin_lock->owning_thread_id, ep_rt_mono_native_thread_id_get ())); + g_assert (ep_rt_mono_native_thread_id_equals (ep_rt_spin_lock_get_owning_thread_id (spin_lock), ep_rt_mono_native_thread_id_get ())); } static @@ -1775,7 +1577,7 @@ inline void ep_rt_spin_lock_requires_lock_not_held (const ep_rt_spin_lock_handle_t *spin_lock) { - g_assert (!spin_lock->lock_is_held || (spin_lock->lock_is_held && !ep_rt_mono_native_thread_id_equals (spin_lock->owning_thread_id, ep_rt_mono_native_thread_id_get ()))); + g_assert (!ep_rt_mono_native_thread_id_equals (ep_rt_spin_lock_get_owning_thread_id (spin_lock), ep_rt_mono_native_thread_id_get ())); } #endif @@ -2001,13 +1803,9 @@ inline EventPipeThread * ep_rt_thread_get (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME - extern MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + extern MonoNativeTlsKey _ep_rt_mono_thread_holder_tls_id; + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); return thread_holder ? ep_thread_holder_get_thread (thread_holder) : NULL; -#else - return ep_rt_mono_func_table_get ()->ep_rt_mono_thread_get (); -#endif } static @@ -2016,8 +1814,10 @@ EventPipeThread * ep_rt_thread_get_or_create (void) { EventPipeThread *thread = ep_rt_thread_get (); - if (!thread) - thread = ep_rt_mono_func_table_get ()->ep_rt_mono_thread_get_or_create (); + if (!thread) { + extern EventPipeThread * ep_rt_mono_thread_get_or_create (void); + thread = ep_rt_mono_thread_get_or_create (); + } return thread; } @@ -2114,17 +1914,10 @@ int32_t ep_rt_mono_thread_sleep (uint32_t ms, bool alertable) { gboolean alerted = false; -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME if (alertable) return (int32_t)mono_thread_info_sleep (ms, &alerted); else return (int32_t)mono_thread_info_sleep (ms, NULL); -#else - if (alertable) - return (int32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_thread_info_sleep (ms, &alerted); - else - return (int32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_thread_info_sleep (ms, NULL); -#endif } static @@ -2132,11 +1925,7 @@ inline bool ep_rt_mono_thread_yield (void) { -#ifdef EP_RT_MONO_USE_STATIC_RUNTIME return (mono_thread_info_yield () == TRUE) ? true : false; -#else - return (ep_rt_mono_func_table_get ()->ep_rt_mono_thread_info_yield () == TRUE) ? true : false; -#endif } // See src/coreclr/vm/spinlock.h for details. @@ -2317,5 +2106,12 @@ ep_rt_volatile_store_ptr_without_barrier ( *ptr = value; } +/* + * EventPipe Native Events. + */ + +bool +ep_rt_mono_write_event_ee_startup_start (void); + #endif /* ENABLE_PERFTRACING */ #endif /* __EVENTPIPE_RT_MONO_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt-types-mono.h b/src/mono/mono/eventpipe/ep-rt-types-mono.h index 484ee34d8c3a02..ef248e56af8b1e 100644 --- a/src/mono/mono/eventpipe/ep-rt-types-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-types-mono.h @@ -68,8 +68,7 @@ struct _rt_mono_event_internal_t { struct _rt_mono_lock_internal_t { MonoCoopMutex *lock; #ifdef EP_CHECKED_BUILD - MonoNativeThreadId owning_thread_id; - bool lock_is_held; + volatile MonoNativeThreadId owning_thread_id; #endif }; diff --git a/src/mono/mono/eventpipe/test/CMakeLists.txt b/src/mono/mono/eventpipe/test/CMakeLists.txt index f0f5612ecd07c5..65784b823c4960 100644 --- a/src/mono/mono/eventpipe/test/CMakeLists.txt +++ b/src/mono/mono/eventpipe/test/CMakeLists.txt @@ -1,6 +1,7 @@ if(ENABLE_PERFTRACING) - if(ENABLE_EVENTPIPE_TEST AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) + # TODO: Add support for dynamic components once package/deploy have been resolved. + if(ENABLE_EVENTPIPE_TEST AND STATIC_COMPONENTS AND (NOT DISABLE_COMPONENTS) AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) set(EVENTPIPE_TEST_SOURCES "") set(EVENTPIPE_TEST_HEADERS "") @@ -26,42 +27,19 @@ if(ENABLE_PERFTRACING) ep-tests-debug.h ) - include_directories( - ${PROJECT_SOURCE_DIR}/../../native/ - ${PROJECT_SOURCE_DIR}/.. - ${PROJECT_SOURCE_DIR} - ${PROJECT_SOURCE_DIR}/eglib - ${PROJECT_BINARY_DIR}/.. - ${PROJECT_BINARY_DIR}/eglib - ) - - if(HAVE_SYS_ICU) - if(ICU_LIBDIR) - set(ICU_LDFLAGS "-L${ICU_LIBDIR}") - endif() - endif() - - if(HOST_DARWIN) - set(OS_LIBS "-framework CoreFoundation" "-framework Foundation") - elseif(HOST_IOS) - set(OS_LIBS "-framework CoreFoundation" "-lobjc" "-lc++") - elseif(HOST_ANDROID) - set(OS_LIBS m dl log) - elseif(HOST_LINUX) - set(OS_LIBS pthread m dl) - elseif(HOST_WIN32) - set(OS_LIBS bcrypt.lib ws2_32.lib version.lib winmm.lib) - endif() + addprefix(EVENTPIPE_TEST_SOURCES ${MONO_EVENTPIPE_TEST_SOURCE_PATH} "${EVENTPIPE_TEST_SOURCES}") + addprefix(EVENTPIPE_TEST_HEADERS ${MONO_EVENTPIPE_TEST_SOURCE_PATH} "${EVENTPIPE_TEST_HEADERS}") set(CMAKE_SKIP_RPATH 1) add_executable(ep-test ${EVENTPIPE_TEST_SOURCES} ${EVENTPIPE_TEST_HEADERS}) + target_sources(ep-test PRIVATE "${mono-components-objects}") target_link_libraries(ep-test monosgen-static ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) if(ICU_LDFLAGS) set_target_properties(ep-test PROPERTIES LINK_FLAGS ${ICU_LDFLAGS}) endif() install(TARGETS ep-test RUNTIME) - else(ENABLE_EVENTPIPE_TEST AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) + else(ENABLE_EVENTPIPE_TEST AND STATIC_COMPONENTS AND (NOT DISABLE_COMPONENTS) AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) message(VERBOSE "Skip building native EventPipe library test runner.") - endif(ENABLE_EVENTPIPE_TEST AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) + endif(ENABLE_EVENTPIPE_TEST AND STATIC_COMPONENTS AND (NOT DISABLE_COMPONENTS) AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) endif(ENABLE_PERFTRACING) diff --git a/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c b/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c index 35f38084b0ba68..3a13b05911e8de 100644 --- a/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c +++ b/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c @@ -333,7 +333,7 @@ test_buffer_manager_read_event (void) test_location = 5; - ep_raise_error_if_nok (ep_event_instance_get_thread_id (ep_event_instance) == ep_rt_current_thread_get_id ()); + ep_raise_error_if_nok (ep_event_instance_get_thread_id (ep_event_instance) == ep_rt_thread_id_t_to_uint64_t (ep_rt_current_thread_get_id ())); ep_on_exit: buffer_manager_fini (buffer_manager,thread, session, provider, ep_event); @@ -581,11 +581,12 @@ test_buffer_manager_perf (void) static RESULT test_buffer_manager_teardown (void) { +#ifdef _CRTDBG_MAP_ALLOC // Need to emulate a thread exit to make sure TLS gets cleaned up for current thread // or we will get memory leaks reported. + extern void ep_rt_mono_thread_exited (void); ep_rt_mono_thread_exited (); -#ifdef _CRTDBG_MAP_ALLOC _CrtMemCheckpoint (&eventpipe_memory_end_snapshot); if ( _CrtMemDifference( &eventpipe_memory_diff_snapshot, &eventpipe_memory_start_snapshot, &eventpipe_memory_end_snapshot) ) { _CrtMemDumpStatistics( &eventpipe_memory_diff_snapshot ); diff --git a/src/mono/mono/eventpipe/test/ep-setup-tests.c b/src/mono/mono/eventpipe/test/ep-setup-tests.c index 30743664ac6c7f..6bb24553e7f356 100644 --- a/src/mono/mono/eventpipe/test/ep-setup-tests.c +++ b/src/mono/mono/eventpipe/test/ep-setup-tests.c @@ -12,6 +12,8 @@ test_setup (void) if (core_root) { mono_set_assemblies_path (core_root); g_free (core_root); + } else { + mono_set_assemblies_path ("."); } eventpipe_test_domain = mono_jit_init_version_for_test_only ("eventpipe-tests", "v4.0.30319"); diff --git a/src/mono/mono/eventpipe/test/ep-tests.c b/src/mono/mono/eventpipe/test/ep-tests.c index 34179b61642b8b..b0e7803924551d 100644 --- a/src/mono/mono/eventpipe/test/ep-tests.c +++ b/src/mono/mono/eventpipe/test/ep-tests.c @@ -1256,6 +1256,7 @@ test_eventpipe_mem_checkpoint (void) #ifdef _CRTDBG_MAP_ALLOC // Need to emulate a thread exit to make sure TLS gets cleaned up for current thread // or we will get memory leaks reported. + extern void ep_rt_mono_thread_exited (void); ep_rt_mono_thread_exited (); _CrtMemCheckpoint (&eventpipe_memory_end_snapshot); diff --git a/src/mono/mono/eventpipe/test/ep-thread-tests.c b/src/mono/mono/eventpipe/test/ep-thread-tests.c index 1ffe239b47c3dd..2eb85ff976c2da 100644 --- a/src/mono/mono/eventpipe/test/ep-thread-tests.c +++ b/src/mono/mono/eventpipe/test/ep-thread-tests.c @@ -128,6 +128,7 @@ test_get_or_create_thread (void) // Need to emulate a thread exit to make sure TLS gets cleaned up for current thread // or we will get memory leaks reported. + extern void ep_rt_mono_thread_exited (void); ep_rt_mono_thread_exited (); thread = ep_thread_get (); @@ -199,6 +200,7 @@ test_thread_activity_id (void) // Need to emulate a thread exit to make sure TLS gets cleaned up for current thread // or we will get memory leaks reported. + extern void ep_rt_mono_thread_exited (void); ep_rt_mono_thread_exited (); thread = ep_thread_get (); diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 4b56d07c440560..1b7ba75f6b0e44 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -71,6 +71,8 @@ set(metadata_common_sources class-setup-vtable.c cominterop.c cominterop.h + components.h + components.c coree.c coree.h coree-internals.h diff --git a/src/mono/mono/metadata/appdomain.c b/src/mono/mono/metadata/appdomain.c index 6426bc8729a168..9626f3a91e57c3 100644 --- a/src/mono/mono/metadata/appdomain.c +++ b/src/mono/mono/metadata/appdomain.c @@ -69,10 +69,7 @@ #include #include #include - -#ifdef ENABLE_PERFTRACING -#include -#endif +#include #ifdef HOST_WIN32 #include @@ -281,10 +278,10 @@ mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoT mono_thread_internal_attach (domain); -#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) - ds_server_init (); - ds_server_pause_for_diagnostics_monitor (); -#endif + mono_component_diagnostics_server ()->init (); + mono_component_diagnostics_server ()->pause_for_diagnostics_monitor (); + + mono_component_event_pipe ()->write_event_ee_startup_start (); mono_type_initialization_init (); diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 233e4ecc9b655e..2889d03722304e 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -16,6 +16,7 @@ #include "mono/sgen/gc-internal-agnostic.h" #include "mono/utils/mono-error-internals.h" #include "mono/utils/mono-memory-model.h" +#include "mono/utils/mono-compiler.h" #define MONO_CLASS_IS_ARRAY(c) (m_class_get_rank (c)) @@ -1126,6 +1127,7 @@ mono_identifier_escape_type_name_chars (const char* identifier); char* mono_type_get_full_name (MonoClass *klass); +MONO_COMPONENT_API char * mono_method_get_name_full (MonoMethod *method, gboolean signature, gboolean ret, MonoTypeNameFormat format); diff --git a/src/mono/mono/metadata/components.c b/src/mono/mono/metadata/components.c new file mode 100644 index 00000000000000..6301566d6c45bb --- /dev/null +++ b/src/mono/mono/metadata/components.c @@ -0,0 +1,194 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#include +#include +#include +#include "mono/component/component.h" +#include "mono/component/hot_reload.h" +#include "mono/component/event_pipe.h" +#include "mono/component/diagnostics_server.h" +#include "mono/metadata/class-internals.h" +#include "mono/metadata/components.h" +#include "mono/utils/mono-dl.h" +#include "mono/utils/mono-logger-internals.h" +#include "mono/utils/mono-path.h" + +typedef MonoComponent * (*MonoComponentInitFn) (void); + +typedef struct _MonoComponentEntry { + const char *lib_name; + const char *name; + MonoComponentInitFn init; + MonoComponent **component; + MonoDl *lib; +} MonoComponentEntry; + +#ifdef STATIC_COMPONENTS +#define COMPONENT_INIT_FUNC(name) (MonoComponentInitFn) mono_component_ ## name ## _init +#else +#define COMPONENT_INIT_FUNC(name) (MonoComponentInitFn) mono_component_ ## name ## _stub_init +#endif + +#define HOT_RELOAD_LIBRARY_NAME "hot_reload" +#define HOT_RELOAD_COMPONENT_NAME HOT_RELOAD_LIBRARY_NAME +MonoComponentHotReload *hot_reload = NULL; + +MonoComponentEventPipe *event_pipe = NULL; +MonoComponentDiagnosticsServer *diagnostics_server = NULL; + +// DiagnosticsServer/EventPipe components currently hosted by diagnostics_tracing library. +#define DIAGNOSTICS_TRACING_LIBRARY_NAME "diagnostics_tracing" +#define EVENT_PIPE_COMPONENT_NAME "event_pipe" +#define DIAGNOSTICS_SERVER_COMPONENT_NAME "diagnostics_server" + +/* One per component */ +MonoComponentEntry components[] = { + { HOT_RELOAD_LIBRARY_NAME, HOT_RELOAD_COMPONENT_NAME, COMPONENT_INIT_FUNC (hot_reload), (MonoComponent**)&hot_reload, NULL }, + { DIAGNOSTICS_TRACING_LIBRARY_NAME, EVENT_PIPE_COMPONENT_NAME, COMPONENT_INIT_FUNC (event_pipe), (MonoComponent**)&event_pipe, NULL }, + { DIAGNOSTICS_TRACING_LIBRARY_NAME, DIAGNOSTICS_SERVER_COMPONENT_NAME, COMPONENT_INIT_FUNC (diagnostics_server), (MonoComponent**)&diagnostics_server, NULL }, +}; + +#ifndef STATIC_COMPONENTS +static MonoComponent* +get_component (const MonoComponentEntry *component, MonoDl **component_lib); +#endif + +void +mono_components_init (void) +{ +#ifdef STATIC_COMPONENTS + /* directly call each components init function */ + /* TODO: support disabled components. + * + * The issue here is that we need to do static linking, so if we don't + * directly reference mono_component__init anywhere (ie + * if we dlsym from RTLD_DEFAULT) the static linking of the final + * binary won't actually include that symbol (unless we play + * platform-specific linker tricks). + * + * So maybe we will need some API hook so that embedders need to call + * to pass us the address of each component that isn't disabled. + * + */ + for (int i = 0; i < G_N_ELEMENTS (components); ++i) + *components [i].component = components [i].init (); +#else + /* call get_component for each component and init it or its stubs and add it to loaded_components */ + MonoDl *lib = NULL; + + for (int i = 0; i < G_N_ELEMENTS (components); ++i) { + *components [i].component = get_component (&components [i], &lib); + components [i].lib = lib; + if (!*components [i].component) + *components [i].component = components [i].init (); + } +#endif + /* validate components interface version */ + for (int i = 0; i < G_N_ELEMENTS (components); ++i) { + guint64 version = (guint64)(*components [i].component)->itf_version; + g_assertf (version == MONO_COMPONENT_ITF_VERSION, "%s component returned unexpected interface version (expected %" PRIu64 " got %" PRIu64 ")", components [i].name, (guint64)MONO_COMPONENT_ITF_VERSION, version); + } +} + +static char* +component_init_name (const MonoComponentEntry *component) +{ + return g_strdup_printf ("mono_component_%s_init", component->name); +} + +static gpointer +load_component_entrypoint (MonoDl *lib, const MonoComponentEntry *component) +{ + char *component_init = component_init_name (component); + gpointer sym = NULL; + char *error_msg = mono_dl_symbol (lib, component_init, &sym); + if (error_msg) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Component %s library does not have symbol %s: %s", component->name, component_init, error_msg); + g_free (error_msg); + g_free (component_init); + return NULL; + } + g_free (component_init); + return sym; +} + +#ifndef STATIC_COMPONENTS +static char* +component_library_base_name (const MonoComponentEntry *component) +{ + return g_strdup_printf ("mono-component-%s", component->lib_name); +} + +static char * +components_dir (void) +{ + static char *dir = NULL; + if (!dir) { + char buf[4096]; + if (g_module_address ((void *)components_dir, buf, sizeof (buf), NULL, NULL, 0, NULL)) { + char *resolvedname = mono_path_resolve_symlinks (buf); + dir = g_path_get_dirname (resolvedname); + g_free (resolvedname); + } + } + return dir; +} + +static MonoDl* +try_load (const char* dir, const MonoComponentEntry *component, const char* component_base_lib) +{ + MonoDl *lib = NULL; + void *iter = NULL; + char *path = NULL; + while ((path = mono_dl_build_path (dir, component_base_lib, &iter)) && !lib) { + char *error_msg = NULL; + lib = mono_dl_open (path, MONO_DL_EAGER, &error_msg); + if (!lib) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Component %s not found: %s", component->name, error_msg); + g_free (error_msg); + continue; + } + } + if (lib) + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Component %s found at %s", component->name, path); + g_free (path); + return lib; +} + +static MonoComponentInitFn +load_component (const MonoComponentEntry *component, MonoDl **lib_out) +{ + char *component_base_lib = component_library_base_name (component); + MonoComponentInitFn result = NULL; + + /* FIXME: just copy what mono_profiler_load does, assuming it works */ + + /* FIXME: do I need to provide a path? */ + MonoDl *lib = NULL; + lib = try_load (components_dir (), component, component_base_lib); + if (!lib) + lib = try_load (NULL, component, component_base_lib); + + g_free (component_base_lib); + if (!lib) + goto done; + + gpointer sym = load_component_entrypoint (lib, component); + + result = (MonoComponentInitFn)sym; + *lib_out = lib; +done: + return result; +} + +MonoComponent* +get_component (const MonoComponentEntry *component, MonoDl **lib_out) +{ + MonoComponentInitFn initfn = load_component (component, lib_out); + if (!initfn) + return NULL; + return initfn(); +} +#endif diff --git a/src/mono/mono/metadata/components.h b/src/mono/mono/metadata/components.h new file mode 100644 index 00000000000000..2fd82eaf97e398 --- /dev/null +++ b/src/mono/mono/metadata/components.h @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#ifndef _MONO_METADATA_COMPONENTS_H +#define _MONO_METADATA_COMPONENTS_H + +#include +#include +#include +#include + +void +mono_components_init (void); + +/* Declare each component's getter function here */ +static inline +MonoComponentHotReload * +mono_component_hot_reload (void) +{ + extern MonoComponentHotReload *hot_reload; + return hot_reload; +} + +static inline +MonoComponentEventPipe * +mono_component_event_pipe (void) +{ + extern MonoComponentEventPipe *event_pipe; + return event_pipe; +} + +static inline +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server (void) +{ + extern MonoComponentDiagnosticsServer *diagnostics_server; + return diagnostics_server; +} + +/* Declare each copomnents stub init function here */ +MonoComponentHotReload * +mono_component_hot_reload_stub_init (void); + +MonoComponentEventPipe * +mono_component_event_pipe_stub_init (void); + +MonoComponentDiagnosticsServer * +mono_component_diagnostics_server_stub_init (void); + +#endif/*_MONO_METADATA_COMPONENTS_H*/ diff --git a/src/mono/mono/metadata/environment-internals.h b/src/mono/mono/metadata/environment-internals.h index cfd13afc4d53b6..510f4222c90ede 100644 --- a/src/mono/mono/metadata/environment-internals.h +++ b/src/mono/mono/metadata/environment-internals.h @@ -7,10 +7,12 @@ #ifndef _MONO_METADATA_ENVIRONMENT_INTERNALS_H_ #define _MONO_METADATA_ENVIRONMENT_INTERNALS_H_ +#include + void mono_set_os_args (int argc, char **argv); -char * +MONO_COMPONENT_API char * mono_get_os_cmd_line (void); #endif /* _MONO_METADATA_ENVIRONMENT_INTERNALS_H_ */ diff --git a/src/mono/mono/metadata/gc-internals.h b/src/mono/mono/metadata/gc-internals.h index f52deb7dbda4d8..34203f25357957 100644 --- a/src/mono/mono/metadata/gc-internals.h +++ b/src/mono/mono/metadata/gc-internals.h @@ -18,6 +18,7 @@ #include #include #include +#include /* Register a memory area as a conservatively scanned GC root */ #define MONO_GC_REGISTER_ROOT_PINNING(x,src,key,msg) mono_gc_register_root ((char*)&(x), sizeof(x), MONO_GC_DESCRIPTOR_NULL, (src), (key), (msg)) @@ -426,7 +427,7 @@ extern gchar **mono_do_not_finalize_class_names; * Unified runtime stop/restart world, SGEN Only. * Will take and release the LOCK_GC. */ -void mono_stop_world (MonoThreadInfoFlags flags); -void mono_restart_world (MonoThreadInfoFlags flags); +MONO_COMPONENT_API void mono_stop_world (MonoThreadInfoFlags flags); +MONO_COMPONENT_API void mono_restart_world (MonoThreadInfoFlags flags); #endif /* __MONO_METADATA_GC_INTERNAL_H__ */ diff --git a/src/mono/mono/metadata/icall-eventpipe.c b/src/mono/mono/metadata/icall-eventpipe.c index c8ab05a558af30..53755c6b2f0277 100644 --- a/src/mono/mono/metadata/icall-eventpipe.c +++ b/src/mono/mono/metadata/icall-eventpipe.c @@ -1,206 +1,15 @@ #include #include #include - #include #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Rundown flags. -#define METHOD_FLAGS_DYNAMIC_METHOD 0x1 -#define METHOD_FLAGS_GENERIC_METHOD 0x2 -#define METHOD_FLAGS_SHARED_GENERIC_METHOD 0x4 -#define METHOD_FLAGS_JITTED_METHOD 0x8 -#define METHOD_FLAGS_JITTED_HELPER_METHOD 0x10 - -#define MODULE_FLAGS_NATIVE_MODULE 0x2 -#define MODULE_FLAGS_DYNAMIC_MODULE 0x4 -#define MODULE_FLAGS_MANIFEST_MODULE 0x8 - -#define ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY 0x2 -#define ASSEMBLY_FLAGS_NATIVE_ASSEMBLY 0x4 -#define ASSEMBLY_FLAGS_COLLECTIBLE_ASSEMBLY 0x8 - -#define DOMAIN_FLAGS_DEFAULT_DOMAIN 0x1 -#define DOMAIN_FLAGS_EXECUTABLE_DOMAIN 0x2 - -typedef enum _EventPipeActivityControlCode { - EP_ACTIVITY_CONTROL_GET_ID = 1, - EP_ACTIVITY_CONTROL_SET_ID = 2, - EP_ACTIVITY_CONTROL_CREATE_ID = 3, - EP_ACTIVITY_CONTROL_GET_SET_ID = 4, - EP_ACTIVITY_CONTROL_CREATE_SET_ID = 5 -} EventPipeActivityControlCode; - -typedef struct _EventPipeProviderConfigurationNative { - gunichar2 *provider_name; - uint64_t keywords; - uint32_t logging_level; - gunichar2 *filter_data; -} EventPipeProviderConfigurationNative; - -typedef struct _EventPipeSessionInfo { - int64_t starttime_as_utc_filetime; - int64_t start_timestamp; - int64_t timestamp_frequency; -} EventPipeSessionInfo; - -typedef struct _EventPipeEventInstanceData { - intptr_t provider_id; - uint32_t event_id; - uint32_t thread_id; - int64_t timestamp; - uint8_t activity_id [EP_ACTIVITY_ID_SIZE]; - uint8_t related_activity_id [EP_ACTIVITY_ID_SIZE]; - const uint8_t *payload; - uint32_t payload_len; -} EventPipeEventInstanceData; - -typedef struct _EventPipeFireMethodEventsData{ - MonoDomain *domain; - uint8_t *buffer; - size_t buffer_size; - ep_rt_mono_fire_method_rundown_events_func method_events_func; -} EventPipeFireMethodEventsData; - -typedef struct _EventPipeSampleProfileData { - EventPipeStackContents stack_contents; - uint64_t thread_id; - uintptr_t thread_ip; - uint32_t payload_data; -} EventPipeSampleProfileData; - -gboolean ep_rt_mono_initialized; -MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; -gpointer ep_rt_mono_rand_provider; - -static ep_rt_thread_holder_alloc_func thread_holder_alloc_callback_func; -static ep_rt_thread_holder_free_func thread_holder_free_callback_func; - -static GArray * _ep_rt_mono_sampled_thread_callstacks = NULL; -static uint32_t _ep_rt_mono_max_sampled_thread_count = 32; +#include /* * Forward declares of all static functions. */ -static -gboolean -rand_try_get_bytes_func ( - guchar *buffer, - gssize buffer_size, - MonoError *error); - -static -EventPipeThread * -eventpipe_thread_get (void); - -static -EventPipeThread * -eventpipe_thread_get_or_create (void); - -static -void -eventpipe_thread_exited (void); - -static -void -profiler_eventpipe_thread_exited ( - MonoProfiler *prof, - uintptr_t tid); - -static -gpointer -eventpipe_thread_attach (gboolean background_thread); - -static -void -eventpipe_thread_detach (void); - -static -void -eventpipe_fire_method_events ( - MonoJitInfo *ji, - MonoMethod *method, - EventPipeFireMethodEventsData *events_data); - -static -void -eventpipe_fire_method_events_func ( - MonoJitInfo *ji, - gpointer user_data); - -static -void -eventpipe_fire_assembly_events ( - MonoDomain *domain, - MonoAssembly *assembly, - ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func); - -static -gboolean -eventpipe_execute_rundown ( - ep_rt_mono_fire_domain_rundown_events_func domain_events_func, - ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, - ep_rt_mono_fire_method_rundown_events_func methods_events_func); - -static -gboolean -eventpipe_walk_managed_stack_for_thread_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - gpointer data); - -static -gboolean -eventpipe_walk_managed_stack_for_thread ( - ep_rt_thread_handle_t thread, - EventPipeStackContents *stack_contents); - -static -gboolean -eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - gpointer data); - -static -gboolean -eventpipe_sample_profiler_write_sampling_event_for_threads ( - ep_rt_thread_handle_t sampling_thread, - EventPipeEvent *sampling_event); - -static -gboolean -eventpipe_method_get_simple_assembly_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len); - -static -gboolean -evetpipe_method_get_full_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len); - static void delegate_callback_data_free_func ( @@ -218,578 +27,6 @@ delegate_callback_func ( EventFilterDescriptor *filter_data, void *callback_context); -static -gboolean -rand_try_get_bytes_func ( - guchar *buffer, - gssize buffer_size, - MonoError *error) -{ - g_assert (ep_rt_mono_rand_provider != NULL); - return mono_rand_try_get_bytes (&ep_rt_mono_rand_provider, buffer, buffer_size, error); -} - -static -EventPipeThread * -eventpipe_thread_get (void) -{ - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); - return thread_holder ? ep_thread_holder_get_thread (thread_holder) : NULL; -} - -static -EventPipeThread * -eventpipe_thread_get_or_create (void) -{ - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); - if (!thread_holder && thread_holder_alloc_callback_func) { - thread_holder = thread_holder_alloc_callback_func (); - mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, thread_holder); - } - return ep_thread_holder_get_thread (thread_holder); -} - -static -void -eventpipe_thread_exited (void) -{ - if (ep_rt_mono_initialized) { - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); - if (thread_holder && thread_holder_free_callback_func) - thread_holder_free_callback_func (thread_holder); - mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, NULL); - } -} - -static -void -profiler_eventpipe_thread_exited ( - MonoProfiler *prof, - uintptr_t tid) -{ - eventpipe_thread_exited (); -} - -static -gpointer -eventpipe_thread_attach (gboolean background_thread) -{ - MonoThread *thread = NULL; - - // NOTE, under netcore, only root domain exists. - if (!mono_thread_current ()) { - thread = mono_thread_internal_attach (mono_get_root_domain ()); - if (background_thread && thread) { - mono_thread_set_state (thread, ThreadState_Background); - mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE); - } - } - - return thread; -} - -static -void -eventpipe_thread_detach (void) -{ - MonoThread *current_thread = mono_thread_current (); - if (current_thread) - mono_thread_internal_detach (current_thread); -} - -static -void -eventpipe_fire_method_events ( - MonoJitInfo *ji, - MonoMethod *method, - EventPipeFireMethodEventsData *events_data) -{ - g_assert_checked (ji != NULL); - g_assert_checked (events_data->domain != NULL); - g_assert_checked (events_data->method_events_func != NULL); - - uint64_t method_id = 0; - uint64_t module_id = 0; - uint64_t method_code_start = (uint64_t)ji->code_start; - uint32_t method_code_size = (uint32_t)ji->code_size; - uint32_t method_token = 0; - uint32_t method_flags = 0; - uint8_t kind = MONO_CLASS_DEF; - char *method_namespace = NULL; - const char *method_name = NULL; - char *method_signature = NULL; - - //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. - - if (method) { - method_id = (uint64_t)method; - method_token = method->token; - - if (mono_jit_info_get_generic_sharing_context (ji)) - method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; - - if (method->dynamic) - method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; - - if (!ji->from_aot && !ji->from_llvm) { - method_flags |= METHOD_FLAGS_JITTED_METHOD; - if (method->wrapper_type != MONO_WRAPPER_NONE) - method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; - } - - if (method->is_generic || method->is_inflated) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - - method_name = method->name; - method_signature = mono_signature_full_name (method->signature); - - if (method->klass) { - module_id = (uint64_t)m_class_get_image (method->klass); - kind = m_class_get_class_kind (method->klass); - if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); - } - } - - uint16_t offset_entries = 0; - uint32_t *il_offsets = NULL; - uint32_t *native_offsets = NULL; - - MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL; - if (debug_info) { - offset_entries = debug_info->num_line_numbers; - size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); - if (!events_data->buffer || needed_size > events_data->buffer_size) { - g_free (events_data->buffer); - events_data->buffer_size = (size_t)(needed_size * 1.5); - events_data->buffer = g_new (uint8_t, events_data->buffer_size); - } - - if (events_data->buffer) { - il_offsets = (uint32_t*)events_data->buffer; - native_offsets = il_offsets + offset_entries; - - for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { - il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; - native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; - } - } - - mono_debug_free_method_jit_info (debug_info); - } - - if (events_data->buffer && !il_offsets && !native_offsets) { - // No IL offset -> Native offset mapping available. Put all code on IL offset 0. - g_assert_checked (events_data->buffer_size >= sizeof (uint32_t) * 2); - offset_entries = 1; - il_offsets = (uint32_t*)events_data->buffer; - native_offsets = il_offsets + offset_entries; - il_offsets [0] = 0; - native_offsets [0] = (uint32_t)ji->code_size; - } - - events_data->method_events_func ( - method_id, - module_id, - method_code_start, - method_code_size, - method_token, - method_flags, - (ep_char8_t *)method_namespace, - (ep_char8_t *)method_name, - (ep_char8_t *)method_signature, - offset_entries, - il_offsets, - native_offsets, - NULL); - - g_free (method_namespace); - g_free (method_signature); -} - -static -void -eventpipe_fire_method_events_func ( - MonoJitInfo *ji, - gpointer user_data) -{ - EventPipeFireMethodEventsData *events_data = (EventPipeFireMethodEventsData *)user_data; - g_assert_checked (events_data != NULL); - - if (ji && !ji->is_trampoline && !ji->async) { - MonoMethod *method = jinfo_get_method (ji); - if (method && !m_method_is_wrapper (method)) - eventpipe_fire_method_events (ji, method, events_data); - } -} - -static -void -eventpipe_fire_assembly_events ( - MonoDomain *domain, - MonoAssembly *assembly, - ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func) -{ - g_assert_checked (domain != NULL); - g_assert_checked (assembly != NULL); - g_assert_checked (assembly_events_func != NULL); - - uint64_t domain_id = (uint64_t)domain; - uint64_t module_id = (uint64_t)assembly->image; - uint64_t assembly_id = (uint64_t)assembly; - - // TODO: Extract all module IL/Native paths and pdb metadata when available. - const char *module_il_path = ""; - const char *module_il_pdb_path = ""; - const char *module_native_path = ""; - const char *module_native_pdb_path = ""; - uint8_t signature [EP_GUID_SIZE] = { 0 }; - uint32_t module_il_pdb_age = 0; - uint32_t module_native_pdb_age = 0; - - uint32_t reserved_flags = 0; - uint64_t binding_id = 0; - - // Native methods are part of JIT table and already emitted. - // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? - - // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. - uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; - if (assembly->image) { - if (assembly->image->dynamic) - module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; - if (assembly->image->aot_module) - module_flags |= MODULE_FLAGS_NATIVE_MODULE; - - module_il_path = assembly->image->filename ? assembly->image->filename : ""; - } - - uint32_t assembly_flags = 0; - if (assembly->dynamic) - assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; - - if (assembly->image && assembly->image->aot_module) { - assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; - } - - char *assembly_name = mono_stringify_assembly_name (&assembly->aname); - - assembly_events_func ( - domain_id, - assembly_id, - assembly_flags, - binding_id, - (const ep_char8_t*)assembly_name, - module_id, - module_flags, - reserved_flags, - (const ep_char8_t *)module_il_path, - (const ep_char8_t *)module_native_path, - signature, - module_il_pdb_age, - (const ep_char8_t *)module_il_pdb_path, - signature, - module_native_pdb_age, - (const ep_char8_t *)module_native_pdb_path, - NULL); - - g_free (assembly_name); -} - -static -gboolean -eventpipe_execute_rundown ( - ep_rt_mono_fire_domain_rundown_events_func domain_events_func, - ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, - ep_rt_mono_fire_method_rundown_events_func method_events_func) -{ - g_assert_checked (domain_events_func != NULL); - g_assert_checked (assembly_events_func != NULL); - g_assert_checked (method_events_func != NULL); - - // Under netcore we only have root domain. - MonoDomain *root_domain = mono_get_root_domain (); - if (root_domain) { - uint64_t domain_id = (uint64_t)root_domain; - - // Iterate all functions in use (both JIT and AOT). - EventPipeFireMethodEventsData events_data; - events_data.domain = root_domain; - events_data.buffer_size = 1024 * sizeof(uint32_t); - events_data.buffer = g_new (uint8_t, events_data.buffer_size); - events_data.method_events_func = method_events_func; - mono_jit_info_table_foreach_internal (eventpipe_fire_method_events_func, &events_data); - g_free (events_data.buffer); - - // Iterate all assemblies in domain. - GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies (); - if (assemblies) { - for (int i = 0; i < assemblies->len; ++i) { - MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); - if (assembly) - eventpipe_fire_assembly_events (root_domain, assembly, assembly_events_func); - } - g_ptr_array_free (assemblies, TRUE); - } - - uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; - const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : ""; - uint32_t domain_index = 1; - - domain_events_func ( - domain_id, - domain_flags, - (const ep_char8_t *)domain_name, - domain_index, - NULL); - } - - return TRUE; -} - -static -gboolean -eventpipe_walk_managed_stack_for_thread_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - gpointer data) -{ - g_assert_checked (frame != NULL); - g_assert_checked (data != NULL); - - switch (frame->type) { - case FRAME_TYPE_DEBUGGER_INVOKE: - case FRAME_TYPE_MANAGED_TO_NATIVE: - case FRAME_TYPE_TRAMPOLINE: - case FRAME_TYPE_INTERP_TO_MANAGED: - case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX: - return FALSE; - case FRAME_TYPE_MANAGED: - case FRAME_TYPE_INTERP: - if (!frame->ji) - return FALSE; - MonoMethod *method = frame->ji->async ? NULL : frame->actual_method; - if (method && !m_method_is_wrapper (method)) - ep_stack_contents_append ((EventPipeStackContents *)data, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method); - return ep_stack_contents_get_length ((EventPipeStackContents *)data) >= EP_MAX_STACK_DEPTH; - default: - g_assert_not_reached (); - return FALSE; - } -} - -static -gboolean -eventpipe_walk_managed_stack_for_thread ( - ep_rt_thread_handle_t thread, - EventPipeStackContents *stack_contents) -{ - g_assert (thread != NULL && stack_contents != NULL); - - if (thread == ep_rt_thread_get_handle ()) - mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (eventpipe_walk_managed_stack_for_thread_func, NULL, MONO_UNWIND_SIGNAL_SAFE, stack_contents); - else - mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_walk_managed_stack_for_thread_func, mono_thread_info_get_suspend_state (thread), MONO_UNWIND_SIGNAL_SAFE, stack_contents); - - return TRUE; -} - -static -gboolean -eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - gpointer data) -{ - g_assert_checked (frame != NULL); - g_assert_checked (data != NULL); - - EventPipeSampleProfileData *sample_data = (EventPipeSampleProfileData *)data; - - if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) { - if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; - else - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; - } - - return eventpipe_walk_managed_stack_for_thread_func (frame, ctx, &sample_data->stack_contents); -} - -static -gboolean -eventpipe_sample_profiler_write_sampling_event_for_threads ( - ep_rt_thread_handle_t sampling_thread, - EventPipeEvent *sampling_event) -{ - // Follows CoreClr implementation of sample profiler. Generic invasive/expensive way to do CPU sample profiling relying on STW and stackwalks. - // TODO: Investigate alternatives on platforms supporting Signals/SuspendThread (see Mono profiler) or CPU PMU's (see ETW/perf_event_open). - - // Sample profiler only runs on one thread, no need to synchorinize. - if (!_ep_rt_mono_sampled_thread_callstacks) - _ep_rt_mono_sampled_thread_callstacks = g_array_sized_new (FALSE, FALSE, sizeof (EventPipeSampleProfileData), _ep_rt_mono_max_sampled_thread_count); - - // Make sure there is room based on previous max number of sampled threads. - // NOTE, there is a chance there are more threads than max, if that's the case we will - // miss those threads in this sample, but will be included in next when max has been adjusted. - g_array_set_size (_ep_rt_mono_sampled_thread_callstacks, _ep_rt_mono_max_sampled_thread_count); - - uint32_t filtered_thread_count = 0; - uint32_t sampled_thread_count = 0; - - mono_stop_world (MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE); - - // Record all info needed in sample events while runtime is suspended, must be async safe. - FOREACH_THREAD_SAFE_EXCLUDE (thread_info, MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE) { - if (!mono_thread_info_is_running (thread_info)) { - MonoThreadUnwindState *thread_state = mono_thread_info_get_suspend_state (thread_info); - if (thread_state->valid) { - if (sampled_thread_count < _ep_rt_mono_max_sampled_thread_count) { - EventPipeSampleProfileData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileData, sampled_thread_count); - data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info)); - data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx); - data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR; - ep_stack_contents_reset (&data->stack_contents); - mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_sample_profiler_walk_managed_stack_for_thread_func, thread_state, MONO_UNWIND_SIGNAL_SAFE, data); - sampled_thread_count++; - } - } - } - filtered_thread_count++; - } FOREACH_THREAD_SAFE_END - - mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE); - - // Fire sample event for threads. Must be done after runtime is resumed since it's not async safe. - // Since we can't keep thread info around after runtime as been suspended, use an empty - // adapter instance and only set recorded tid as parameter inside adapter. - THREAD_INFO_TYPE adapter = { 0 }; - for (uint32_t i = 0; i < sampled_thread_count; ++i) { - EventPipeSampleProfileData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileData, i); - if (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length(&data->stack_contents) > 0) { - mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id)); - ep_write_sample_profile_event (sampling_thread, sampling_event, &adapter, &data->stack_contents, (uint8_t *)&data->payload_data, sizeof (data->payload_data)); - } - } - - // Current thread count will be our next maximum sampled threads. - _ep_rt_mono_max_sampled_thread_count = filtered_thread_count; - - return TRUE; -} - -static -gboolean -eventpipe_method_get_simple_assembly_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len) -{ - g_assert_checked (method != NULL); - g_assert_checked (name != NULL); - - MonoClass *method_class = mono_method_get_class (method); - MonoImage *method_image = method_class ? mono_class_get_image (method_class) : NULL; - const ep_char8_t *assembly_name = method_image ? mono_image_get_name (method_image) : NULL; - - if (!assembly_name) - return FALSE; - - g_strlcpy (name, assembly_name, name_len); - return TRUE; -} - -static -gboolean -evetpipe_method_get_full_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len) -{ - g_assert_checked (method != NULL); - g_assert_checked (name != NULL); - - char *full_method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL); - if (!full_method_name) - return FALSE; - - g_strlcpy (name, full_method_name, name_len); - - g_free (full_method_name); - return TRUE; -} - -void -mono_eventpipe_init ( - EventPipeMonoFuncTable *table, - ep_rt_thread_holder_alloc_func thread_holder_alloc_func, - ep_rt_thread_holder_free_func thread_holder_free_func) -{ - if (table != NULL) { - table->ep_rt_mono_cpu_count = mono_cpu_count; - table->ep_rt_mono_process_current_pid = mono_process_current_pid; - table->ep_rt_mono_native_thread_id_get = mono_native_thread_id_get; - table->ep_rt_mono_native_thread_id_equals = mono_native_thread_id_equals; - table->ep_rt_mono_runtime_is_shutting_down = mono_runtime_is_shutting_down; - table->ep_rt_mono_rand_try_get_bytes = rand_try_get_bytes_func; - table->ep_rt_mono_thread_get = eventpipe_thread_get; - table->ep_rt_mono_thread_get_or_create = eventpipe_thread_get_or_create; - table->ep_rt_mono_thread_exited = eventpipe_thread_exited; - table->ep_rt_mono_thread_info_sleep = mono_thread_info_sleep; - table->ep_rt_mono_thread_info_yield = mono_thread_info_yield; - table->ep_rt_mono_w32file_close = mono_w32file_close; - table->ep_rt_mono_w32file_create = mono_w32file_create; - table->ep_rt_mono_w32file_write = mono_w32file_write; - table->ep_rt_mono_w32event_create = mono_w32event_create; - table->ep_rt_mono_w32event_close = mono_w32event_close; - table->ep_rt_mono_w32event_set = mono_w32event_set; - table->ep_rt_mono_w32hadle_wait_one = mono_w32handle_wait_one; - table->ep_rt_mono_valloc = mono_valloc; - table->ep_rt_mono_vfree = mono_vfree; - table->ep_rt_mono_valloc_granule = mono_valloc_granule; - table->ep_rt_mono_thread_platform_create_thread = mono_thread_platform_create_thread; - table->ep_rt_mono_thread_attach = eventpipe_thread_attach; - table->ep_rt_mono_thread_detach = eventpipe_thread_detach; - table->ep_rt_mono_get_os_cmd_line = mono_get_os_cmd_line; - table->ep_rt_mono_get_managed_cmd_line = mono_runtime_get_managed_cmd_line; - table->ep_rt_mono_execute_rundown = eventpipe_execute_rundown; - table->ep_rt_mono_walk_managed_stack_for_thread = eventpipe_walk_managed_stack_for_thread; - table->ep_rt_mono_sample_profiler_write_sampling_event_for_threads = eventpipe_sample_profiler_write_sampling_event_for_threads; - table->ep_rt_mono_method_get_simple_assembly_name = eventpipe_method_get_simple_assembly_name; - table->ep_rt_mono_method_get_full_name = evetpipe_method_get_full_name; - } - - thread_holder_alloc_callback_func = thread_holder_alloc_func; - thread_holder_free_callback_func = thread_holder_free_func; - mono_native_tls_alloc (&ep_rt_mono_thread_holder_tls_id, NULL); - - mono_100ns_ticks (); - mono_rand_open (); - ep_rt_mono_rand_provider = mono_rand_init (NULL, 0); - - ep_rt_mono_initialized = TRUE; - - MonoProfilerHandle profiler = mono_profiler_create (NULL); - mono_profiler_set_thread_stopped_callback (profiler, profiler_eventpipe_thread_exited); -} - -void -mono_eventpipe_fini (void) -{ - if (_ep_rt_mono_sampled_thread_callstacks) - g_array_free (_ep_rt_mono_sampled_thread_callstacks, TRUE); - - if (ep_rt_mono_initialized) - mono_rand_close (ep_rt_mono_rand_provider); - - _ep_rt_mono_sampled_thread_callstacks = NULL; - ep_rt_mono_rand_provider = NULL; - thread_holder_alloc_callback_func = NULL; - thread_holder_free_callback_func = NULL; - ep_rt_mono_initialized = FALSE; -} - static void delegate_callback_data_free_func ( @@ -857,11 +94,11 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider ( char *provider_name_utf8 = mono_string_handle_to_utf8 (provider_name, error); if (is_ok (error) && provider_name_utf8) { - provider = ep_create_provider (provider_name_utf8, delegate_callback_func, delegate_callback_data_free_func, callback_data); + provider = mono_component_event_pipe ()->create_provider (provider_name_utf8, delegate_callback_func, delegate_callback_data_free_func, callback_data); } g_free (provider_name_utf8); - return provider; + return (gconstpointer)provider; } intptr_t @@ -877,7 +114,7 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DefineEvent ( g_assert (provider_handle != 0); EventPipeProvider *provider = (EventPipeProvider *)provider_handle; - EventPipeEvent *ep_event = ep_provider_add_event (provider, event_id, (uint64_t)keywords, event_version, (EventPipeEventLevel)level, /* needStack = */ true, metadata, metadata_len); + EventPipeEvent *ep_event = mono_component_event_pipe ()->provider_add_event (provider, event_id, (uint64_t)keywords, event_version, (EventPipeEventLevel)level, /* needStack = */ true, metadata, metadata_len); g_assert (ep_event != NULL); return (intptr_t)ep_event; @@ -886,15 +123,14 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DefineEvent ( void ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DeleteProvider (intptr_t provider_handle) { - if (provider_handle) { - ep_delete_provider ((EventPipeProvider *)provider_handle); - } + if (provider_handle) + mono_component_event_pipe ()->delete_provider ((EventPipeProvider *)provider_handle); } void ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Disable (uint64_t session_id) { - ep_disable (session_id); + mono_component_event_pipe ()->disable (session_id); } uint64_t @@ -915,42 +151,21 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Enable ( if (output_file) output_file_utf8 = mono_utf16_to_utf8 (output_file, g_utf16_len (output_file), error); - EventPipeProviderConfigurationNative *native_config_providers = (EventPipeProviderConfigurationNative *)providers; - EventPipeProviderConfiguration *config_providers = g_new0 (EventPipeProviderConfiguration, providers_len); - - if (config_providers) { - for (int i = 0; i < providers_len; ++i) { - ep_provider_config_init ( - &config_providers[i], - native_config_providers[i].provider_name ? mono_utf16_to_utf8 (native_config_providers[i].provider_name, g_utf16_len (native_config_providers[i].provider_name), error) : NULL, - native_config_providers [i].keywords, - (EventPipeEventLevel)native_config_providers [i].logging_level, - native_config_providers[i].filter_data ? mono_utf16_to_utf8 (native_config_providers[i].filter_data, g_utf16_len (native_config_providers[i].filter_data), error) : NULL); - } - } - - session_id = ep_enable ( + session_id = mono_component_event_pipe ()->enable ( output_file_utf8, circular_buffer_size_mb, - config_providers, + (EventPipeProviderConfigurationNative *)providers, providers_len, output_file != NULL ? EP_SESSION_TYPE_FILE : EP_SESSION_TYPE_LISTENER, (EventPipeSerializationFormat)format, true, NULL, NULL); - ep_start_streaming (session_id); - if (config_providers) { - for (int i = 0; i < providers_len; ++i) { - ep_provider_config_fini (&config_providers[i]); - g_free ((ep_char8_t *)ep_provider_config_get_provider_name (&config_providers[i])); - g_free ((ep_char8_t *)ep_provider_config_get_filter_data (&config_providers[i])); - } - } + mono_component_event_pipe ()->start_streaming (session_id); g_free (output_file_utf8); - return session_id; + return (uint64_t)session_id; } int32_t @@ -958,40 +173,7 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_EventActivityIdControl ( uint32_t control_code, /* GUID * */uint8_t *activity_id) { - int32_t result = 0; - ep_rt_thread_activity_id_handle_t activity_id_handle = ep_thread_get_activity_id_handle (); - - if (activity_id_handle == NULL) - return 1; - - uint8_t current_activity_id [EP_ACTIVITY_ID_SIZE]; - EventPipeActivityControlCode activity_control_code = (EventPipeActivityControlCode)control_code; - switch (activity_control_code) { - case EP_ACTIVITY_CONTROL_GET_ID: - ep_thread_get_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); - break; - case EP_ACTIVITY_CONTROL_SET_ID: - ep_thread_set_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); - break; - case EP_ACTIVITY_CONTROL_CREATE_ID: - ep_thread_create_activity_id (activity_id, EP_ACTIVITY_ID_SIZE); - break; - case EP_ACTIVITY_CONTROL_GET_SET_ID: - ep_thread_get_activity_id (activity_id_handle, current_activity_id, EP_ACTIVITY_ID_SIZE); - ep_thread_set_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); - memcpy (activity_id, current_activity_id, EP_ACTIVITY_ID_SIZE); - break; - case EP_ACTIVITY_CONTROL_CREATE_SET_ID: - ep_thread_get_activity_id (activity_id_handle, activity_id, EP_ACTIVITY_ID_SIZE); - ep_thread_create_activity_id (current_activity_id, EP_ACTIVITY_ID_SIZE); - ep_thread_set_activity_id (activity_id_handle, current_activity_id, EP_ACTIVITY_ID_SIZE); - break; - default: - result = 1; - break; - } - - return result; + return mono_component_event_pipe ()->thread_ctrl_activity_id ((EventPipeActivityControlCode)control_code, activity_id, EP_ACTIVITY_ID_SIZE) ? 0 : 1; } MonoBoolean @@ -999,25 +181,7 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetNextEvent ( uint64_t session_id, /* EventPipeEventInstanceData * */void *instance) { - g_assert (instance != NULL); - - EventPipeEventInstance *const next_instance = ep_get_next_event (session_id); - EventPipeEventInstanceData *const data = (EventPipeEventInstanceData *)instance; - if (next_instance && data) { - const EventPipeEvent *const ep_event = ep_event_instance_get_ep_event (next_instance); - if (ep_event) { - data->provider_id = (intptr_t)ep_event_get_provider (ep_event); - data->event_id = ep_event_get_event_id (ep_event); - } - data->thread_id = ep_event_instance_get_thread_id (next_instance); - data->timestamp = ep_event_instance_get_timestamp (next_instance); - memcpy (&data->activity_id, ep_event_instance_get_activity_id_cref (next_instance), EP_ACTIVITY_ID_SIZE); - memcpy (&data->related_activity_id, ep_event_instance_get_related_activity_id_cref (next_instance), EP_ACTIVITY_ID_SIZE); - data->payload = ep_event_instance_get_data (next_instance); - data->payload_len = ep_event_instance_get_data_len (next_instance); - } - - return next_instance != NULL; + return mono_component_event_pipe ()->get_next_event ((EventPipeSessionID)session_id, (EventPipeEventInstanceData *)instance) ? TRUE : FALSE; } intptr_t @@ -1029,7 +193,7 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetProvider (const gunich if (provider_name) { provider_name_utf8 = mono_utf16_to_utf8 (provider_name, g_utf16_len (provider_name), error); - provider = ep_get_provider (provider_name_utf8); + provider = mono_component_event_pipe()->get_provider (provider_name_utf8); } g_free (provider_name_utf8); @@ -1041,25 +205,13 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetSessionInfo ( uint64_t session_id, /* EventPipeSessionInfo * */void *session_info) { - bool result = false; - if (session_info) { - EventPipeSession *session = ep_get_session ((EventPipeSessionID)session_id); - if (session) { - EventPipeSessionInfo *instance = (EventPipeSessionInfo *)session_info; - instance->starttime_as_utc_filetime = ep_session_get_session_start_time (session); - instance->start_timestamp = ep_session_get_session_start_timestamp (session); - instance->timestamp_frequency = ep_perf_frequency_query (); - result = true; - } - } - - return result; + return mono_component_event_pipe()->get_session_info (session_id, (EventPipeSessionInfo *)session_info) ? TRUE : FALSE; } intptr_t ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetWaitHandle (uint64_t session_id) { - return (intptr_t)ep_get_wait_handle (session_id); + return (intptr_t) mono_component_event_pipe()->get_wait_handle ((EventPipeSessionID)session_id); } void @@ -1072,7 +224,7 @@ ves_icall_System_Diagnostics_Tracing_EventPipeInternal_WriteEventData ( { g_assert (event_handle); EventPipeEvent *ep_event = (EventPipeEvent *)event_handle; - ep_write_event_2 (ep_event, (EventData *)event_data, event_data_len, activity_id, related_activity_id); + mono_component_event_pipe()->write_event_2 (ep_event, (EventData *)event_data, event_data_len, activity_id, related_activity_id); } #else /* ENABLE_PERFTRACING */ diff --git a/src/mono/mono/metadata/jit-info.h b/src/mono/mono/metadata/jit-info.h index dabb36af8bf3e1..ec41b61c0b3417 100644 --- a/src/mono/mono/metadata/jit-info.h +++ b/src/mono/mono/metadata/jit-info.h @@ -260,7 +260,7 @@ mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end); MonoGenericJitInfo* mono_jit_info_get_generic_jit_info (MonoJitInfo *ji); -MonoGenericSharingContext* +MONO_COMPONENT_API MonoGenericSharingContext* mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji); void @@ -289,7 +289,7 @@ MonoJitInfo* mono_jit_info_table_find_internal (gpointer addr, gboolean try_aot, typedef void (*MonoJitInfoFunc) (MonoJitInfo *ji, gpointer user_data); -void +MONO_COMPONENT_API void mono_jit_info_table_foreach_internal (MonoJitInfoFunc func, gpointer user_data); void diff --git a/src/mono/mono/metadata/loader-internals.h b/src/mono/mono/metadata/loader-internals.h index ec6eb8f80cdf3b..af4ff2e4865685 100644 --- a/src/mono/mono/metadata/loader-internals.h +++ b/src/mono/mono/metadata/loader-internals.h @@ -278,7 +278,7 @@ mono_alc_add_assembly (MonoAssemblyLoadContext *alc, MonoAssembly *ass); MonoAssembly* mono_alc_find_assembly (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname); -GPtrArray* +MONO_COMPONENT_API GPtrArray* mono_alc_get_all_loaded_assemblies (void); MONO_API void diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index e18a6f4ec8b8cc..0d9c7dcfe048bb 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -30,6 +30,7 @@ #include "debug-helpers.h" #include "abi-details.h" #include "cominterop.h" +#include "components.h" #include #include #include @@ -2029,6 +2030,8 @@ mono_metadata_init (void) for (i = 0; i < NBUILTIN_TYPES (); ++i) g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]); + mono_components_init (); + #ifdef ENABLE_METADATA_UPDATE mono_metadata_update_init (); #endif diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index 13c0cf562d5ca5..e70f24f7cc480d 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -1224,7 +1224,7 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib, Mo g_hash_table_add (native_library_module_blocklist, module); mono_dl_close (module); } else { - MonoDl raw_module = { 0 }; + MonoDl raw_module = { { 0 } }; raw_module.handle = lib; mono_dl_close (&raw_module); } @@ -1255,7 +1255,7 @@ ves_icall_System_Runtime_InteropServices_NativeLibrary_GetSymbol (gpointer lib, if (!symbol) mono_error_set_generic_error (error, "System", "EntryPointNotFoundException", "%s: %s", module->full_name, symbol_name); } else { - MonoDl raw_module = { 0 }; + MonoDl raw_module = { { 0 } }; raw_module.handle = lib; mono_dl_symbol (&raw_module, symbol_name, &symbol); if (!symbol) diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index c92ea7bcf43d62..49af8f525f91e7 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -691,6 +691,7 @@ mono_get_runtime_callbacks (void); void mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs); +MONO_COMPONENT_API MonoRuntimeExceptionHandlingCallbacks * mono_get_eh_callbacks (void); @@ -1795,6 +1796,7 @@ mono_string_from_utf32_checked (const mono_unichar4 *data, MonoError *error); char* mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error); +MONO_COMPONENT_API char* mono_utf16_to_utf8 (const mono_unichar2 *s, gsize slength, MonoError *error); @@ -2070,7 +2072,7 @@ mono_gc_wbarrier_value_copy_internal (void* dest, const void* src, int count, Mo void mono_gc_wbarrier_object_copy_internal (MonoObject* obj, MonoObject *src); -char * +MONO_COMPONENT_API char * mono_runtime_get_managed_cmd_line (void); char * diff --git a/src/mono/mono/metadata/threads-types.h b/src/mono/mono/metadata/threads-types.h index b9c963721d58e2..e3869ca5b5fdd5 100644 --- a/src/mono/mono/metadata/threads-types.h +++ b/src/mono/mono/metadata/threads-types.h @@ -207,7 +207,7 @@ void mono_thread_internal_unhandled_exception (MonoObject* exc); void mono_alloc_special_static_data_free (GHashTable *special_static_fields); -void mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state); +MONO_COMPONENT_API void mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state); void mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state); gboolean mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test); gboolean mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set); diff --git a/src/mono/mono/metadata/w32event.h b/src/mono/mono/metadata/w32event.h index 74a045cc4dd0db..8f88ce09450239 100644 --- a/src/mono/mono/metadata/w32event.h +++ b/src/mono/mono/metadata/w32event.h @@ -12,16 +12,20 @@ #include "object-internals.h" #include "w32handle.h" #include +#include void mono_w32event_init (void); +MONO_COMPONENT_API gpointer mono_w32event_create (gboolean manual, gboolean initial); +MONO_COMPONENT_API gboolean mono_w32event_close (gpointer handle); +MONO_COMPONENT_API void mono_w32event_set (gpointer handle); diff --git a/src/mono/mono/metadata/w32file.h b/src/mono/mono/metadata/w32file.h index 2700933c98bc38..86e1c05f397e1a 100644 --- a/src/mono/mono/metadata/w32file.h +++ b/src/mono/mono/metadata/w32file.h @@ -142,12 +142,15 @@ typedef struct { void mono_w32file_init (void); +MONO_COMPONENT_API gpointer mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs); +MONO_COMPONENT_API gboolean mono_w32file_close (gpointer handle); +MONO_COMPONENT_API gboolean mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error); diff --git a/src/mono/mono/metadata/w32handle.h b/src/mono/mono/metadata/w32handle.h index c985e793232fb6..6ec82b812e0772 100644 --- a/src/mono/mono/metadata/w32handle.h +++ b/src/mono/mono/metadata/w32handle.h @@ -16,6 +16,7 @@ #include "mono/utils/mono-coop-mutex.h" #include "mono/utils/mono-error.h" +#include #define MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS 64 #define MONO_INFINITE_WAIT ((guint32) 0xFFFFFFFF) @@ -136,6 +137,7 @@ mono_w32handle_lock (MonoW32Handle *handle_data); void mono_w32handle_unlock (MonoW32Handle *handle_data); +MONO_COMPONENT_API MonoW32HandleWaitRet mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable); diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index 6e5c37ba16b352..8fbc1af6141fa1 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -19,6 +19,18 @@ include_directories( ${PROJECT_SOURCE_DIR}/../eglib ${PROJECT_SOURCE_DIR}/../sgen) +if(HOST_DARWIN) +set(OS_LIBS "-framework CoreFoundation" "-framework Foundation") +elseif(HOST_IOS) +set(OS_LIBS "-framework CoreFoundation" "-lobjc" "-lc++") +elseif(HOST_ANDROID) +set(OS_LIBS m dl log) +elseif(HOST_LINUX) +set(OS_LIBS pthread m dl) +elseif(HOST_WIN32) +set(OS_LIBS bcrypt.lib Mswsock.lib ws2_32.lib psapi.lib version.lib advapi32.lib winmm.lib kernel32.lib) +endif() + # # SUBDIRS # @@ -29,21 +41,7 @@ include(../sgen/CMakeLists.txt) if(INTERNAL_ZLIB) # TODO: hook up HAVE_SYS_ZLIB instead include(../zlib/CMakeLists.txt) endif() - -if(ENABLE_PERFTRACING) - - set (SHARED_EVENTPIPE_INCLUDE_PATH "../../../native/") - set (SHARED_EVENTPIPE_SOURCE_PATH "../../../native/eventpipe/") - set (MONO_EVENTPIPE_SHIM_SOURCE_PATH "../eventpipe/") - - include(${MONO_EVENTPIPE_SHIM_SOURCE_PATH}/CMakeLists.txt) - - include_directories( - ${SHARED_EVENTPIPE_INCLUDE_PATH} - ${MONO_EVENTPIPE_SHIM_SOURCE_PATH} - ) - -endif(ENABLE_PERFTRACING) +include(../component/CMakeLists.txt) if(HOST_WIN32) # /OPT:ICF merges idential functions breaking mono_lookup_icall_symbol () @@ -242,8 +240,6 @@ set(windows_sources mini-windows.c mini-windows-tls-callback.c mini-windows.h - mini-windows-dllmain.c - # mini-windows-dlldac.c ) set(posix_sources @@ -310,23 +306,21 @@ if(LLVM_LIBDIR) link_directories(${LLVM_LIBDIR}) endif() -if(HOST_DARWIN) -set(OS_LIBS "-framework CoreFoundation" "-framework Foundation") -elseif(HOST_IOS) -set(OS_LIBS "-framework CoreFoundation" "-lobjc" "-lc++") -elseif(HOST_ANDROID) -set(OS_LIBS m dl log) -elseif(HOST_LINUX) -set(OS_LIBS pthread m dl) -elseif(HOST_WIN32) -set(OS_LIBS bcrypt.lib Mswsock.lib ws2_32.lib psapi.lib version.lib advapi32.lib winmm.lib kernel32.lib) +if(HOST_WIN32) set(mini_sources "${mini_sources};${PROJECT_BINARY_DIR}/../../NativeVersion.rc") # this is generated by GenerateMonoVersionFile in mono.proj endif() +set(monosgen-sources "${metadata_sources};${utils_sources};${sgen_sources};${icu_shim_sources};${mini_sources};${zlib_sources}") + +add_library(monosgen-objects OBJECT "${monosgen-sources}") +add_library(monosgen-static STATIC $;$) +set_target_properties(monosgen-static PROPERTIES OUTPUT_NAME ${MONO_LIB_NAME}) + +if(DISABLE_COMPONENTS) + # add component fallback stubs into static mono library when components have been disabled. + target_sources(monosgen-static PRIVATE "${mono-components-stub-objects}") +endif() -add_library(monosgen-objects OBJECT "${eglib_sources};${metadata_sources};${utils_sources};${sgen_sources};${icu_shim_sources};${eventpipe_sources};${mini_sources};${zlib_sources}") -add_library(monosgen-static STATIC $) -set_target_properties(monosgen-static PROPERTIES OUTPUT_NAME monosgen-2.0) if(NOT DISABLE_LIBS) install(TARGETS monosgen-static LIBRARY) install(FILES ${metadata_public_headers} @@ -337,14 +331,21 @@ if(NOT DISABLE_LIBS) DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mono-2.0/mono/jit) endif() if(NOT DISABLE_SHARED_LIBS) - add_library(monosgen-shared SHARED $ ) - set_target_properties(monosgen-shared PROPERTIES OUTPUT_NAME monosgen-2.0) + if(HOST_WIN32) + add_library(monosgen-shared SHARED "mini-windows-dllmain.c;${monosgen-sources}") + target_compile_definitions(monosgen-shared PRIVATE -DMONO_DLL_EXPORT) + else() + add_library(monosgen-shared SHARED $) + target_compile_definitions(monosgen-objects PRIVATE -DMONO_DLL_EXPORT) + endif() + target_sources(monosgen-shared PRIVATE $) + set_target_properties(monosgen-shared PROPERTIES OUTPUT_NAME ${MONO_SHARED_LIB_NAME}) if(TARGET_WIN32) - # on Windows the import library for the shared monosgen-2.0 library will have the same name as the static library (monosgen-2.0.lib), + # on Windows the import library for the shared mono library will have the same name as the static library, # to avoid a conflict we rename the import library with the .import.lib suffix set_target_properties(monosgen-shared PROPERTIES IMPORT_SUFFIX ".import.lib") endif() - target_link_libraries(monosgen-shared ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) + target_link_libraries(monosgen-shared PRIVATE ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) if(ICU_LDFLAGS) set_property(TARGET monosgen-shared APPEND_STRING PROPERTY LINK_FLAGS " ${ICU_LDFLAGS}") endif() @@ -354,7 +355,26 @@ if(NOT DISABLE_SHARED_LIBS) if(TARGET_DARWIN) set_property(TARGET monosgen-shared APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-compatibility_version -Wl,2.0 -Wl,-current_version -Wl,2.0") endif() + if(NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS AND NOT DISABLE_LINK_STATIC_COMPONENTS) + # if components are built statically, but we're building a shared lib mono, + # link them into the library + target_sources(monosgen-shared PRIVATE "${mono-components-objects}") + elseif(NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS AND DISABLE_LINK_STATIC_COMPONENTS) + # if components are built statically, we're building a shared lib mono, but we shouldn't link components + # link the fallback stubs into the runtime + target_sources(monosgen-shared PRIVATE "${mono-components-stub-objects}") + elseif(NOT DISABLE_COMPONENTS AND NOT STATIC_COMPONENTS) + # if components are built dynamically, link the fallback stubs into the runtime + target_sources(monosgen-shared PRIVATE "${mono-components-stub-objects}") + elseif(DISABLE_COMPONENTS) + # if components are disabled, link the fallback stubs into the runtime + target_sources(monosgen-shared PRIVATE "${mono-components-stub-objects}") + endif() install(TARGETS monosgen-shared LIBRARY) + if(HOST_WIN32 AND TARGET_AMD64) + add_library(monosgen-shared-dac SHARED "mini-windows-dlldac.c") + set_target_properties(monosgen-shared-dac PROPERTIES OUTPUT_NAME ${MONO_SHARED_LIB_NAME}-dac) + endif() endif() find_package(Python3 COMPONENTS Interpreter) @@ -398,7 +418,21 @@ if(NOT DISABLE_EXECUTABLES) set(sgen_sources "${sgen_sources};${PROJECT_BINARY_DIR}/../../NativeVersion.rc") endif() add_executable(mono-sgen "${sgen_sources}") - target_link_libraries(mono-sgen monosgen-static ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) + target_link_libraries(mono-sgen PRIVATE monosgen-static ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) + if(NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS AND NOT DISABLE_LINK_STATIC_COMPONENTS) + # if components are built statically, link them into runtime. + target_sources(mono-sgen PRIVATE "${mono-components-objects}") + elseif(NOT DISABLE_COMPONENTS AND STATIC_COMPONENTS AND DISABLE_LINK_STATIC_COMPONENTS) + # if components are built statically, but we shouldn't link components + # link the fallback stubs into the runtime + target_sources(mono-sgen PRIVATE "${mono-components-stub-objects}") + elseif(NOT DISABLE_COMPONENTS AND NOT STATIC_COMPONENTS) + # if components are built dynamically, link the fallback stubs into the runtime + target_sources(mono-sgen PRIVATE "${mono-components-stub-objects}") + elseif(DISABLE_COMPONENTS) + # if components are disabled, link the fallback stubs into the runtime + # fallback stubs already provided in monosgen-static when components are disabled + endif() if(ICU_LDFLAGS) set_property(TARGET mono-sgen APPEND_STRING PROPERTY LINK_FLAGS " ${ICU_LDFLAGS}") endif() diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index f1c43bcabaea95..0dc726c4b530e5 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -71,11 +71,7 @@ #include #include #include - -#ifdef ENABLE_PERFTRACING -#include -#include -#endif +#include #include "mini.h" #include "seq-points.h" @@ -4428,12 +4424,10 @@ mini_init (const char *filename, const char *runtime_version) else domain = mono_init_from_assembly (filename, filename); -#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) if (mono_compile_aot) - ds_server_disable (); + mono_component_diagnostics_server ()->disable (); - ep_init (); -#endif + mono_component_event_pipe ()->init (); if (mono_aot_only) { /* This helps catch code allocation requests */ @@ -4500,9 +4494,7 @@ mini_init (const char *filename, const char *runtime_version) #endif mono_threads_set_runtime_startup_finished (); -#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) - ep_finish_init (); -#endif + mono_component_event_pipe ()->finish_init (); #ifdef ENABLE_EXPERIMENT_TIERED if (!mono_compile_aot) { @@ -4883,10 +4875,8 @@ mini_cleanup (MonoDomain *domain) jit_stats_cleanup (); mono_jit_dump_cleanup (); mini_get_interp_callbacks ()->cleanup (); -#if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) - ep_shutdown (); - ds_server_shutdown (); -#endif + mono_component_event_pipe ()->shutdown (); + mono_component_diagnostics_server ()->shutdown (); } void diff --git a/src/mono/mono/utils/atomic.h b/src/mono/mono/utils/atomic.h index 4b46122c518656..5ba7bd2c2a0861 100755 --- a/src/mono/mono/utils/atomic.h +++ b/src/mono/mono/utils/atomic.h @@ -373,7 +373,7 @@ static inline gint64 mono_atomic_load_i64(volatile gint64 *src) #else /* Implement 64-bit cas by hand or emulate it. */ -extern gint64 mono_atomic_cas_i64(volatile gint64 *dest, gint64 exch, gint64 comp); +MONO_COMPONENT_API gint64 mono_atomic_cas_i64(volatile gint64 *dest, gint64 exch, gint64 comp); /* Implement all other 64-bit atomics in terms of a specialized CAS * in this case, since chances are that the other 64-bit atomic diff --git a/src/mono/mono/utils/mono-compiler.h b/src/mono/mono/utils/mono-compiler.h index 4f6043e3349d22..f5f8b860ca0cd9 100644 --- a/src/mono/mono/utils/mono-compiler.h +++ b/src/mono/mono/utils/mono-compiler.h @@ -14,6 +14,8 @@ #include #endif +#include + #ifdef __GNUC__ #define MONO_ATTR_USED __attribute__ ((__used__)) #else @@ -81,6 +83,18 @@ typedef ptrdiff_t ssize_t; /* Used to mark internal functions used by the CoreFX PAL library */ #define MONO_PAL_API MONO_API +/* Mono components */ + +/* Used to mark internal functions used by dynamically linked runtime components */ +#define MONO_COMPONENT_API MONO_API + +#ifdef COMPILING_COMPONENT_DYNAMIC +#define MONO_COMPONENT_EXPORT_ENTRYPOINT MONO_EXTERN_C MONO_API_EXPORT +#else +#define MONO_COMPONENT_EXPORT_ENTRYPOINT /* empty */ +#endif + + #ifdef __GNUC__ #define MONO_ALWAYS_INLINE __attribute__ ((__always_inline__)) #elif defined(_MSC_VER) diff --git a/src/mono/mono/utils/mono-proclib.h b/src/mono/mono/utils/mono-proclib.h index 01c93526c124b5..6b653bd7ff27e9 100644 --- a/src/mono/mono/utils/mono-proclib.h +++ b/src/mono/mono/utils/mono-proclib.h @@ -70,7 +70,7 @@ char* mono_process_get_name (gpointer pid, char *buf, int len); gint64 mono_process_get_data (gpointer pid, MonoProcessData data); gint64 mono_process_get_data_with_error (gpointer pid, MonoProcessData data, MonoProcessError *error); -int mono_process_current_pid (void); +MONO_COMPONENT_API int mono_process_current_pid (void); MONO_API int mono_cpu_count (void); gint64 mono_cpu_get_data (int cpu_id, MonoCpuData data, MonoProcessError *error); diff --git a/src/mono/mono/utils/mono-rand.h b/src/mono/mono/utils/mono-rand.h index 2f3b6aaa36cff3..4ce397aa8e4f75 100644 --- a/src/mono/mono/utils/mono-rand.h +++ b/src/mono/mono/utils/mono-rand.h @@ -10,18 +10,22 @@ #include "mono-compiler.h" #include "mono-error.h" +MONO_COMPONENT_API gboolean mono_rand_open (void); +MONO_COMPONENT_API gpointer mono_rand_init (const guchar *seed, gssize seed_size); +MONO_COMPONENT_API gboolean mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gssize buffer_size, MonoError *error); gboolean mono_rand_try_get_uint32 (gpointer *handle, guint32 *val, guint32 min, guint32 max, MonoError *error); +MONO_COMPONENT_API void mono_rand_close (gpointer handle); diff --git a/src/mono/mono/utils/mono-threads.h b/src/mono/mono/utils/mono-threads.h index 8d08f10fe5baf0..c0cd48216528b3 100644 --- a/src/mono/mono/utils/mono-threads.h +++ b/src/mono/mono/utils/mono-threads.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -451,9 +452,7 @@ mono_thread_info_unset_internal_thread_gchandle (THREAD_INFO_TYPE *info); gboolean mono_thread_info_is_exiting (void); -#ifdef HOST_WIN32 -G_EXTERN_C // due to THREAD_INFO_TYPE varying -#endif +MONO_COMPONENT_API THREAD_INFO_TYPE * mono_thread_info_current (void); @@ -470,6 +469,7 @@ mono_thread_info_current_unchecked (void); MONO_API int mono_thread_info_get_small_id (void); +MONO_COMPONENT_API MonoLinkedListSet* mono_thread_info_list_head (void); @@ -506,7 +506,7 @@ mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize); MONO_API gboolean mono_thread_info_yield (void); -gint +MONO_COMPONENT_API gint mono_thread_info_sleep (guint32 ms, gboolean *alerted); gint @@ -624,7 +624,7 @@ gint mono_threads_suspend_get_suspend_signal (void); gint mono_threads_suspend_get_restart_signal (void); gint mono_threads_suspend_get_abort_signal (void); -gboolean +MONO_COMPONENT_API gboolean mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *tid); @@ -763,7 +763,7 @@ gboolean mono_threads_transition_peek_blocking_suspend_requested (THREAD_INFO_TY void mono_threads_transition_begin_no_safepoints (THREAD_INFO_TYPE* info, const char *func); void mono_threads_transition_end_no_safepoints (THREAD_INFO_TYPE* info, const char *func); -G_EXTERN_C // due to THREAD_INFO_TYPE varying +MONO_COMPONENT_API MonoThreadUnwindState* mono_thread_info_get_suspend_state (THREAD_INFO_TYPE *info); gpointer @@ -772,8 +772,7 @@ mono_threads_enter_gc_unsafe_region_cookie (void); void mono_thread_info_wait_for_resume (THREAD_INFO_TYPE *info); /* Advanced suspend API, used for suspending multiple threads as once. */ -G_EXTERN_C // due to THREAD_INFO_TYPE varying -gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info); +MONO_COMPONENT_API gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info); gboolean mono_thread_info_is_live (THREAD_INFO_TYPE *info); G_EXTERN_C // due to THREAD_INFO_TYPE varying int mono_thread_info_suspend_count (THREAD_INFO_TYPE *info); diff --git a/src/mono/mono/utils/mono-time.h b/src/mono/mono/utils/mono-time.h index 921efbbc61a95c..874a4677c693ac 100644 --- a/src/mono/mono/utils/mono-time.h +++ b/src/mono/mono/utils/mono-time.h @@ -20,7 +20,7 @@ gint64 mono_msec_boottime (void); gint64 mono_msec_ticks (void); /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */ -gint64 mono_100ns_ticks (void); +MONO_COMPONENT_API gint64 mono_100ns_ticks (void); /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */ gint64 mono_100ns_datetime (void); diff --git a/src/native/eventpipe/CMakeLists.txt b/src/native/eventpipe/CMakeLists.txt index 07acdcf6800029..c320b615fc410e 100644 --- a/src/native/eventpipe/CMakeLists.txt +++ b/src/native/eventpipe/CMakeLists.txt @@ -41,6 +41,7 @@ if(ENABLE_PERFTRACING OR FEATURE_PERFTRACING) ep-file.h ep-getter-setter.h ep-ipc-pal-types.h + ep-ipc-pal-types-forward.h ep-ipc-stream.h ep-json-file.h ep-metadata-generator.h @@ -56,6 +57,7 @@ if(ENABLE_PERFTRACING OR FEATURE_PERFTRACING) ep-stream.h ep-thread.h ep-types.h + ep-types-forward.h ) list(APPEND SHARED_DIAGNOSTIC_SERVER_SOURCES diff --git a/src/native/eventpipe/ds-ipc.c b/src/native/eventpipe/ds-ipc.c index 8493eeab058246..a8b12b1e980f16 100644 --- a/src/native/eventpipe/ds-ipc.c +++ b/src/native/eventpipe/ds-ipc.c @@ -7,6 +7,7 @@ #define DS_IMPL_IPC_PAL_GETTER_SETTER #include "ds-ipc.h" #include "ds-protocol.h" +#include "ep.h" #include "ds-rt.h" /* @@ -164,7 +165,7 @@ ipc_stream_factory_build_and_add_port ( bool result = false; DiagnosticsIpc *ipc = NULL; -#ifndef DS_IPC_PAL_TCP +#ifndef DS_IPC_DISABLE_LISTEN_PORTS if (!default_port && builder->type == DS_PORT_TYPE_LISTEN) { // Ignore listen type (see conversation in https://github.com/dotnet/runtime/pull/40499 for details) DS_LOG_INFO_0 ("ipc_stream_factory_build_and_add_port - Ignoring LISTEN port configuration"); @@ -238,6 +239,8 @@ ipc_log_poll_handles (ds_rt_ipc_poll_handle_array_t *ipc_poll_handles) bool ds_ipc_stream_factory_init (void) { + ep_ipc_stream_factory_callback_set (ds_ipc_stream_factory_any_suspended_ports); + ds_rt_port_array_alloc (&_ds_port_array); return ds_rt_port_array_is_valid (&_ds_port_array); } @@ -255,6 +258,8 @@ ds_ipc_stream_factory_fini (void) } ds_rt_port_array_free (&_ds_port_array);*/ + + ep_ipc_stream_factory_callback_set (NULL); } bool diff --git a/src/native/eventpipe/ds-rt-config.h b/src/native/eventpipe/ds-rt-config.h index 678ee18de2bde9..cb84d7d31afd1b 100644 --- a/src/native/eventpipe/ds-rt-config.h +++ b/src/native/eventpipe/ds-rt-config.h @@ -11,7 +11,7 @@ #define DS_INCLUDE_SOURCE_FILES #endif -#ifdef FEATURE_PERFTRACING_PAL_TCP +#ifdef ENABLE_PERFTRACING_PAL_TCP #define DS_IPC_PAL_TCP #else #ifndef HOST_WIN32 @@ -21,11 +21,11 @@ #endif #endif -#ifdef FEATURE_PERFTRACING_DISABLE_CONNECT_PORTS +#ifdef ENABLE_PERFTRACING_DISABLE_CONNECT_PORTS #define DS_IPC_DISABLE_CONNECT_PORTS #endif -#ifdef FEATURE_PERFTRACING_DISABLE_LISTEN_PORTS +#ifdef ENABLE_PERFTRACING_DISABLE_LISTEN_PORTS #define DS_IPC_DISABLE_LISTEN_PORTS #endif diff --git a/src/native/eventpipe/ds-server.c b/src/native/eventpipe/ds-server.c index 7f9c6866e0341c..dfce6d6860464e 100644 --- a/src/native/eventpipe/ds-server.c +++ b/src/native/eventpipe/ds-server.c @@ -116,7 +116,7 @@ EP_RT_DEFINE_THREAD_FUNC (server_thread) EP_ASSERT (server_volatile_load_shutting_down_state () || ds_ipc_stream_factory_has_active_ports ()); if (!ds_ipc_stream_factory_has_active_ports ()) { -#ifndef DS_IPC_PAL_TCP +#ifndef DS_IPC_DISABLE_LISTEN_PORTS DS_LOG_ERROR_0 ("Diagnostics IPC listener was undefined"); #endif return 1; diff --git a/src/native/eventpipe/ep-buffer-manager.c b/src/native/eventpipe/ep-buffer-manager.c index bcab43e1d34480..5b7c0592caf1b3 100644 --- a/src/native/eventpipe/ep-buffer-manager.c +++ b/src/native/eventpipe/ep-buffer-manager.c @@ -1371,6 +1371,7 @@ ep_buffer_manager_write_all_buffers_to_file_v4 ( } ep_on_exit: + ep_rt_thread_session_state_array_fini(&session_states_to_delete); return; ep_on_error: ep_exit_error_handler (); diff --git a/src/native/eventpipe/ep-ipc-pal-types-forward.h b/src/native/eventpipe/ep-ipc-pal-types-forward.h new file mode 100644 index 00000000000000..2c890cce81a772 --- /dev/null +++ b/src/native/eventpipe/ep-ipc-pal-types-forward.h @@ -0,0 +1,22 @@ +#ifndef __EVENTPIPE_IPC_PAL_TYPES_FORWARD_H__ +#define __EVENTPIPE_IPC_PAL_TYPES_FORWARD_H__ + +#ifdef ENABLE_PERFTRACING + +#include +#include +#ifndef __cplusplus +#include +#endif // __cplusplus + +typedef char ep_char8_t; + +/* + * IPC Stream Structs. + */ + +typedef struct _IpcStream IpcStream; +typedef struct _IpcStreamVtable IpcStreamVtable; + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_IPC_PAL_TYPES_FORWARD_H__ */ diff --git a/src/native/eventpipe/ep-ipc-pal-types.h b/src/native/eventpipe/ep-ipc-pal-types.h index ac2f3d0c5bd678..a353b8a3c104c8 100644 --- a/src/native/eventpipe/ep-ipc-pal-types.h +++ b/src/native/eventpipe/ep-ipc-pal-types.h @@ -9,20 +9,7 @@ #endif #include "ep-getter-setter.h" -#include -#include -#ifndef __cplusplus -#include -#endif // __cplusplus - -typedef char ep_char8_t; - -/* - * IPC Stream Structs. - */ - -typedef struct _IpcStream IpcStream; -typedef struct _IpcStreamVtable IpcStreamVtable; +#include "ep-ipc-pal-types-forward.h" #endif /* ENABLE_PERFTRACING */ #endif /* __EVENTPIPE_IPC_PAL_TYPES_H__ */ diff --git a/src/native/eventpipe/ep-types-forward.h b/src/native/eventpipe/ep-types-forward.h new file mode 100644 index 00000000000000..c6954d632961cd --- /dev/null +++ b/src/native/eventpipe/ep-types-forward.h @@ -0,0 +1,207 @@ +#ifndef __EVENTPIPE_TYPES_FORWARD_H__ +#define __EVENTPIPE_TYPES_FORWARD_H__ + +#ifdef ENABLE_PERFTRACING + +/* + * EventPipe Structs. + */ + +typedef struct _EventData EventData; +typedef struct _EventFilterDescriptor EventFilterDescriptor; +typedef struct _EventPipeBuffer EventPipeBuffer; +typedef struct _EventPipeBufferList EventPipeBufferList; +typedef struct _EventPipeBufferManager EventPipeBufferManager; +typedef struct _EventPipeBlock EventPipeBlock; +typedef struct _EventPipeBlockVtable EventPipeBlockVtable; +typedef struct _EventPipeConfiguration EventPipeConfiguration; +typedef struct _EventPipeEvent EventPipeEvent; +typedef struct _EventPipeEventBlockBase EventPipeEventBlockBase; +typedef struct _EventPipeEventBlock EventPipeEventBlock; +typedef struct _EventPipeEventHeader EventPipeEventHeader; +typedef struct _EventPipeEventInstance EventPipeEventInstance; +typedef struct _EventPipeEventMetadataEvent EventPipeEventMetadataEvent; +typedef struct _EventPipeEventPayload EventPipeEventPayload; +typedef struct _EventPipeEventSource EventPipeEventSource; +typedef struct _EventPipeFile EventPipeFile; +typedef struct _EventPipeJsonFile EventPipeJsonFile; +typedef struct _EventPipeMetadataBlock EventPipeMetadataBlock; +typedef struct _EventPipeParameterDesc EventPipeParameterDesc; +typedef struct _EventPipeProvider EventPipeProvider; +typedef struct _EventPipeProviderCallbackData EventPipeProviderCallbackData; +typedef struct _EventPipeProviderCallbackDataQueue EventPipeProviderCallbackDataQueue; +typedef struct _EventPipeProviderConfiguration EventPipeProviderConfiguration; +typedef struct _EventPipeSession EventPipeSession; +typedef struct _EventPipeSessionProvider EventPipeSessionProvider; +typedef struct _EventPipeSessionProviderList EventPipeSessionProviderList; +typedef struct _EventPipeSequencePoint EventPipeSequencePoint; +typedef struct _EventPipeSequencePointBlock EventPipeSequencePointBlock; +typedef struct _EventPipeStackBlock EventPipeStackBlock; +typedef struct _EventPipeStackContents EventPipeStackContents; +typedef struct _EventPipeSystemTime EventPipeSystemTime; +typedef struct _EventPipeThread EventPipeThread; +typedef struct _EventPipeThreadHolder EventPipeThreadHolder; +typedef struct _EventPipeThreadSessionState EventPipeThreadSessionState; +typedef struct _FastSerializableObject FastSerializableObject; +typedef struct _FastSerializableObjectVtable FastSerializableObjectVtable; +typedef struct _FastSerializer FastSerializer; +typedef struct _FileStream FileStream; +typedef struct _FileStreamWriter FileStreamWriter; +typedef struct _IpcStreamWriter IpcStreamWriter; +typedef struct _StackHashEntry StackHashEntry; +typedef struct _StackHashKey StackHashKey; +typedef struct _StreamWriter StreamWriter; +typedef struct _StreamWriterVtable StreamWriterVtable; + +#define EP_MAX_NUMBER_OF_SESSIONS 64 + +#define EP_GUID_SIZE 16 + +#define EP_ACTIVITY_ID_SIZE EP_GUID_SIZE + +#define EP_MAX_STACK_DEPTH 100 + +/* + * EventPipe Enums. + */ + +typedef enum { + EP_BUFFER_STATE_WRITABLE = 0, + EP_BUFFER_STATE_READ_ONLY = 1 +} EventPipeBufferState; + +typedef enum { + EP_EVENT_LEVEL_LOGALWAYS, + EP_EVENT_LEVEL_CRITICAL, + EP_EVENT_LEVEL_ERROR, + EP_EVENT_LEVEL_WARNING, + EP_EVENT_LEVEL_INFORMATIONAL, + EP_EVENT_LEVEL_VERBOSE +} EventPipeEventLevel; + +typedef enum { + EP_FILE_FLUSH_FLAGS_EVENT_BLOCK = 1, + EP_FILE_FLUSH_FLAGS_METADATA_BLOCK = 2, + EP_FILE_FLUSH_FLAGS_STACK_BLOCK = 4, + EP_FILE_FLUSH_FLAGS_ALL_BLOCKS = EP_FILE_FLUSH_FLAGS_EVENT_BLOCK | EP_FILE_FLUSH_FLAGS_METADATA_BLOCK | EP_FILE_FLUSH_FLAGS_STACK_BLOCK +} EventPipeFileFlushFlags; + +// Represents the type of an event parameter. +// This enum is derived from the managed TypeCode type, though +// not all of these values are available in TypeCode. +// For example, Guid does not exist in TypeCode. +// Keep this in sync with COR_PRF_EVENTPIPE_PARAM_TYPE defined in +// corprof.idl +typedef enum { + EP_PARAMETER_TYPE_EMPTY = 0, // Null reference + EP_PARAMETER_TYPE_OBJECT = 1, // Instance that isn't a value + EP_PARAMETER_TYPE_DB_NULL = 2, // Database null value + EP_PARAMETER_TYPE_BOOLEAN = 3, // Boolean + EP_PARAMETER_TYPE_CHAR = 4, // Unicode character + EP_PARAMETER_TYPE_SBYTE = 5, // Signed 8-bit integer + EP_PARAMETER_TYPE_BYTE = 6, // Unsigned 8-bit integer + EP_PARAMETER_TYPE_INT16 = 7, // Signed 16-bit integer + EP_PARAMETER_TYPE_UINT16 = 8, // Unsigned 16-bit integer + EP_PARAMETER_TYPE_INT32 = 9, // Signed 32-bit integer + EP_PARAMETER_TYPE_UINT32 = 10, // Unsigned 32-bit integer + EP_PARAMETER_TYPE_INT64 = 11, // Signed 64-bit integer + EP_PARAMETER_TYPE_UINT64 = 12, // Unsigned 64-bit integer + EP_PARAMETER_TYPE_SINGLE = 13, // IEEE 32-bit float + EP_PARAMETER_TYPE_DOUBLE = 14, // IEEE 64-bit double + EP_PARAMETER_TYPE_DECIMAL = 15, // Decimal + EP_PARAMETER_TYPE_DATE_TIME = 16, // DateTime + EP_PARAMETER_TYPE_GUID = 17, // Guid + EP_PARAMETER_TYPE_STRING = 18, // Unicode character string + EP_PARAMETER_TYPE_ARRAY = 19 // Indicates the type is an arbitrary sized array +} EventPipeParameterType; + +typedef enum { + EP_METADATA_TAG_OPCODE = 1, + EP_METADATA_TAG_PARAMETER_PAYLOAD = 2 +} EventPipeMetadataTag; + +typedef enum { + EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR = 0, + EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL = 1, + EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED = 2 +} EventPipeSampleProfilerSampleType; + +typedef enum { + // Default format used in .Net Core 2.0-3.0 Preview 6 + // TBD - it may remain the default format .Net Core 3.0 when + // used with private EventPipe managed API via reflection. + // This format had limited official exposure in documented + // end-user RTM scenarios, but it is supported by PerfView, + // TraceEvent, and was used by AI profiler. + EP_SERIALIZATION_FORMAT_NETPERF_V3, + // Default format we plan to use in .Net Core 3 Preview7+ + // for most if not all scenarios. + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + EP_SERIALIZATION_FORMAT_COUNT +} EventPipeSerializationFormat; + +typedef enum { + EP_SESSION_TYPE_FILE, + EP_SESSION_TYPE_LISTENER, + EP_SESSION_TYPE_IPCSTREAM, + EP_SESSION_TYPE_SYNCHRONOUS +} EventPipeSessionType ; + +typedef enum { + EP_STATE_NOT_INITIALIZED, + EP_STATE_INITIALIZED, + EP_STATE_SHUTTING_DOWN +} EventPipeState; + +typedef enum { + EP_THREAD_TYPE_SERVER, + EP_THREAD_TYPE_SESSION, + EP_THREAD_TYPE_SAMPLING +} EventPipeThreadType; + +/* + * EventPipe Basic Types. + */ + +typedef intptr_t EventPipeWaitHandle; +typedef uint64_t EventPipeSessionID; +typedef unsigned short ep_char16_t; +typedef int64_t ep_timestamp_t; +typedef int64_t ep_system_timestamp_t; + +/* + * EventPipe Callbacks. + */ + +// Define the event pipe callback to match the ETW callback signature. +typedef void (*EventPipeCallback)( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_data); + +typedef void (*EventPipeCallbackDataFree)( + EventPipeCallback callback, + void *callback_data); + +typedef void (*EventPipeSessionSynchronousCallback)( + EventPipeProvider *provider, + uint32_t event_id, + uint32_t event_version, + uint32_t metadata_blob_len, + const uint8_t *metadata_blob, + uint32_t event_data_len, + const uint8_t *event_data, + const uint8_t *activity_id, + const uint8_t *related_activity_id, + /*ep_rt_thread_handle_t*/ void *event_thread, + uint32_t stack_frames_len, + uintptr_t *stack_frames); + +typedef bool (*EventPipeIpcStreamFactorySuspendedPortsCallback)(void); + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_TYPES_FORWARD_H__ */ diff --git a/src/native/eventpipe/ep-types.h b/src/native/eventpipe/ep-types.h index 0c91757fcfbe95..22ad3a749bf865 100644 --- a/src/native/eventpipe/ep-types.h +++ b/src/native/eventpipe/ep-types.h @@ -10,206 +10,10 @@ #endif #include "ep-getter-setter.h" -/* - * EventPipe Structs. - */ - -typedef struct _EventData EventData; -typedef struct _EventFilterDescriptor EventFilterDescriptor; -typedef struct _EventPipeBuffer EventPipeBuffer; -typedef struct _EventPipeBufferList EventPipeBufferList; -typedef struct _EventPipeBufferManager EventPipeBufferManager; -typedef struct _EventPipeBlock EventPipeBlock; -typedef struct _EventPipeBlockVtable EventPipeBlockVtable; -typedef struct _EventPipeConfiguration EventPipeConfiguration; -typedef struct _EventPipeEvent EventPipeEvent; -typedef struct _EventPipeEventBlockBase EventPipeEventBlockBase; -typedef struct _EventPipeEventBlock EventPipeEventBlock; -typedef struct _EventPipeEventHeader EventPipeEventHeader; -typedef struct _EventPipeEventInstance EventPipeEventInstance; -typedef struct _EventPipeEventMetadataEvent EventPipeEventMetadataEvent; -typedef struct _EventPipeEventPayload EventPipeEventPayload; -typedef struct _EventPipeEventSource EventPipeEventSource; -typedef struct _EventPipeFile EventPipeFile; -typedef struct _EventPipeJsonFile EventPipeJsonFile; -typedef struct _EventPipeMetadataBlock EventPipeMetadataBlock; -typedef struct _EventPipeParameterDesc EventPipeParameterDesc; -typedef struct _EventPipeProvider EventPipeProvider; -typedef struct _EventPipeProviderCallbackData EventPipeProviderCallbackData; -typedef struct _EventPipeProviderCallbackDataQueue EventPipeProviderCallbackDataQueue; -typedef struct _EventPipeProviderConfiguration EventPipeProviderConfiguration; -typedef struct _EventPipeSession EventPipeSession; -typedef struct _EventPipeSessionProvider EventPipeSessionProvider; -typedef struct _EventPipeSessionProviderList EventPipeSessionProviderList; -typedef struct _EventPipeSequencePoint EventPipeSequencePoint; -typedef struct _EventPipeSequencePointBlock EventPipeSequencePointBlock; -typedef struct _EventPipeStackBlock EventPipeStackBlock; -typedef struct _EventPipeStackContents EventPipeStackContents; -typedef struct _EventPipeSystemTime EventPipeSystemTime; -typedef struct _EventPipeThread EventPipeThread; -typedef struct _EventPipeThreadHolder EventPipeThreadHolder; -typedef struct _EventPipeThreadSessionState EventPipeThreadSessionState; -typedef struct _FastSerializableObject FastSerializableObject; -typedef struct _FastSerializableObjectVtable FastSerializableObjectVtable; -typedef struct _FastSerializer FastSerializer; -typedef struct _FileStream FileStream; -typedef struct _FileStreamWriter FileStreamWriter; -typedef struct _IpcStreamWriter IpcStreamWriter; -typedef struct _StackHashEntry StackHashEntry; -typedef struct _StackHashKey StackHashKey; -typedef struct _StreamWriter StreamWriter; -typedef struct _StreamWriterVtable StreamWriterVtable; - -#define EP_MAX_NUMBER_OF_SESSIONS 64 - -#define EP_GUID_SIZE 16 - -#define EP_ACTIVITY_ID_SIZE EP_GUID_SIZE - -#define EP_MAX_STACK_DEPTH 100 - -/* - * EventPipe Enums. - */ - -typedef enum { - EP_BUFFER_STATE_WRITABLE = 0, - EP_BUFFER_STATE_READ_ONLY = 1 -} EventPipeBufferState; - -typedef enum { - EP_EVENT_LEVEL_LOGALWAYS, - EP_EVENT_LEVEL_CRITICAL, - EP_EVENT_LEVEL_ERROR, - EP_EVENT_LEVEL_WARNING, - EP_EVENT_LEVEL_INFORMATIONAL, - EP_EVENT_LEVEL_VERBOSE -} EventPipeEventLevel; - -typedef enum { - EP_FILE_FLUSH_FLAGS_EVENT_BLOCK = 1, - EP_FILE_FLUSH_FLAGS_METADATA_BLOCK = 2, - EP_FILE_FLUSH_FLAGS_STACK_BLOCK = 4, - EP_FILE_FLUSH_FLAGS_ALL_BLOCKS = EP_FILE_FLUSH_FLAGS_EVENT_BLOCK | EP_FILE_FLUSH_FLAGS_METADATA_BLOCK | EP_FILE_FLUSH_FLAGS_STACK_BLOCK -} EventPipeFileFlushFlags; - -// Represents the type of an event parameter. -// This enum is derived from the managed TypeCode type, though -// not all of these values are available in TypeCode. -// For example, Guid does not exist in TypeCode. -// Keep this in sync with COR_PRF_EVENTPIPE_PARAM_TYPE defined in -// corprof.idl -typedef enum { - EP_PARAMETER_TYPE_EMPTY = 0, // Null reference - EP_PARAMETER_TYPE_OBJECT = 1, // Instance that isn't a value - EP_PARAMETER_TYPE_DB_NULL = 2, // Database null value - EP_PARAMETER_TYPE_BOOLEAN = 3, // Boolean - EP_PARAMETER_TYPE_CHAR = 4, // Unicode character - EP_PARAMETER_TYPE_SBYTE = 5, // Signed 8-bit integer - EP_PARAMETER_TYPE_BYTE = 6, // Unsigned 8-bit integer - EP_PARAMETER_TYPE_INT16 = 7, // Signed 16-bit integer - EP_PARAMETER_TYPE_UINT16 = 8, // Unsigned 16-bit integer - EP_PARAMETER_TYPE_INT32 = 9, // Signed 32-bit integer - EP_PARAMETER_TYPE_UINT32 = 10, // Unsigned 32-bit integer - EP_PARAMETER_TYPE_INT64 = 11, // Signed 64-bit integer - EP_PARAMETER_TYPE_UINT64 = 12, // Unsigned 64-bit integer - EP_PARAMETER_TYPE_SINGLE = 13, // IEEE 32-bit float - EP_PARAMETER_TYPE_DOUBLE = 14, // IEEE 64-bit double - EP_PARAMETER_TYPE_DECIMAL = 15, // Decimal - EP_PARAMETER_TYPE_DATE_TIME = 16, // DateTime - EP_PARAMETER_TYPE_GUID = 17, // Guid - EP_PARAMETER_TYPE_STRING = 18, // Unicode character string - EP_PARAMETER_TYPE_ARRAY = 19 // Indicates the type is an arbitrary sized array -} EventPipeParameterType; - -typedef enum { - EP_METADATA_TAG_OPCODE = 1, - EP_METADATA_TAG_PARAMETER_PAYLOAD = 2 -} EventPipeMetadataTag; - -typedef enum { - EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR = 0, - EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL = 1, - EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED = 2 -} EventPipeSampleProfilerSampleType; - -typedef enum { - // Default format used in .Net Core 2.0-3.0 Preview 6 - // TBD - it may remain the default format .Net Core 3.0 when - // used with private EventPipe managed API via reflection. - // This format had limited official exposure in documented - // end-user RTM scenarios, but it is supported by PerfView, - // TraceEvent, and was used by AI profiler. - EP_SERIALIZATION_FORMAT_NETPERF_V3, - // Default format we plan to use in .Net Core 3 Preview7+ - // for most if not all scenarios. - EP_SERIALIZATION_FORMAT_NETTRACE_V4, - EP_SERIALIZATION_FORMAT_COUNT -} EventPipeSerializationFormat; - -typedef enum { - EP_SESSION_TYPE_FILE, - EP_SESSION_TYPE_LISTENER, - EP_SESSION_TYPE_IPCSTREAM, - EP_SESSION_TYPE_SYNCHRONOUS -} EventPipeSessionType ; - -typedef enum { - EP_STATE_NOT_INITIALIZED, - EP_STATE_INITIALIZED, - EP_STATE_SHUTTING_DOWN -} EventPipeState; - -typedef enum { - EP_THREAD_TYPE_SERVER, - EP_THREAD_TYPE_SESSION, - EP_THREAD_TYPE_SAMPLING -} EventPipeThreadType; - -/* - * EventPipe Basic Types. - */ - -typedef intptr_t EventPipeWaitHandle; -typedef uint64_t EventPipeSessionID; -typedef unsigned short ep_char16_t; -typedef int64_t ep_timestamp_t; -typedef int64_t ep_system_timestamp_t; +#include "ep-types-forward.h" #include "ep-rt-types.h" -/* - * EventPipe Callbacks. - */ - -// Define the event pipe callback to match the ETW callback signature. -typedef void (*EventPipeCallback)( - const uint8_t *source_id, - unsigned long is_enabled, - uint8_t level, - uint64_t match_any_keywords, - uint64_t match_all_keywords, - EventFilterDescriptor *filter_data, - void *callback_data); - -typedef void (*EventPipeCallbackDataFree)( - EventPipeCallback callback, - void *callback_data); - -typedef void (*EventPipeSessionSynchronousCallback)( - EventPipeProvider *provider, - uint32_t event_id, - uint32_t event_version, - uint32_t metadata_blob_len, - const uint8_t *metadata_blob, - uint32_t event_data_len, - const uint8_t *event_data, - const uint8_t *activity_id, - const uint8_t *related_activity_id, - ep_rt_thread_handle_t event_thread, - uint32_t stack_frames_len, - uintptr_t *stack_frames); - /* * EventFilterDescriptor. */ diff --git a/src/native/eventpipe/ep.c b/src/native/eventpipe/ep.c index 5517c7d98fcc75..9552dd59eb11a3 100644 --- a/src/native/eventpipe/ep.c +++ b/src/native/eventpipe/ep.c @@ -20,6 +20,8 @@ static bool _ep_can_start_threads = false; static ep_rt_session_id_array_t _ep_deferred_enable_session_ids = { 0 }; static ep_rt_session_id_array_t _ep_deferred_disable_session_ids = { 0 }; +static EventPipeIpcStreamFactorySuspendedPortsCallback _ep_ipc_stream_factory_suspended_ports_callback = NULL; + /* * Forward declares of all static functions. */ @@ -842,8 +844,7 @@ static bool ipc_stream_factory_any_suspended_ports (void) { - extern bool ds_ipc_stream_factory_any_suspended_ports (void); - return ds_ipc_stream_factory_any_suspended_ports (); + return _ep_ipc_stream_factory_suspended_ports_callback ? _ep_ipc_stream_factory_suspended_ports_callback () : false; } #ifdef EP_CHECKED_BUILD @@ -1523,6 +1524,12 @@ ep_system_time_set ( system_time->milliseconds = milliseconds; } +void +ep_ipc_stream_factory_callback_set (EventPipeIpcStreamFactorySuspendedPortsCallback suspended_ports_callback) +{ + _ep_ipc_stream_factory_suspended_ports_callback = suspended_ports_callback; +} + #endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ #endif /* ENABLE_PERFTRACING */ diff --git a/src/native/eventpipe/ep.h b/src/native/eventpipe/ep.h index cfb99aa9d65a92..fb2dafd246924c 100644 --- a/src/native/eventpipe/ep.h +++ b/src/native/eventpipe/ep.h @@ -337,6 +337,13 @@ ep_system_time_get (EventPipeSystemTime *system_time) ep_rt_system_time_get (system_time); } +/* + * EventPipeIpcStreamFactoryCallback. + */ + +void +ep_ipc_stream_factory_callback_set (EventPipeIpcStreamFactorySuspendedPortsCallback suspended_ports_callback); + #else /* ENABLE_PERFTRACING */ static diff --git a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs index af036e41e27375..7667f0ae6fe8e4 100644 --- a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs +++ b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -33,6 +33,11 @@ public class AndroidAppBuilderTask : Task /// public bool ForceAOT { get; set; } + /// + /// List of components to static link, if available + /// + public string? StaticLinkedComponentNames { get; set; } = ""!; + [Required] public string RuntimeIdentifier { get; set; } = ""!; @@ -90,6 +95,7 @@ public override bool Execute() apkBuilder.KeyStorePath = KeyStorePath; apkBuilder.ForceInterpreter = ForceInterpreter; apkBuilder.ForceAOT = ForceAOT; + apkBuilder.StaticLinkedComponentNames = StaticLinkedComponentNames; apkBuilder.Assemblies = Assemblies; (ApkBundlePath, ApkPackageId) = apkBuilder.BuildApk(abi, MainLibraryFileName, MonoRuntimeHeaders); diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index 0ce54fd15c1d6d..67e5cd7c6a5c2c 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -24,6 +24,7 @@ public class ApkBuilder public string? KeyStorePath { get; set; } public bool ForceInterpreter { get; set; } public bool ForceAOT { get; set; } + public string? StaticLinkedComponentNames { get; set; } public ITaskItem[] Assemblies { get; set; } = Array.Empty(); public (string apk, string packageId) BuildApk( @@ -171,6 +172,7 @@ public class ApkBuilder // 1. Build libmonodroid.so` via cmake + string nativeLibraries = ""; string monoRuntimeLib = Path.Combine(AppDir, "libmonosgen-2.0.a"); if (!File.Exists(monoRuntimeLib)) { @@ -178,9 +180,56 @@ public class ApkBuilder } else { - monoRuntimeLib = $" {monoRuntimeLib}{Environment.NewLine}"; + nativeLibraries += $"{monoRuntimeLib}{Environment.NewLine}"; } + string[] staticComponentStubLibs = Directory.GetFiles(AppDir, "libmono-component-*-stub-static.a"); + bool staticLinkAllComponents = false; + string[] componentNames = Array.Empty(); + + if (!string.IsNullOrEmpty(StaticLinkedComponentNames) && StaticLinkedComponentNames.Equals("*", StringComparison.OrdinalIgnoreCase)) + staticLinkAllComponents = true; + else if (!string.IsNullOrEmpty(StaticLinkedComponentNames)) + componentNames = StaticLinkedComponentNames.Split(";"); + + // by default, component stubs will be linked and depending on how mono runtime has been build, + // stubs can disable or dynamic load components. + foreach (string staticComponentStubLib in staticComponentStubLibs) + { + string componentLibToLink = staticComponentStubLib; + if (staticLinkAllComponents) + { + // static link component. + componentLibToLink = componentLibToLink.Replace("-stub-static.a", "-static.a", StringComparison.OrdinalIgnoreCase); + } + else + { + foreach (string componentName in componentNames) + { + if (componentLibToLink.Contains(componentName, StringComparison.OrdinalIgnoreCase)) + { + // static link component. + componentLibToLink = componentLibToLink.Replace("-stub-static.a", "-static.a", StringComparison.OrdinalIgnoreCase); + break; + } + } + } + + // if lib doesn't exist (primarly due to runtime build without static lib support), fallback linking stub lib. + if (!File.Exists(componentLibToLink)) + { + Utils.LogInfo($"\nCouldn't find static component library: {componentLibToLink}, linking static component stub library: {staticComponentStubLib}.\n"); + componentLibToLink = staticComponentStubLib; + } + + nativeLibraries += $" {componentLibToLink}{Environment.NewLine}"; + } + + // There's a circular dependecy between static mono runtime lib and static component libraries. + // Adding mono runtime lib before and after component libs will resolve issues with undefined symbols + // due to circular dependecy. + nativeLibraries += $" {monoRuntimeLib}{Environment.NewLine}"; + string aotSources = ""; foreach (string asm in assemblerFiles) { @@ -190,7 +239,7 @@ public class ApkBuilder string cmakeLists = Utils.GetEmbeddedResource("CMakeLists-android.txt") .Replace("%MonoInclude%", monoRuntimeHeaders) - .Replace("%NativeLibrariesToLink%", monoRuntimeLib) + .Replace("%NativeLibrariesToLink%", nativeLibraries) .Replace("%AotSources%", aotSources) .Replace("%AotModulesSource%", string.IsNullOrEmpty(aotSources) ? "" : "modules.c"); diff --git a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs index 6affce39e30f5b..85efde52b045fa 100644 --- a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs +++ b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs @@ -126,6 +126,11 @@ public string TargetOS /// public bool ForceAOT { get; set; } + /// + /// List of components to static link, if available + /// + public string? StaticLinkedComponentNames { get; set; } = ""!; + /// /// Forces the runtime to use the invariant mode /// @@ -199,7 +204,7 @@ public override bool Execute() generator.EnableRuntimeLogging = EnableRuntimeLogging; XcodeProjectPath = generator.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, - AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, Optimized, NativeMainSource); + AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, ForceAOT, ForceInterpreter, InvariantGlobalization, Optimized, StaticLinkedComponentNames, NativeMainSource); if (BuildAppBundle) { diff --git a/src/tasks/AppleAppBuilder/Xcode.cs b/src/tasks/AppleAppBuilder/Xcode.cs index 442eb539af38b2..90bf0ff56ab2aa 100644 --- a/src/tasks/AppleAppBuilder/Xcode.cs +++ b/src/tasks/AppleAppBuilder/Xcode.cs @@ -53,6 +53,7 @@ public string GenerateXCode( bool forceInterpreter, bool invariantGlobalization, bool stripDebugSymbols, + string? staticLinkedComponentNames=null, string? nativeMainSource = null) { // bundle everything as resources excluding native files @@ -102,11 +103,58 @@ public string GenerateXCode( .Replace("%MonoInclude%", monoInclude) .Replace("%HardenedRuntime%", hardenedRuntime ? "TRUE" : "FALSE"); + string toLink = ""; + + string[] allComponentLibs = Directory.GetFiles(workspace, "libmono-component-*-static.a"); + string[] staticComponentStubLibs = Directory.GetFiles(workspace, "libmono-component-*-stub-static.a"); + bool staticLinkAllComponents = false; + string[] componentNames = Array.Empty(); + + if (!string.IsNullOrEmpty(staticLinkedComponentNames) && staticLinkedComponentNames.Equals("*", StringComparison.OrdinalIgnoreCase)) + staticLinkAllComponents = true; + else if (!string.IsNullOrEmpty(staticLinkedComponentNames)) + componentNames = staticLinkedComponentNames.Split(";"); + + // by default, component stubs will be linked and depending on how mono runtime has been build, + // stubs can disable or dynamic load components. + foreach (string staticComponentStubLib in staticComponentStubLibs) + { + string componentLibToLink = staticComponentStubLib; + if (staticLinkAllComponents) + { + // static link component. + componentLibToLink = componentLibToLink.Replace("-stub-static.a", "-static.a", StringComparison.OrdinalIgnoreCase); + } + else + { + foreach (string componentName in componentNames) + { + if (componentLibToLink.Contains(componentName, StringComparison.OrdinalIgnoreCase)) + { + // static link component. + componentLibToLink = componentLibToLink.Replace("-stub-static.a", "-static.a", StringComparison.OrdinalIgnoreCase); + break; + } + } + } + + // if lib doesn't exist (primarly due to runtime build without static lib support), fallback linking stub lib. + if (!File.Exists(componentLibToLink)) + { + Utils.LogInfo($"\nCouldn't find static component library: {componentLibToLink}, linking static component stub library: {staticComponentStubLib}.\n"); + componentLibToLink = staticComponentStubLib; + } + + toLink += $" \"-force_load {componentLibToLink}\"{Environment.NewLine}"; + } string[] dylibs = Directory.GetFiles(workspace, "*.dylib"); - string toLink = ""; foreach (string lib in Directory.GetFiles(workspace, "*.a")) { + // all component libs already added to linker. + if (allComponentLibs.Any(lib.Contains)) + continue; + string libName = Path.GetFileNameWithoutExtension(lib); // libmono must always be statically linked, for other librarires we can use dylibs bool dylibExists = libName != "libmonosgen-2.0" && dylibs.Any(dylib => Path.GetFileName(dylib) == libName + ".dylib");