Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/mono
diff options
context:
space:
mode:
authorAleksey Kliger (λgeek) <aleksey@lambdageek.org>2022-08-08 21:29:15 +0300
committerGitHub <noreply@github.com>2022-08-08 21:29:15 +0300
commit89db9c050b1baa7a8be686a128b1b8a93d084a0a (patch)
treeac8ea8cf1702d1367e012948febfdd3baba86f35 /src/mono
parenta688d43a1035c9d60c2f0050883b31774bbb66c9 (diff)
[wasm-ep] Use DOTNET_DiagnosticPorts to configure Diagnostic Server (#73370)
* [wasm-ep] Use DOTNET_DiagnosticPorts to configure Diagnostic Server Parse it the same way that the C code does: ``` <uri>[,<connect|listen>][,<suspend|nosuspend>] ``` - uri should be a websocket uri - listen is not supported as it doesn't make sense with a WebSocket - connect is the default if omitted - suspend is the default if omitted --- Additionally, move `mono_wasm_diagnostics_init` to later in the startup flow. This gives Blazor a chance to set DOTNET_DiagnosticPorts from their `onRuntimeInitialized` callback. Fixes https://github.com/dotnet/runtime/issues/73011 * Initialize diagnostic server in different places for Blazor and non-Blazor It has to be after environment variables are set, but before mono_wasm_load_runtime is called. There is no good place that's common to both startup paths. Try it on both. Use a flag to make diagnostics initialization run at most once * update browser-eventpipe sample to use DOTNET_DiagnosticPorts * remove unused imports
Diffstat (limited to 'src/mono')
-rw-r--r--src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj22
-rw-r--r--src/mono/wasm/runtime/cwraps.ts4
-rw-r--r--src/mono/wasm/runtime/diagnostics/index.ts87
-rw-r--r--src/mono/wasm/runtime/driver.c6
-rw-r--r--src/mono/wasm/runtime/memory.ts16
-rw-r--r--src/mono/wasm/runtime/startup.ts18
6 files changed, 128 insertions, 25 deletions
diff --git a/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj b/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj
index f3feef21cce..eb58b28f8cf 100644
--- a/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj
+++ b/src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj
@@ -20,25 +20,19 @@
<ItemGroup>
<WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraFilesToDeploy Include="mock.js" Condition="'$(MonoDiagnosticsMock)' == 'true'"/>
- <WasmExtraConfig Condition="true" Include="environmentVariables" Value='
-{
- "MONO_LOG_LEVEL": "warning",
- "MONO_LOG_MASK": "all"
-}' />
<!-- this option requires running dotnet-dsrouter and a real dotnet-trace client -->
- <WasmExtraConfig Condition="true and '$(MonoDiagnosticsMock)' != 'true'" Include="diagnosticOptions" Value='
+ <WasmExtraConfig Condition="'$(MonoDiagnosticsMock)' != 'true'" Include="environmentVariables" Value='
{
- "server": { "suspend": true, "connectUrl": "ws://localhost:8088/diagnostics" }
+ "MONO_LOG_LEVEL": "warning",
+ "MONO_LOG_MASK": "all",
+ "DOTNET_DiagnosticPorts": "ws://localhost:8088/diagnostics,suspend"
}' />
<!-- this option requires compiling the runtime with /p:MonoDiagnosticsMock=true and also building this project with the same property-->
- <WasmExtraConfig Condition="true and '$(MonoDiagnosticsMock)' == 'true'" Include="diagnosticOptions" Value='
+ <WasmExtraConfig Condition="'$(MonoDiagnosticsMock)' == 'true'" Include="environmentVariables" Value='
{
- "server": { "suspend": false, "connectUrl": "mock:./mock.js" }
-}' />
- <!-- this option will create an EventPipe session at startup, that will dump its data into the Emscripten VFS -->
- <WasmExtraConfig Condition="false" Include="diagnosticOptions" Value='
-{
- "sessions": [ { "collectRundownEvents": "true", "providers": "WasmHello::5:EventCounterIntervalSec=1" } ]
+ "MONO_LOG_LEVEL": "warning",
+ "MONO_LOG_MASK": "all",
+ "DOTNET_DiagnosticPorts": "mock:./mock.js,suspend"
}' />
</ItemGroup>
diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts
index ccc2e72d23f..d65947d498c 100644
--- a/src/mono/wasm/runtime/cwraps.ts
+++ b/src/mono/wasm/runtime/cwraps.ts
@@ -81,6 +81,7 @@ const fn_signatures: SigLine[] = [
//INTERNAL
[false, "mono_wasm_exit", "void", ["number"]],
+ [true, "mono_wasm_getenv", "number", ["string"]],
[true, "mono_wasm_set_main_args", "void", ["number", "number"]],
[false, "mono_wasm_enable_on_demand_gc", "void", ["number"]],
[false, "mono_profiler_init_aot", "void", ["number"]],
@@ -189,6 +190,7 @@ export interface t_Cwraps {
//INTERNAL
mono_wasm_exit(exit_code: number): number;
+ mono_wasm_getenv(name: string): CharPtr;
mono_wasm_enable_on_demand_gc(enable: number): void;
mono_wasm_set_main_args(argc: number, argv: VoidPtr): void;
mono_profiler_init_aot(desc: string): void;
@@ -232,4 +234,4 @@ export function init_c_exports(): void {
wf[name] = fce;
}
}
-} \ No newline at end of file
+}
diff --git a/src/mono/wasm/runtime/diagnostics/index.ts b/src/mono/wasm/runtime/diagnostics/index.ts
index 20300048931..68f79ed9f01 100644
--- a/src/mono/wasm/runtime/diagnostics/index.ts
+++ b/src/mono/wasm/runtime/diagnostics/index.ts
@@ -94,12 +94,25 @@ export const diagnostics: Diagnostics = getDiagnostics();
let suspendOnStartup = false;
let diagnosticsServerEnabled = false;
-export async function mono_wasm_init_diagnostics(options: DiagnosticOptions): Promise<void> {
+let diagnosticsInitialized = false;
+
+export async function mono_wasm_init_diagnostics(opts: "env" | DiagnosticOptions): Promise<void> {
+ if (diagnosticsInitialized)
+ return;
if (!monoWasmThreads) {
- console.warn("MONO_WASM: ignoring diagnostics options because this runtime does not support diagnostics", options);
+ console.warn("MONO_WASM: ignoring diagnostics options because this runtime does not support diagnostics", opts);
return;
} else {
- if (!is_nullish(options.server)) {
+ let options: DiagnosticOptions | null;
+ if (opts === "env") {
+ options = diagnostic_options_from_environment();
+ if (!options)
+ return;
+ } else {
+ options = opts;
+ }
+ diagnosticsInitialized = true;
+ if (!is_nullish(options?.server)) {
if (options.server.connectUrl === undefined || typeof (options.server.connectUrl) !== "string") {
throw new Error("server.connectUrl must be a string");
}
@@ -130,6 +143,74 @@ function boolsyOption(x: string | boolean): boolean {
throw new Error(`invalid option: "${x}", should be true, false, or "true" or "false"`);
}
+/// Parse environment variables for diagnostics configuration
+///
+/// The environment variables are:
+/// * DOTNET_DiagnosticPorts
+///
+function diagnostic_options_from_environment(): DiagnosticOptions | null {
+ const val = memory.getEnv("DOTNET_DiagnosticPorts");
+ if (is_nullish(val))
+ return null;
+ // TODO: consider also parsing the DOTNET_EnableEventPipe and DOTNET_EventPipeOutputPath, DOTNET_EvnetPipeConfig variables
+ // to configure the startup sessions that will dump output to the VFS.
+ return diagnostic_options_from_ports_spec(val);
+}
+
+/// Parse a DOTNET_DiagnosticPorts string and return a DiagnosticOptions object.
+/// See https://docs.microsoft.com/en-us/dotnet/core/diagnostics/diagnostic-port#configure-additional-diagnostic-ports
+function diagnostic_options_from_ports_spec(val: string): DiagnosticOptions | null {
+ if (val === "")
+ return null;
+ const ports = val.split(";");
+ if (ports.length === 0)
+ return null;
+ if (ports.length !== 1) {
+ console.warn("MONO_WASM: multiple diagnostic ports specified, only the last one will be used");
+ }
+ const portSpec = ports[ports.length - 1];
+ const components = portSpec.split(",");
+ if (components.length < 1 || components.length > 3) {
+ console.warn("MONO_WASM: invalid diagnostic port specification, should be of the form <port>[,<connect>],[<nosuspend|suspend>]");
+ return null;
+ }
+ const uri: string = components[0];
+ let connect = true;
+ let suspend = true;
+ // the C Diagnostic Server goes through these parts in reverse, do the same here.
+ for (let i = components.length - 1; i >= 1; i--) {
+ const component = components[i];
+ switch (component.toLowerCase()) {
+ case "nosuspend":
+ suspend = false;
+ break;
+ case "suspend":
+ suspend = true;
+ break;
+ case "listen":
+ connect = false;
+ break;
+ case "connect":
+ connect = true;
+ break;
+ default:
+ console.warn(`MONO_WASM: invalid diagnostic port specification component: ${component}`);
+ break;
+ }
+ }
+ if (!connect) {
+ console.warn("MONO_WASM: this runtime does not support listening on a diagnostic port; no diagnostic server started");
+ return null;
+ }
+ return {
+ server: {
+ connectUrl: uri,
+ suspend: suspend,
+ }
+ };
+
+}
+
export function mono_wasm_diagnostic_server_on_runtime_server_init(out_options: VoidPtr): void {
if (diagnosticsServerEnabled) {
/* called on the main thread when the runtime is sufficiently initialized */
diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c
index a4108177548..0ddc467ae59 100644
--- a/src/mono/wasm/runtime/driver.c
+++ b/src/mono/wasm/runtime/driver.c
@@ -281,6 +281,12 @@ mono_wasm_setenv (const char *name, const char *value)
monoeg_g_setenv (strdup (name), strdup (value), 1);
}
+EMSCRIPTEN_KEEPALIVE char *
+mono_wasm_getenv (const char *name)
+{
+ return monoeg_g_getenv (name); // JS must free
+}
+
static void *sysglobal_native_handle;
static void*
diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts
index 95373c22fb7..2ac62de35f7 100644
--- a/src/mono/wasm/runtime/memory.ts
+++ b/src/mono/wasm/runtime/memory.ts
@@ -1,7 +1,7 @@
import monoWasmThreads from "consts:monoWasmThreads";
import { Module, runtimeHelpers } from "./imports";
import { mono_assert, MemOffset, NumberOrPointer } from "./types";
-import { VoidPtr } from "./types/emscripten";
+import { VoidPtr, CharPtr } from "./types/emscripten";
import * as cuint64 from "./cuint64";
import cwraps, { I52Error } from "./cwraps";
@@ -263,6 +263,18 @@ export function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr {
return memoryOffset;
}
+export function getEnv(name: string): string | null {
+ let charPtr: CharPtr = <any>0;
+ try {
+ charPtr = cwraps.mono_wasm_getenv(name);
+ if (<any>charPtr === 0)
+ return null;
+ else return Module.UTF8ToString(charPtr);
+ } finally {
+ if (charPtr) Module._free(<any>charPtr);
+ }
+}
+
const BuiltinAtomics = globalThis.Atomics;
export const Atomics = monoWasmThreads ? {
@@ -276,4 +288,4 @@ export const Atomics = monoWasmThreads ? {
} : {
storeI32: setI32,
notifyI32: () => { /*empty*/ }
-}; \ No newline at end of file
+};
diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts
index b6e6f688030..051c0a796c5 100644
--- a/src/mono/wasm/runtime/startup.ts
+++ b/src/mono/wasm/runtime/startup.ts
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+import MonoWasmThreads from "consts:monoWasmThreads";
import { mono_assert, CharPtrNull, DotnetModule, MonoConfig, MonoConfigError, LoadingResource, AssetEntry, ResourceRequest } from "./types";
import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, INTERNAL, Module, runtimeHelpers } from "./imports";
import cwraps, { init_c_exports } from "./cwraps";
@@ -25,6 +26,7 @@ import { cwraps_internal } from "./exports-internal";
import { cwraps_binding_api, cwraps_mono_api } from "./net6-legacy/exports-legacy";
import { DotnetPublicAPI } from "./export-types";
import { BINDING, MONO } from "./net6-legacy/imports";
+import { mono_wasm_init_diagnostics } from "./diagnostics";
let all_assets_loaded_in_memory: Promise<void> | null = null;
const loaded_files: { url: string, file: string }[] = [];
@@ -130,8 +132,8 @@ function preInit(isCustomStartup: boolean, userPreInit: (() => void)[]) {
abort_startup(err, true);
throw err;
}
- // this will start immediately but return on first await.
- // It will block our `preRun` by afterPreInit promise
+ // this will start immediately but return on first await.
+ // It will block our `preRun` by afterPreInit promise
// It will block emscripten `userOnRuntimeInitialized` by pending addRunDependency("mono_pre_init")
(async () => {
try {
@@ -196,7 +198,7 @@ async function onRuntimeInitializedAsync(isCustomStartup: boolean, userOnRuntime
_print_error("MONO_WASM: user callback onRuntimeInitialized() failed", err);
throw err;
}
- // finish
+ // finish
await mono_wasm_after_user_runtime_initialized();
} catch (err) {
_print_error("MONO_WASM: onRuntimeInitializedAsync() failed", err);
@@ -326,6 +328,10 @@ async function mono_wasm_after_user_runtime_initialized(): Promise<void> {
}
}
}
+ // for Blazor, init diagnostics after their "onRuntimeInitalized" sets env variables, but before their postRun callback (which calls mono_wasm_load_runtime)
+ if (MonoWasmThreads) {
+ await mono_wasm_init_diagnostics("env");
+ }
if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: Initializing mono runtime");
@@ -532,8 +538,10 @@ async function _apply_configuration_from_args() {
if (config.coverageProfilerOptions)
mono_wasm_init_coverage_profiler(config.coverageProfilerOptions);
-
- // FIXME await mono_wasm_init_diagnostics(config.diagnosticOptions);
+ // for non-Blazor, init diagnostics after environment variables are set
+ if (MonoWasmThreads) {
+ await mono_wasm_init_diagnostics("env");
+ }
}
export function mono_wasm_load_runtime(unused?: string, debugLevel?: number): void {