diff --git a/src/mono/browser/runtime/cwraps.ts b/src/mono/browser/runtime/cwraps.ts
index fe7ae5269f2f9..29d384f65795b 100644
--- a/src/mono/browser/runtime/cwraps.ts
+++ b/src/mono/browser/runtime/cwraps.ts
@@ -9,7 +9,7 @@ import type {
MonoType, MonoObjectRef, MonoStringRef, JSMarshalerArguments
} from "./types/internal";
import type { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr, ManagedPointer } from "./types/emscripten";
-import { linkerEnableAotProfiler, linkerEnableBrowserProfiler, Module } from "./globals";
+import { Module, runtimeHelpers } from "./globals";
import { mono_log_error } from "./logging";
import { mono_assert } from "./globals";
@@ -60,8 +60,8 @@ const fn_signatures: SigLine[] = [
[true, "mono_wasm_getenv", "number", ["string"]],
[true, "mono_wasm_set_main_args", "void", ["number", "number"]],
// These two need to be lazy because they may be missing
- [() => !linkerEnableAotProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
- [() => !linkerEnableBrowserProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
+ [() => !runtimeHelpers.emscriptenBuildOptions.enableAotProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
+ [() => !runtimeHelpers.emscriptenBuildOptions.enableBrowserProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
[true, "mono_wasm_profiler_init_browser", "void", ["number"]],
[false, "mono_wasm_exec_regression", "number", ["number", "string"]],
[false, "mono_wasm_invoke_method_bound", "number", ["number", "number", "number"]],
diff --git a/src/mono/browser/runtime/dotnet.d.ts b/src/mono/browser/runtime/dotnet.d.ts
index 0d8f2833e3674..406deb7e4bf94 100644
--- a/src/mono/browser/runtime/dotnet.d.ts
+++ b/src/mono/browser/runtime/dotnet.d.ts
@@ -609,6 +609,9 @@ type RuntimeAPI = {
productVersion: string;
gitHash: string;
buildConfiguration: string;
+ wasmEnableThreads: boolean;
+ wasmEnableSIMD: boolean;
+ wasmEnableExceptionHandling: boolean;
};
} & APIType;
type ModuleAPI = {
diff --git a/src/mono/browser/runtime/driver.c b/src/mono/browser/runtime/driver.c
index bb95a67097351..a7bd6f5966e0b 100644
--- a/src/mono/browser/runtime/driver.c
+++ b/src/mono/browser/runtime/driver.c
@@ -189,19 +189,6 @@ mono_wasm_load_runtime (const char *unused, int debug_level)
mono_wasm_link_icu_shim ();
#endif
-#ifndef DISABLE_THREADS
- monoeg_g_setenv ("MONO_SLEEP_ABORT_LIMIT", "5000", 0);
-#endif
-
- // monoeg_g_setenv ("DOTNET_DebugWriteToStdErr", "1", 0);
-
-#ifdef DEBUG
- // monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0);
- // monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0);
- // Setting this env var allows Diagnostic.Debug to write to stderr. In a browser environment this
- // output will be sent to the console. Right now this is the only way to emit debug logging from
- // corlib assemblies.
-#endif
// When the list of app context properties changes, please update RuntimeConfigReservedProperties for
// target _WasmGenerateRuntimeConfig in BrowserWasmApp.targets file
const char *appctx_keys[2];
@@ -372,7 +359,10 @@ mono_wasm_exec_regression (int verbose_level, char *image)
EMSCRIPTEN_KEEPALIVE int
mono_wasm_exit (int exit_code)
{
- mono_jit_cleanup (root_domain);
+ if (exit_code == 0)
+ {
+ mono_jit_cleanup (root_domain);
+ }
fflush (stdout);
fflush (stderr);
emscripten_force_exit (exit_code);
diff --git a/src/mono/browser/runtime/es6/dotnet.es6.lib.js b/src/mono/browser/runtime/es6/dotnet.es6.lib.js
index 0a9236a11d3ba..cc1944eeed984 100644
--- a/src/mono/browser/runtime/es6/dotnet.es6.lib.js
+++ b/src/mono/browser/runtime/es6/dotnet.es6.lib.js
@@ -15,7 +15,7 @@ const RUN_AOT_COMPILATION = process.env.RUN_AOT_COMPILATION === "1";
var methodIndexByName = undefined;
var gitHash = undefined;
-function setup(linkerSetup) {
+function setup(emscriptenBuildOptions) {
// USE_PTHREADS is emscripten's define symbol, which is passed to acorn optimizer, so we could use it here
#if USE_PTHREADS
const modulePThread = PThread;
@@ -43,8 +43,7 @@ function setup(linkerSetup) {
updateMemoryViews,
getMemory: () => { return wasmMemory; },
getWasmIndirectFunctionTable: () => { return wasmTable; },
- ...linkerSetup
- });
+ }, emscriptenBuildOptions);
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) {
@@ -83,11 +82,12 @@ function injectDependencies() {
#endif
DotnetSupportLib["$DOTNET__postset"] = `DOTNET.setup({ ` +
- `linkerWasmEnableSIMD: ${WASM_ENABLE_SIMD ? "true" : "false"},` +
- `linkerWasmEnableEH: ${WASM_ENABLE_EH ? "true" : "false"},` +
- `linkerEnableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` +
- `linkerEnableBrowserProfiler: ${ENABLE_BROWSER_PROFILER ? "true" : "false"}, ` +
- `linkerRunAOTCompilation: ${RUN_AOT_COMPILATION ? "true" : "false"}, ` +
+ `wasmEnableSIMD: ${WASM_ENABLE_SIMD ? "true" : "false"},` +
+ `wasmEnableEH: ${WASM_ENABLE_EH ? "true" : "false"},` +
+ `enableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` +
+ `enableBrowserProfiler: ${ENABLE_BROWSER_PROFILER ? "true" : "false"}, ` +
+ `runAOTCompilation: ${RUN_AOT_COMPILATION ? "true" : "false"}, ` +
+ `wasmEnableThreads: ${USE_PTHREADS ? "true" : "false"}, ` +
`gitHash: "${gitHash}", ` +
`});`;
@@ -96,4 +96,4 @@ function injectDependencies() {
}
-// var methodIndexByName wil be appended below by the MSBuild in browser.proj
+// var methodIndexByName wil be appended below by the MSBuild in browser.proj via exports-linker.ts
diff --git a/src/mono/browser/runtime/exports-binding.ts b/src/mono/browser/runtime/exports-binding.ts
index 58ddb435f41ed..cb286789879b6 100644
--- a/src/mono/browser/runtime/exports-binding.ts
+++ b/src/mono/browser/runtime/exports-binding.ts
@@ -12,7 +12,7 @@ import { mono_interp_jit_wasm_entry_trampoline, mono_interp_record_interp_entry
import { mono_interp_jit_wasm_jit_call_trampoline, mono_interp_invoke_wasm_jit_call_trampoline, mono_interp_flush_jitcall_queue } from "./jiterpreter-jit-call";
import { mono_wasm_resolve_or_reject_promise } from "./marshal-to-js";
import { mono_wasm_eventloop_has_unsettled_interop_promises } from "./pthreads/shared/eventloop";
-import { mono_wasm_pthread_on_pthread_attached, mono_wasm_pthread_on_pthread_unregistered, mono_wasm_pthread_on_pthread_registered } from "./pthreads/worker";
+import { mono_wasm_pthread_on_pthread_attached, mono_wasm_pthread_on_pthread_unregistered, mono_wasm_pthread_on_pthread_registered, mono_wasm_pthread_set_name } from "./pthreads/worker";
import { mono_wasm_schedule_timer, schedule_background_exec } from "./scheduling";
import { mono_wasm_asm_loaded } from "./startup";
import { mono_wasm_diagnostic_server_on_server_thread_created } from "./diagnostics/server_pthread";
@@ -37,6 +37,8 @@ export const mono_wasm_threads_imports = !WasmEnableThreads ? [] : [
mono_wasm_pthread_on_pthread_registered,
mono_wasm_pthread_on_pthread_attached,
mono_wasm_pthread_on_pthread_unregistered,
+ mono_wasm_pthread_set_name,
+
// threads.c
mono_wasm_eventloop_has_unsettled_interop_promises,
// diagnostics_server.c
diff --git a/src/mono/browser/runtime/exports.ts b/src/mono/browser/runtime/exports.ts
index 1cea8798bb4b4..2f3aa96a0ec6b 100644
--- a/src/mono/browser/runtime/exports.ts
+++ b/src/mono/browser/runtime/exports.ts
@@ -3,6 +3,10 @@
import ProductVersion from "consts:productVersion";
import BuildConfiguration from "consts:configuration";
+import WasmEnableThreads from "consts:wasmEnableThreads";
+import WasmEnableSIMD from "consts:wasmEnableSIMD";
+import WasmEnableExceptionHandling from "consts:wasmEnableExceptionHandling";
+
import type { RuntimeAPI } from "./types";
import { Module, exportedRuntimeAPI, loaderHelpers, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals";
@@ -18,6 +22,7 @@ import { mono_wasm_stringify_as_error_with_stack } from "./logging";
import { instantiate_asset, instantiate_symbols_asset, instantiate_segmentation_rules_asset } from "./assets";
import { jiterpreter_dump_stats } from "./jiterpreter";
import { forceDisposeProxies } from "./gc-handles";
+import { dumpThreads } from "./pthreads/browser";
export let runtimeList: RuntimeList;
@@ -35,6 +40,11 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
forceDisposeProxies,
instantiate_segmentation_rules_asset,
});
+ if (WasmEnableThreads) {
+ Object.assign(runtimeHelpers, {
+ dumpThreads,
+ });
+ }
const API = export_api();
Object.assign(exportedRuntimeAPI, {
@@ -43,7 +53,10 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
runtimeBuildInfo: {
productVersion: ProductVersion,
gitHash: runtimeHelpers.gitHash,
- buildConfiguration: BuildConfiguration
+ buildConfiguration: BuildConfiguration,
+ wasmEnableThreads: WasmEnableThreads,
+ wasmEnableSIMD: WasmEnableSIMD,
+ wasmEnableExceptionHandling: WasmEnableExceptionHandling,
},
...API,
});
diff --git a/src/mono/browser/runtime/globals.ts b/src/mono/browser/runtime/globals.ts
index bf7b5a01a997b..be2ae8f86bee9 100644
--- a/src/mono/browser/runtime/globals.ts
+++ b/src/mono/browser/runtime/globals.ts
@@ -9,7 +9,7 @@
import gitHash from "consts:gitHash";
import { RuntimeAPI } from "./types/index";
-import type { GlobalObjects, EmscriptenInternals, RuntimeHelpers, LoaderHelpers, DotnetModuleInternal, PromiseAndController } from "./types/internal";
+import type { GlobalObjects, EmscriptenInternals, RuntimeHelpers, LoaderHelpers, DotnetModuleInternal, PromiseAndController, EmscriptenBuildOptions } from "./types/internal";
import { mono_log_error } from "./logging";
// these are our public API (except internal)
@@ -30,23 +30,14 @@ export let exportedRuntimeAPI: RuntimeAPI = null as any;
export let runtimeHelpers: RuntimeHelpers = null as any;
export let loaderHelpers: LoaderHelpers = null as any;
-export let linkerWasmEnableSIMD = true;
-export let linkerWasmEnableEH = true;
-export let linkerEnableAotProfiler = false;
-export let linkerEnableBrowserProfiler = false;
-export let linkerRunAOTCompilation = false;
export let _runtimeModuleLoaded = false; // please keep it in place also as rollup guard
-export function passEmscriptenInternals(internals: EmscriptenInternals): void {
+export function passEmscriptenInternals(internals: EmscriptenInternals, emscriptenBuildOptions: EmscriptenBuildOptions): void {
+ runtimeHelpers.emscriptenBuildOptions = emscriptenBuildOptions;
+
ENVIRONMENT_IS_PTHREAD = internals.isPThread;
- linkerWasmEnableSIMD = internals.linkerWasmEnableSIMD;
- linkerWasmEnableEH = internals.linkerWasmEnableEH;
- linkerEnableAotProfiler = internals.linkerEnableAotProfiler;
- linkerEnableBrowserProfiler = internals.linkerEnableBrowserProfiler;
- linkerRunAOTCompilation = internals.linkerRunAOTCompilation;
runtimeHelpers.quit = internals.quit_;
runtimeHelpers.ExitStatus = internals.ExitStatus;
- runtimeHelpers.moduleGitHash = internals.gitHash;
runtimeHelpers.getMemory = internals.getMemory;
runtimeHelpers.getWasmIndirectFunctionTable = internals.getWasmIndirectFunctionTable;
runtimeHelpers.updateMemoryViews = internals.updateMemoryViews;
diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts
index cacd4d306695a..dcbba5928a5bc 100644
--- a/src/mono/browser/runtime/jiterpreter-support.ts
+++ b/src/mono/browser/runtime/jiterpreter-support.ts
@@ -3,7 +3,7 @@
import WasmEnableThreads from "consts:wasmEnableThreads";
import { NativePointer, ManagedPointer, VoidPtr } from "./types/emscripten";
-import { Module, mono_assert, runtimeHelpers, linkerRunAOTCompilation } from "./globals";
+import { Module, mono_assert, runtimeHelpers } from "./globals";
import { WasmOpcode, WasmSimdOpcode, WasmValtype } from "./jiterpreter-opcodes";
import { MintOpcode } from "./mintops";
import cwraps from "./cwraps";
@@ -2017,8 +2017,8 @@ export function jiterpreter_allocate_tables() {
// then create special placeholder functions that examine the rmethod to determine which kind
// of method is being called.
const traceTableSize = options.tableSize,
- jitCallTableSize = linkerRunAOTCompilation ? options.tableSize : 1,
- interpEntryTableSize = linkerRunAOTCompilation ? options.aotTableSize : 1,
+ jitCallTableSize = runtimeHelpers.emscriptenBuildOptions.runAOTCompilation ? options.tableSize : 1,
+ interpEntryTableSize = runtimeHelpers.emscriptenBuildOptions.runAOTCompilation ? options.aotTableSize : 1,
numInterpEntryTables = JiterpreterTable.LAST - JiterpreterTable.InterpEntryStatic0 + 1,
totalSize = traceTableSize + jitCallTableSize + (numInterpEntryTables * interpEntryTableSize) + 1,
wasmTable = getWasmFunctionTable();
diff --git a/src/mono/browser/runtime/loader/config.ts b/src/mono/browser/runtime/loader/config.ts
index 68f62e2261ddd..9364bf706801f 100644
--- a/src/mono/browser/runtime/loader/config.ts
+++ b/src/mono/browser/runtime/loader/config.ts
@@ -193,6 +193,11 @@ export function normalizeConfig() {
config.pthreadPoolSize = 7;
}
+ // this is how long the Mono GC will try to wait for all threads to be suspended before it gives up and aborts the process
+ if (WasmEnableThreads && config.environmentVariables["MONO_SLEEP_ABORT_LIMIT"] === undefined) {
+ config.environmentVariables["MONO_SLEEP_ABORT_LIMIT"] = "5000";
+ }
+
// Default values (when WasmDebugLevel is not set)
// - Build (debug) => debugBuild=true & debugLevel=-1 => -1
// - Build (release) => debugBuild=true & debugLevel=0 => 0
@@ -200,9 +205,10 @@ export function normalizeConfig() {
// - Publish (release) => debugBuild=false & debugLevel=0 => 0
config.debugLevel = hasDebuggingEnabled(config) ? config.debugLevel : 0;
- if (config.diagnosticTracing === undefined && BuildConfiguration === "Debug") {
+ if (BuildConfiguration === "Debug" && config.diagnosticTracing === undefined) {
config.diagnosticTracing = true;
}
+
if (config.applicationCulture) {
// If a culture is specified via start options use that to initialize the Emscripten \ .NET culture.
config.environmentVariables!["LANG"] = `${config.applicationCulture}.UTF-8`;
diff --git a/src/mono/browser/runtime/loader/exit.ts b/src/mono/browser/runtime/loader/exit.ts
index f29bd54d43c10..2078a9f0533ec 100644
--- a/src/mono/browser/runtime/loader/exit.ts
+++ b/src/mono/browser/runtime/loader/exit.ts
@@ -108,6 +108,9 @@ export function mono_exit(exit_code: number, reason?: any): void {
if (exit_code === 0 && loaderHelpers.config?.interopCleanupOnExit) {
runtimeHelpers.forceDisposeProxies(true, true);
}
+ if (WasmEnableThreads && exit_code !== 0 && loaderHelpers.config?.dumpThreadsOnNonZeroExit) {
+ runtimeHelpers.dumpThreads();
+ }
}
}
catch (err) {
diff --git a/src/mono/browser/runtime/loader/globals.ts b/src/mono/browser/runtime/loader/globals.ts
index 8e65efcf4d5b3..ff84a5ddb3581 100644
--- a/src/mono/browser/runtime/loader/globals.ts
+++ b/src/mono/browser/runtime/loader/globals.ts
@@ -13,7 +13,7 @@ import type { MonoConfig, RuntimeAPI } from "../types";
import { assert_runtime_running, installUnhandledErrorHandler, is_exited, is_runtime_running, mono_exit } from "./exit";
import { assertIsControllablePromise, createPromiseController, getPromiseController } from "./promise-controller";
import { mono_download_assets, resolve_single_asset_path, retrieve_asset_download } from "./assets";
-import { mono_log_error, mono_set_thread_name, setup_proxy_console } from "./logging";
+import { mono_log_error, set_thread_prefix, setup_proxy_console } from "./logging";
import { invokeLibraryInitializers } from "./libraryInitializers";
import { deep_merge_config, hasDebuggingEnabled } from "./config";
import { logDownloadStatsToConsole, purgeUnusedCacheEntriesAsync } from "./assetsCache";
@@ -114,7 +114,7 @@ export function setLoaderGlobals(
mono_download_assets,
resolve_single_asset_path,
setup_proxy_console,
- mono_set_thread_name,
+ set_thread_prefix,
logDownloadStatsToConsole,
purgeUnusedCacheEntriesAsync,
installUnhandledErrorHandler,
diff --git a/src/mono/browser/runtime/loader/logging.ts b/src/mono/browser/runtime/loader/logging.ts
index d61e16f5d11c9..723e55201fcc5 100644
--- a/src/mono/browser/runtime/loader/logging.ts
+++ b/src/mono/browser/runtime/loader/logging.ts
@@ -14,8 +14,8 @@ let theConsoleApi: any;
let originalConsoleMethods: any;
let threadNamePrefix: string;
-export function mono_set_thread_name(threadName: string) {
- threadNamePrefix = threadName;
+export function set_thread_prefix(threadPrefix: string) {
+ threadNamePrefix = threadPrefix;
}
export function mono_log_debug(msg: string, ...data: any[]) {
diff --git a/src/mono/browser/runtime/loader/run.ts b/src/mono/browser/runtime/loader/run.ts
index 9a89bac6931af..0466c75a3e0b5 100644
--- a/src/mono/browser/runtime/loader/run.ts
+++ b/src/mono/browser/runtime/loader/run.ts
@@ -125,6 +125,19 @@ export class HostBuilder implements DotnetHostBuilder {
}
}
+ // internal
+ withDumpThreadsOnNonZeroExit(): DotnetHostBuilder {
+ try {
+ deep_merge_config(monoConfig, {
+ dumpThreadsOnNonZeroExit: true
+ });
+ return this;
+ } catch (err) {
+ mono_exit(1, err);
+ throw err;
+ }
+ }
+
// internal
withAssertAfterExit(): DotnetHostBuilder {
try {
diff --git a/src/mono/browser/runtime/logging.ts b/src/mono/browser/runtime/logging.ts
index ff52269a2726f..4e9229796138c 100644
--- a/src/mono/browser/runtime/logging.ts
+++ b/src/mono/browser/runtime/logging.ts
@@ -8,8 +8,8 @@ import { CharPtr, VoidPtr } from "./types/emscripten";
let prefix = "MONO_WASM: ";
-export function mono_set_thread_name(threadName: string) {
- prefix = `[${threadName}] MONO_WASM: `;
+export function set_thread_prefix(threadPrefix: string) {
+ prefix = `[${threadPrefix}] MONO_WASM: `;
}
export function mono_log_debug(msg: string, ...data: any) {
diff --git a/src/mono/browser/runtime/profiler.ts b/src/mono/browser/runtime/profiler.ts
index afc98c51b873b..0567d3a386fe1 100644
--- a/src/mono/browser/runtime/profiler.ts
+++ b/src/mono/browser/runtime/profiler.ts
@@ -1,7 +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 { ENVIRONMENT_IS_WEB, linkerEnableAotProfiler, linkerEnableBrowserProfiler, mono_assert, runtimeHelpers } from "./globals";
+import { ENVIRONMENT_IS_WEB, mono_assert, runtimeHelpers } from "./globals";
import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions } from "./types/internal";
import { profiler_c_functions as cwraps } from "./cwraps";
import { utf8ToString } from "./strings";
@@ -15,7 +15,7 @@ import { utf8ToString } from "./strings";
// DumpAotProfileData stores the data into INTERNAL.aotProfileData.
//
export function mono_wasm_init_aot_profiler(options: AOTProfilerOptions): void {
- mono_assert(linkerEnableAotProfiler, "AOT profiler is not enabled, please use aot; in your project file.");
+ mono_assert(runtimeHelpers.emscriptenBuildOptions.enableAotProfiler, "AOT profiler is not enabled, please use aot; in your project file.");
if (options == null)
options = {};
if (!("writeAt" in options))
@@ -27,7 +27,7 @@ export function mono_wasm_init_aot_profiler(options: AOTProfilerOptions): void {
}
export function mono_wasm_init_browser_profiler(options: BrowserProfilerOptions): void {
- mono_assert(linkerEnableBrowserProfiler, "Browser profiler is not enabled, please use browser; in your project file.");
+ mono_assert(runtimeHelpers.emscriptenBuildOptions.enableBrowserProfiler, "Browser profiler is not enabled, please use browser; in your project file.");
if (options == null)
options = {};
const arg = "browser:";
diff --git a/src/mono/browser/runtime/pthreads/browser/index.ts b/src/mono/browser/runtime/pthreads/browser/index.ts
index f459508a93ef0..e1ea4961a8463 100644
--- a/src/mono/browser/runtime/pthreads/browser/index.ts
+++ b/src/mono/browser/runtime/pthreads/browser/index.ts
@@ -3,11 +3,13 @@
import WasmEnableThreads from "consts:wasmEnableThreads";
-import { MonoWorkerToMainMessage, pthreadPtr } from "../shared/types";
+import { MonoWorkerToMainMessage, PThreadInfo, pthreadPtr } from "../shared/types";
import { MonoThreadMessage } from "../shared";
import { PThreadWorker, allocateUnusedWorker, getRunningWorkers, getUnusedWorkerPool, getWorker, loadWasmModuleToWorker } from "../shared/emscripten-internals";
import { createPromiseController, mono_assert, runtimeHelpers } from "../../globals";
import { MainToWorkerMessageType, PromiseAndController, PromiseController, WorkerToMainMessageType, monoMessageSymbol } from "../../types/internal";
+import { mono_log_info } from "../../logging";
+import { monoThreadInfo } from "../worker";
const threadPromises: Map[]> = new Map();
@@ -101,6 +103,7 @@ function monoWorkerMessageHandler(worker: PThreadWorker, ev: MessageEvent):
case WorkerToMainMessageType.monoAttached:
case WorkerToMainMessageType.enabledInterop:
case WorkerToMainMessageType.monoUnRegistered:
+ case WorkerToMainMessageType.updateInfo:
worker.info = Object.assign(worker.info!, message.info, {});
break;
default:
@@ -168,4 +171,36 @@ export function cancelThreads() {
worker.postMessage({ cmd: "cancel" });
}
}
-}
\ No newline at end of file
+}
+
+export function dumpThreads(): void {
+ if (!WasmEnableThreads) return;
+ mono_log_info("Dumping web worker info as seen by UI thread, it could be stale: ");
+ const emptyInfo = {
+ pthreadId: 0,
+ threadPrefix: " - ",
+ threadName: "????",
+ isRunning: false,
+ isAttached: false,
+ isExternalEventLoop: false,
+ reuseCount: 0,
+ };
+ const threadInfos: PThreadInfo[] = [
+ Object.assign({}, emptyInfo, monoThreadInfo), // UI thread
+ ];
+ for (const worker of getRunningWorkers()) {
+ threadInfos.push(Object.assign({}, emptyInfo, worker.info));
+ }
+ for (const worker of getUnusedWorkerPool()) {
+ threadInfos.push(Object.assign({}, emptyInfo, worker.info));
+ }
+ threadInfos.forEach((info, i) => {
+ const idx = (i + "").padStart(2, "0");
+ const isRunning = (info.isRunning + "").padStart(5, " ");
+ const isAttached = (info.isAttached + "").padStart(5, " ");
+ const isEventLoop = (info.isExternalEventLoop + "").padStart(5, " ");
+ const reuseCount = (info.reuseCount + "").padStart(3, " ");
+ // eslint-disable-next-line no-console
+ console.info(`${idx} | ${info.threadPrefix}: isRunning:${isRunning} isAttached:${isAttached} isEventLoop:${isEventLoop} reuseCount:${reuseCount} - ${info.threadName}`);
+ });
+}
diff --git a/src/mono/browser/runtime/pthreads/shared/emscripten-replacements.ts b/src/mono/browser/runtime/pthreads/shared/emscripten-replacements.ts
index c68de0a52a987..f0bbf80d6636b 100644
--- a/src/mono/browser/runtime/pthreads/shared/emscripten-replacements.ts
+++ b/src/mono/browser/runtime/pthreads/shared/emscripten-replacements.ts
@@ -4,9 +4,9 @@
import WasmEnableThreads from "consts:wasmEnableThreads";
import BuildConfiguration from "consts:configuration";
-import { onWorkerLoadInitiated, resolveThreadPromises } from "../browser";
+import { dumpThreads, onWorkerLoadInitiated, resolveThreadPromises } from "../browser";
import { mono_wasm_pthread_on_pthread_created } from "../worker";
-import { PThreadLibrary, PThreadWorker, getModulePThread, getRunningWorkers, getUnusedWorkerPool } from "./emscripten-internals";
+import { PThreadLibrary, PThreadWorker, getModulePThread, getUnusedWorkerPool } from "./emscripten-internals";
import { loaderHelpers, mono_assert } from "../../globals";
import { mono_log_warn } from "../../logging";
@@ -119,26 +119,10 @@ function allocateUnusedWorker(): PThreadWorker {
pthreadId: 0,
reuseCount: 0,
updateCount: 0,
- threadName: "",
+ threadPrefix: " - ",
+ threadName: "emscripten-pool",
};
return worker;
}
-export function dumpThreads(): void {
- if (!WasmEnableThreads) return;
- // eslint-disable-next-line no-console
- console.log("Running workers:");
- getRunningWorkers().forEach((worker) => {
- // eslint-disable-next-line no-console
- console.log(`${worker.info.threadName}: isRunning:${worker.info.isRunning} isAttached:${worker.info.isAttached} isExternalEventLoop:${worker.info.isExternalEventLoop} ${JSON.stringify(worker.info)}`);
- });
-
- // eslint-disable-next-line no-console
- console.log("Unused workers:");
- getUnusedWorkerPool().forEach((worker) => {
- // eslint-disable-next-line no-console
- console.log(`${worker.info.threadName}: isRunning:${worker.info.isRunning} isAttached:${worker.info.isAttached} isExternalEventLoop:${worker.info.isExternalEventLoop} ${JSON.stringify(worker.info)}`);
- });
-
-}
diff --git a/src/mono/browser/runtime/pthreads/shared/index.ts b/src/mono/browser/runtime/pthreads/shared/index.ts
index 758f1e62b1ba0..d91efc5775173 100644
--- a/src/mono/browser/runtime/pthreads/shared/index.ts
+++ b/src/mono/browser/runtime/pthreads/shared/index.ts
@@ -5,7 +5,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads";
import BuildConfiguration from "consts:configuration";
import { ENVIRONMENT_IS_PTHREAD, Module, loaderHelpers, mono_assert, runtimeHelpers } from "../../globals";
-import { mono_log_debug, mono_set_thread_name } from "../../logging";
+import { mono_log_debug, set_thread_prefix } from "../../logging";
import { bindings_init } from "../../startup";
import { forceDisposeProxies } from "../../gc-handles";
import { GCHandle, GCHandleNull, WorkerToMainMessageType, monoMessageSymbol } from "../../types/internal";
@@ -63,16 +63,28 @@ export function mono_wasm_uninstall_js_worker_interop(): void {
// this is just for Debug build of the runtime, making it easier to debug worker threads
export function update_thread_info(): void {
- loaderHelpers.mono_set_thread_name(monoThreadInfo.threadName!);
+ const threadType = monoThreadInfo.isUI ? "main"
+ : !monoThreadInfo.isAttached ? "emsc"
+ : monoThreadInfo.isTimer ? "timr"
+ : monoThreadInfo.isLongRunning ? "long"
+ : monoThreadInfo.isThreadPoolGate ? "gate"
+ : monoThreadInfo.isDebugger ? "dbgr"
+ : monoThreadInfo.isThreadPoolWorker ? "pool"
+ : monoThreadInfo.isExternalEventLoop ? "jsww"
+ : monoThreadInfo.isBackground ? "back"
+ : "norm";
+ monoThreadInfo.threadPrefix = `0x${monoThreadInfo.pthreadId.toString(16).padStart(8, "0")}-${threadType}`;
+
+ loaderHelpers.set_thread_prefix(monoThreadInfo.threadPrefix!);
if (!loaderHelpers.config.forwardConsoleLogsToWS) {
- mono_set_thread_name(monoThreadInfo.threadName!);
+ set_thread_prefix(monoThreadInfo.threadPrefix!);
}
(globalThis as any).monoThreadInfo = monoThreadInfo;
if (WasmEnableThreads && BuildConfiguration === "Debug" && !runtimeHelpers.cspPolicy) {
monoThreadInfo.updateCount++;
try {
- (globalThis as any).monoThreadInfoFn = new Function(`//# sourceURL=https://${monoThreadInfo.updateCount}WorkerInfo${monoThreadInfo.isAttached ? monoThreadInfo.threadName : ""}/\r\nconsole.log("${JSON.stringify(monoThreadInfo)}");`);
+ (globalThis as any).monoThreadInfoFn = new Function(`//# sourceURL=https://${monoThreadInfo.updateCount}WorkerInfo${monoThreadInfo.isAttached ? monoThreadInfo.threadPrefix : ""}/\r\nconsole.log("${JSON.stringify(monoThreadInfo)}");`);
}
catch (ex) {
runtimeHelpers.cspPolicy = true;
diff --git a/src/mono/browser/runtime/pthreads/shared/types.ts b/src/mono/browser/runtime/pthreads/shared/types.ts
index ab7e3b1a238be..11716137a87e5 100644
--- a/src/mono/browser/runtime/pthreads/shared/types.ts
+++ b/src/mono/browser/runtime/pthreads/shared/types.ts
@@ -12,18 +12,18 @@ export interface PThreadInfo {
reuseCount: number,
updateCount: number,
- name?: string,
threadName: string,
+ threadPrefix: string,
isLoaded?: boolean,
isRegistered?: boolean,
isRunning?: boolean,
isAttached?: boolean,
isExternalEventLoop?: boolean,
- isBrowserThread?: boolean;
+ isUI?: boolean;
isBackground?: boolean,
isDebugger?: boolean,
- isThreadPool?: boolean,
+ isThreadPoolWorker?: boolean,
isTimer?: boolean,
isLongRunning?: boolean,
isThreadPoolGate?: boolean,
diff --git a/src/mono/browser/runtime/pthreads/worker/index.ts b/src/mono/browser/runtime/pthreads/worker/index.ts
index c2af89871d676..0ea6e82de3d98 100644
--- a/src/mono/browser/runtime/pthreads/worker/index.ts
+++ b/src/mono/browser/runtime/pthreads/worker/index.ts
@@ -61,7 +61,8 @@ export const monoThreadInfo: PThreadInfo = {
pthreadId: 0,
reuseCount: 0,
updateCount: 0,
- threadName: "",
+ threadPrefix: " - ",
+ threadName: "emscripten-loaded",
};
/// This is the "public internal" API for runtime subsystems that wish to be notified about
@@ -96,7 +97,7 @@ export function mono_wasm_pthread_on_pthread_created(): void {
monoThreadInfo.pthreadId = pthread_id;
monoThreadInfo.reuseCount++;
monoThreadInfo.updateCount++;
- monoThreadInfo.threadName = `0x${pthread_id.toString(16).padStart(8, "0")}`;
+ monoThreadInfo.threadName = "pthread-assigned";
update_thread_info();
// don't do this callback for the main thread
@@ -153,26 +154,18 @@ export function mono_wasm_pthread_on_pthread_attached(pthread_id: number, thread
try {
mono_assert(monoThreadInfo !== null && monoThreadInfo.pthreadId == pthread_id, "expected monoThreadInfo to be set already when attaching");
- const name = monoThreadInfo.name = utf8ToString(thread_name);
+ const name = monoThreadInfo.threadName = utf8ToString(thread_name);
monoThreadInfo.isAttached = true;
- monoThreadInfo.isThreadPool = threadpool_thread !== 0;
+ monoThreadInfo.isThreadPoolWorker = threadpool_thread !== 0;
monoThreadInfo.isExternalEventLoop = external_eventloop !== 0;
monoThreadInfo.isBackground = background_thread !== 0;
monoThreadInfo.isDebugger = debugger_thread !== 0;
// FIXME: this is a hack to get constant length thread names
+ monoThreadInfo.threadName = name;
monoThreadInfo.isTimer = name == ".NET Timer";
monoThreadInfo.isLongRunning = name == ".NET Long Running Task";
monoThreadInfo.isThreadPoolGate = name == ".NET TP Gate";
- const threadType = monoThreadInfo.isTimer ? "timr"
- : monoThreadInfo.isLongRunning ? "long"
- : monoThreadInfo.isThreadPoolGate ? "gate"
- : monoThreadInfo.isDebugger ? "dbgr"
- : monoThreadInfo.isThreadPool ? "pool"
- : monoThreadInfo.isExternalEventLoop ? "jsww"
- : monoThreadInfo.isBackground ? "back"
- : "norm";
- monoThreadInfo.threadName = `0x${pthread_id.toString(16).padStart(8, "0")}-${threadType}`;
update_thread_info();
currentWorkerThreadEvents.dispatchEvent(makeWorkerThreadEvent(dotnetPthreadAttached, pthread_self));
postMessageToMain({
@@ -187,6 +180,17 @@ export function mono_wasm_pthread_on_pthread_attached(pthread_id: number, thread
}
}
+export function mono_wasm_pthread_set_name(name: CharPtr): void {
+ if (!WasmEnableThreads) return;
+ if (!ENVIRONMENT_IS_PTHREAD) return;
+ monoThreadInfo.threadName = utf8ToString(name);
+ update_thread_info();
+ postMessageToMain({
+ monoCmd: WorkerToMainMessageType.updateInfo,
+ info: monoThreadInfo,
+ });
+}
+
/// Called in the worker thread (not main thread) from mono when a pthread becomes detached from the mono runtime.
export function mono_wasm_pthread_on_pthread_unregistered(pthread_id: number): void {
if (!WasmEnableThreads) return;
@@ -194,7 +198,6 @@ export function mono_wasm_pthread_on_pthread_unregistered(pthread_id: number): v
mono_assert(pthread_id === monoThreadInfo.pthreadId, "expected pthread_id to match when un-registering");
postRunWorker();
monoThreadInfo.isAttached = false;
- monoThreadInfo.threadName = monoThreadInfo.threadName + "=>detached";
update_thread_info();
postMessageToMain({
monoCmd: WorkerToMainMessageType.monoUnRegistered,
diff --git a/src/mono/browser/runtime/snapshot.ts b/src/mono/browser/runtime/snapshot.ts
index 76aac0eecfaa2..e21c13ce2a1b9 100644
--- a/src/mono/browser/runtime/snapshot.ts
+++ b/src/mono/browser/runtime/snapshot.ts
@@ -191,6 +191,7 @@ export async function getCacheKey(prefix: string): Promise {
delete inputs.appendElementOnExit;
delete inputs.assertAfterExit;
delete inputs.interopCleanupOnExit;
+ delete inputs.dumpThreadsOnNonZeroExit;
delete inputs.logExitCode;
delete inputs.pthreadPoolSize;
delete inputs.asyncFlushOnExit;
diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts
index d7db9bc9a5567..892131d818a26 100644
--- a/src/mono/browser/runtime/startup.ts
+++ b/src/mono/browser/runtime/startup.ts
@@ -4,7 +4,7 @@
import WasmEnableThreads from "consts:wasmEnableThreads";
import { DotnetModuleInternal, CharPtrNull } from "./types/internal";
-import { ENVIRONMENT_IS_NODE, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, linkerWasmEnableSIMD, linkerWasmEnableEH, ENVIRONMENT_IS_WORKER } from "./globals";
+import { ENVIRONMENT_IS_NODE, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, ENVIRONMENT_IS_WORKER } from "./globals";
import cwraps, { init_c_exports, threads_c_functions as tcwraps } from "./cwraps";
import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
import { toBase64StringImpl } from "./base64";
@@ -26,7 +26,7 @@ import { mono_log_debug, mono_log_error, mono_log_warn } from "./logging";
// threads
import { preAllocatePThreadWorkerPool, instantiateWasmPThreadWorkerPool } from "./pthreads/browser";
-import { currentWorkerThreadEvents, dotnetPthreadCreated, initWorkerThreadEvents } from "./pthreads/worker";
+import { currentWorkerThreadEvents, dotnetPthreadCreated, initWorkerThreadEvents, monoThreadInfo } from "./pthreads/worker";
import { mono_wasm_main_thread_ptr, mono_wasm_pthread_ptr } from "./pthreads/shared";
import { jiterpreter_allocate_tables } from "./jiterpreter-support";
import { localHeapViewU8 } from "./memory";
@@ -383,8 +383,12 @@ export function postRunWorker() {
async function mono_wasm_init_threads() {
if (!WasmEnableThreads) return;
- const threadName = `0x${mono_wasm_main_thread_ptr().toString(16)}-main`;
- loaderHelpers.mono_set_thread_name(threadName);
+ const threadPrefix = `0x${mono_wasm_main_thread_ptr().toString(16)}-main`;
+ monoThreadInfo.threadPrefix = threadPrefix;
+ monoThreadInfo.threadName = "UI Thread";
+ monoThreadInfo.isUI = true;
+ monoThreadInfo.isAttached = true;
+ loaderHelpers.set_thread_prefix(threadPrefix);
await instantiateWasmPThreadWorkerPool();
await mono_wasm_init_diagnostics();
}
@@ -396,10 +400,13 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void {
mono_log_debug("mono_wasm_pre_init_essential");
if (loaderHelpers.gitHash !== runtimeHelpers.gitHash) {
- mono_log_warn("The version of dotnet.runtime.js is different from the version of dotnet.js!");
+ mono_log_warn(`The version of dotnet.runtime.js ${runtimeHelpers.gitHash} is different from the version of dotnet.js ${loaderHelpers.gitHash}!`);
}
- if (loaderHelpers.gitHash !== runtimeHelpers.moduleGitHash) {
- mono_log_warn("The version of dotnet.native.js is different from the version of dotnet.js!");
+ if (loaderHelpers.gitHash !== runtimeHelpers.emscriptenBuildOptions.gitHash) {
+ mono_log_warn(`The version of dotnet.native.js ${runtimeHelpers.emscriptenBuildOptions.gitHash} is different from the version of dotnet.js ${loaderHelpers.gitHash}!`);
+ }
+ if (WasmEnableThreads !== runtimeHelpers.emscriptenBuildOptions.wasmEnableThreads) {
+ mono_log_warn(`The threads of dotnet.native.js ${runtimeHelpers.emscriptenBuildOptions.wasmEnableThreads} is different from the version of dotnet.runtime.js ${WasmEnableThreads}!`);
}
init_c_exports();
@@ -513,10 +520,10 @@ async function instantiate_wasm_module(
async function ensureUsedWasmFeatures() {
runtimeHelpers.featureWasmSimd = await loaderHelpers.simd();
runtimeHelpers.featureWasmEh = await loaderHelpers.exceptions();
- if (linkerWasmEnableSIMD) {
+ if (runtimeHelpers.emscriptenBuildOptions.wasmEnableSIMD) {
mono_assert(runtimeHelpers.featureWasmSimd, "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features");
}
- if (linkerWasmEnableEH) {
+ if (runtimeHelpers.emscriptenBuildOptions.wasmEnableEH) {
mono_assert(runtimeHelpers.featureWasmEh, "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features");
}
}
diff --git a/src/mono/browser/runtime/types/index.ts b/src/mono/browser/runtime/types/index.ts
index e6f7152b9bff9..5c4c6511763e9 100644
--- a/src/mono/browser/runtime/types/index.ts
+++ b/src/mono/browser/runtime/types/index.ts
@@ -579,6 +579,9 @@ export type RuntimeAPI = {
productVersion: string,
gitHash: string,
buildConfiguration: string,
+ wasmEnableThreads: boolean,
+ wasmEnableSIMD: boolean,
+ wasmEnableExceptionHandling: boolean,
}
} & APIType
diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts
index 08f34bf68a9a0..e0cfaf8fd2a2b 100644
--- a/src/mono/browser/runtime/types/internal.ts
+++ b/src/mono/browser/runtime/types/internal.ts
@@ -78,6 +78,7 @@ export type MonoConfigInternal = MonoConfig & {
appendElementOnExit?: boolean
assertAfterExit?: boolean // default true for shell/nodeJS
interopCleanupOnExit?: boolean
+ dumpThreadsOnNonZeroExit?: boolean
logExitCode?: boolean
forwardConsoleLogsToWS?: boolean,
asyncFlushOnExit?: boolean
@@ -150,7 +151,7 @@ export type LoaderHelpers = {
mono_download_assets: () => Promise,
resolve_single_asset_path: (behavior: SingleAssetBehaviors) => AssetEntryInternal,
setup_proxy_console: (id: string, console: Console, origin: string) => void
- mono_set_thread_name: (tid: string) => void
+ set_thread_prefix: (prefix: string) => void
fetch_like: (url: string, init?: RequestInit) => Promise;
locateFile: (path: string, prefix?: string) => string,
out(message: string): void;
@@ -175,8 +176,8 @@ export type LoaderHelpers = {
simd: () => Promise,
}
export type RuntimeHelpers = {
+ emscriptenBuildOptions: EmscriptenBuildOptions,
gitHash: string,
- moduleGitHash: string,
config: MonoConfigInternal;
diagnosticTracing: boolean;
@@ -227,6 +228,7 @@ export type RuntimeHelpers = {
instantiate_segmentation_rules_asset: (pendingAsset: AssetEntryInternal) => Promise,
jiterpreter_dump_stats?: (x: boolean) => string,
forceDisposeProxies: (disposeMethods: boolean, verbose: boolean) => void,
+ dumpThreads: () => void,
}
export type AOTProfilerOptions = {
@@ -247,13 +249,18 @@ export function is_nullish(value: T | null | undefined): value is null | unde
return (value === undefined) || (value === null);
}
+// these are values from the last re-link with emcc/workload
+export type EmscriptenBuildOptions = {
+ wasmEnableSIMD: boolean,
+ wasmEnableEH: boolean,
+ enableAotProfiler: boolean,
+ enableBrowserProfiler: boolean,
+ runAOTCompilation: boolean,
+ wasmEnableThreads: boolean,
+ gitHash: string,
+};
export type EmscriptenInternals = {
isPThread: boolean,
- linkerWasmEnableSIMD: boolean,
- linkerWasmEnableEH: boolean,
- linkerEnableAotProfiler: boolean,
- linkerEnableBrowserProfiler: boolean,
- linkerRunAOTCompilation: boolean,
quit_: Function,
ExitStatus: ExitStatusError,
gitHash: string,
@@ -466,7 +473,7 @@ export interface PromiseAndController {
promise_control: PromiseController;
}
-export type passEmscriptenInternalsType = (internals: EmscriptenInternals) => void;
+export type passEmscriptenInternalsType = (internals: EmscriptenInternals, emscriptenBuildOptions: EmscriptenBuildOptions) => void;
export type setGlobalObjectsType = (globalObjects: GlobalObjects) => void;
export type initializeExportsType = (globalObjects: GlobalObjects) => RuntimeAPI;
export type initializeReplacementsType = (replacements: EmscriptenReplacements) => void;
@@ -500,6 +507,7 @@ export const monoMessageSymbol = "__mono_message__";
export const enum WorkerToMainMessageType {
monoRegistered = "monoRegistered",
monoAttached = "monoAttached",
+ updateInfo = "updateInfo",
enabledInterop = "notify_enabled_interop",
monoUnRegistered = "monoUnRegistered",
pthreadCreated = "pthreadCreated",
diff --git a/src/mono/browser/test-main.js b/src/mono/browser/test-main.js
index 2c4c04106e22f..16a00729e1de3 100644
--- a/src/mono/browser/test-main.js
+++ b/src/mono/browser/test-main.js
@@ -254,6 +254,7 @@ function configureRuntime(dotnet, runArgs) {
.withElementOnExit()
.withInteropCleanupOnExit()
.withAssertAfterExit()
+ .withDumpThreadsOnNonZeroExit()
.withConfig({
loadAllSatelliteResources: true
});
@@ -272,6 +273,12 @@ function configureRuntime(dotnet, runArgs) {
})
}
}
+
+ // dotnet.withEnvironmentVariable("MONO_LOG_LEVEL", "debug")
+ // dotnet.withEnvironmentVariable("MONO_LOG_MASK", "gc")
+ // dotnet.withEnvironmentVariable("MONO_GC_DEBUG", "9")
+ // dotnet.withEnvironmentVariable("DOTNET_DebugWriteToStdErr", "1")
+
if (ENVIRONMENT_IS_WEB) {
if (runArgs.memorySnapshot)
dotnet.withStartupMemoryCache(true);
@@ -306,6 +313,7 @@ async function dry_run(runArgs) {
virtualWorkingDirectory: undefined,
pthreadPoolSize: 0,
interopCleanupOnExit: false,
+ dumpThreadsOnNonZeroExit: false,
// this just means to not continue startup after the snapshot is taken.
// If there was previously a matching snapshot, it will be used.
exitAfterSnapshot: true
diff --git a/src/mono/mono/utils/mono-threads-wasm.c b/src/mono/mono/utils/mono-threads-wasm.c
index d880b47d0513c..ea8faf904c256 100644
--- a/src/mono/mono/utils/mono-threads-wasm.c
+++ b/src/mono/mono/utils/mono-threads-wasm.c
@@ -164,15 +164,20 @@ mono_native_thread_os_id_get (void)
MONO_API gboolean
mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
{
+#ifdef __EMSCRIPTEN_PTHREADS__
+ return pthread_create (tid, NULL, (void *(*)(void *)) func, arg) == 0;
+#else
g_error ("WASM doesn't support threading");
+#endif
}
-static const char *thread_name;
-
void
mono_native_thread_set_name (MonoNativeThreadId tid, const char *name)
{
- thread_name = g_strdup (name);
+#ifndef DISABLE_THREADS
+ // note there is also emscripten_set_thread_name, but it only changes the name for emscripten profiler
+ mono_wasm_pthread_set_name (name);
+#endif
}
gboolean
diff --git a/src/mono/mono/utils/mono-threads-wasm.h b/src/mono/mono/utils/mono-threads-wasm.h
index bccb81f46fd83..1c4934c2f9b43 100644
--- a/src/mono/mono/utils/mono-threads-wasm.h
+++ b/src/mono/mono/utils/mono-threads-wasm.h
@@ -87,6 +87,9 @@ mono_threads_wasm_on_thread_attached (pthread_t tid, const char* thread_name, gb
void
mono_threads_wasm_on_thread_unregistered (void);
+void
+mono_wasm_pthread_set_name (const char* thread_name);
+
#endif /* HOST_WASM*/
#endif /* __MONO_THREADS_WASM_H__ */