Skip to content

Commit 0577227

Browse files
authored
[wasm-mt] Add MessageChannel between browser thread and new pthreads (#70908)
Add a mechanism for creating a communication channel between the browser thread and new pthreads (running in webworkers - note, Emscripten may recycle workers after a pthread exits). This is done by adding our own event listener to the webworker (in the main thread) and to globalThis (in the worker). This conflicts with emscripten's message handlers (although it's considered a bug by Emscripten upstream that their event handler doesn't ignore unrecognized messages). One potential problem here is that for any communication to happen, the worker must service its event loop. If it's just busy running a loop in wasm, it might never handle the messages. On the other hand, posting messages back to main should work. Once we have our message handlers in place, the rest is straightforward, the worker creates a MessageChannel and transfers one of the ports to the browser thread. With the browser-to-pthread channel established, we can build up cross-thread channels by asking the main thread to transfer ports on our behalf. This part isn't done yet. --- Additionally in the worker, create an `EventTarget` that fires `dotnet:pthread:created` and `dotnet:pthread:attached` events whenever Emscripten begins running a new thread on one of its workers, and whenever that worker attaches to Mono. This lets runtime subsystems be notified on the JS side whenever threads come into existence or may potentially begin to run managed code. --- Also re-organizes our `tsconfig.json` into `tsconfig.shared.json` (common flags), `tsconfig.worker.json` (uses the `esnext` and `worker` libs, so VS Code doesn't offer DOM completions and types, for example), and `tsconfig.json` (uses the `esnext` and `dom` libs). Subsystems with their own subdirectories (like `pthreads/worker` `pthreads/browser`, etc) can use the `tsconfig` `extends` property to include the appropriate root-directory config. --- * outline of a dedicated channel between JS main thread and pthreads * add JS entrypoints for pthread-channel * wire up the MessageChannel to native thread attach * debug printfs etc * split up into pthread-channel module into worker, browser and shared * pthreads modules * add ENVIRONMENT_IS_PTHREAD; mono_wasm_pthread_worker_init * Fixup names; call MessagePort.start; remove printfs * remove whitespace and extra printfs * Exclude threading exports in non-threaded runtime Use the `USE_THREADS` emscripten library ifdef to prevent the entrypoints from being saved. Use a new `MonoWasmThreads` rollup constant to remove JS roots. Verified that a Release build single-threaded dotnet.js doesn't include any of the new pthread support code * Add replacement for PThread.loadWasmModuleToWorker This will allow us to install a message handler when the worker is created, before it has any pthreads assigned to it. We can therefore simplify how we set up our own MessageChannel to simply send a single event from the worker to the browser thread, instead of having to lazily install the event handler on the main thread by queueing async work to the browser thread. * Simplify the dedicated channel creation now that we can add a message handler to a worker when Emscripten creates it, skip the complicated atomic notification process * Don't forget the GC transition out to JS * fix browser-eventpipe default import * move mono_threads_wasm_on_thread_attached later in register_thread Actually attach the thread to the runtime (so that GC transitions work) before calling out to JS * also fix default import in browser-mt-eventpipe * Add replacement for Module.PThread.threadInit Use it to call mono_wasm_pthread_on_pthread_created Rename the previous callback to mono_wasm_pthread_on_pthread_attached - it gets called but it's unused. This is enough to get the diagnostic sever worker started up and pinging. * Cleanup mono_wasm_pthread_on_pthread_created * Share tsconfig parts using "extends" property * Use an EventTarget and custom events for worker thread lifecycle notifications * pass portToMain in ThreadEvents; update README this lets pthread lifecycle event handlers post messages and setup listeners on the message port back to the main browser thread. Also update the README to describe the current design * make pthread/worker/events friendlier to tree shaking and node * another approach to tree shaking rollup doesn't understand fallthru. In the following (which is what `mono_assert` ammounts to) it retains `C`: ``` if (condition) throw new Error (...); // fallthru return new C(); ``` Solution is to use an if-then-else ``` if (condition) throw new Error (...); else return new C(); // C is not retained if 'condition' is false ``` * fix annoying VSCode ESLint toast Cannot read property 'loc' of undefined See microsoft/vscode-eslint#1149 and a proposed workaround in eslint/eslint#14538 (comment) * Add Event and EventTarget polyfill for v8 * fix whitespace and comments
1 parent 5696655 commit 0577227

29 files changed

+605
-36
lines changed

src/mono/mono/component/event_pipe-stub.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#include "mono/component/event_pipe.h"
77
#include "mono/component/event_pipe-wasm.h"
88
#include "mono/metadata/components.h"
9+
#ifdef HOST_WASM
10+
#include <emscripten/emscripten.h>
11+
#endif
912

1013
static EventPipeSessionID _dummy_session_id;
1114

src/mono/mono/component/event_pipe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#include <eventpipe/ep-event-instance.h>
1414
#include <eventpipe/ep-session.h>
1515

16+
#ifdef HOST_WASM
17+
#include <emscripten/emscripten.h>
18+
#endif
1619

1720
extern void ep_rt_mono_component_init (void);
1821
static bool _event_pipe_component_inited = false;

src/mono/mono/utils/mono-threads-wasm.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,29 @@ mono_threads_platform_stw_defer_initial_suspend (MonoThreadInfo *info)
411411
return mono_native_thread_id_equals (mono_thread_info_get_tid (info), mono_threads_wasm_browser_thread_tid ());
412412
}
413413

414+
#ifndef DISABLE_THREADS
415+
extern void
416+
mono_wasm_pthread_on_pthread_attached (gpointer pthread_id);
417+
#endif
418+
419+
void
420+
mono_threads_wasm_on_thread_attached (void)
421+
{
422+
#ifdef DISABLE_THREADS
423+
return;
424+
#else
425+
if (mono_threads_wasm_is_browser_thread ()) {
426+
return;
427+
}
428+
// Notify JS that the pthread attachd to Mono
429+
pthread_t id = pthread_self ();
430+
MONO_ENTER_GC_SAFE;
431+
mono_wasm_pthread_on_pthread_attached (id);
432+
MONO_EXIT_GC_SAFE;
433+
#endif
434+
}
435+
436+
414437
#ifndef DISABLE_THREADS
415438
void
416439
mono_threads_wasm_async_run_in_main_thread (void (*func) (void))
@@ -423,6 +446,14 @@ mono_threads_wasm_async_run_in_main_thread_vi (void (*func) (gpointer), gpointer
423446
{
424447
emscripten_async_run_in_main_runtime_thread (EM_FUNC_SIG_VI, func, user_data);
425448
}
449+
450+
void
451+
mono_threads_wasm_async_run_in_main_thread_vii (void (*func) (gpointer, gpointer), gpointer user_data1, gpointer user_data2)
452+
{
453+
emscripten_async_run_in_main_runtime_thread (EM_FUNC_SIG_VII, func, user_data1, user_data2);
454+
}
455+
456+
426457
#endif /* DISABLE_THREADS */
427458

428459
#endif /* HOST_BROWSER */

src/mono/mono/utils/mono-threads-wasm.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,15 @@ mono_threads_wasm_async_run_in_main_thread (void (*func) (void));
3939
*/
4040
void
4141
mono_threads_wasm_async_run_in_main_thread_vi (void (*func)(gpointer), gpointer user_data);
42+
43+
void
44+
mono_threads_wasm_async_run_in_main_thread_vii (void (*func)(gpointer, gpointer), gpointer user_data1, gpointer user_data2);
4245
#endif /* DISABLE_THREADS */
4346

47+
// Called from register_thread when a pthread attaches to the runtime
48+
void
49+
mono_threads_wasm_on_thread_attached (void);
50+
4451
#endif /* HOST_WASM*/
4552

4653
#endif /* __MONO_THREADS_WASM_H__ */

src/mono/mono/utils/mono-threads.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <mono/utils/mono-coop-semaphore.h>
3232
#include <mono/utils/mono-threads-coop.h>
3333
#include <mono/utils/mono-threads-debug.h>
34+
#include <mono/utils/mono-threads-wasm.h>
3435
#include <mono/utils/os-event.h>
3536
#include <mono/utils/w32api.h>
3637
#include <glib.h>
@@ -552,6 +553,10 @@ register_thread (MonoThreadInfo *info)
552553
g_assert (result);
553554
mono_thread_info_suspend_unlock ();
554555

556+
#ifdef HOST_BROWSER
557+
mono_threads_wasm_on_thread_attached ();
558+
#endif
559+
555560
return TRUE;
556561
}
557562

src/mono/sample/wasm/browser-eventpipe/Program.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,23 @@ private static long recursiveFib (int n)
9393
return recursiveFib (n - 1) + recursiveFib (n - 2);
9494
}
9595

96+
#if false
97+
// dead code to prove that starting user threads isn't possible on the perftracing runtime
98+
public static void Meth() {
99+
Thread.Sleep (500);
100+
while (!GetCancellationToken().IsCancellationRequested) {
101+
Console.WriteLine ("ping");
102+
Thread.Sleep (500);
103+
}
104+
}
105+
#endif
106+
96107
public static async Task<double> StartAsyncWork(int N)
97108
{
98109
CancellationToken ct = GetCancellationToken();
110+
#if false
111+
new Thread(new ThreadStart(Meth)).Start();
112+
#endif
99113
await Task.Delay(1);
100114
long b;
101115
WasmHelloEventSource.Instance.NewCallsCounter();

src/mono/sample/wasm/browser-eventpipe/Wasm.Browser.EventPipe.Sample.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<GenerateRunScriptForSample Condition="'$(ArchiveTests)' == 'true'">true</GenerateRunScriptForSample>
1010
<RunScriptCommand>$(ExecXHarnessCmd) wasm test-browser --app=. --browser=Chrome $(XHarnessBrowserPathArg) --html-file=index.html --output-directory=$(XHarnessOutput) -- $(MSBuildProjectName).dll</RunScriptCommand>
1111
<FeatureWasmPerfTracing>true</FeatureWasmPerfTracing>
12-
<WasmEnablePerfTracing>true</WasmEnablePerfTracing>
12+
<FeatureWasmThreads Condition="false">true</FeatureWasmThreads>
1313
<NoWarn>CA2007</NoWarn> <!-- consider ConfigureAwait() -->
1414
</PropertyGroup>
1515

src/mono/sample/wasm/browser-eventpipe/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createDotnetRuntime } from "./dotnet.js";
1+
import createDotnetRuntime from "./dotnet.js";
22

33
function downloadData(dataURL, filename) {
44
// make an `<a download="filename" href="data:..."/>` link and click on it to trigger a download with the given name

src/mono/sample/wasm/browser-mt-eventpipe/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createDotnetRuntime } from "./dotnet.js";
1+
import createDotnetRuntime from "./dotnet.js";
22

33
function wasm_exit(exit_code, reason) {
44
/* Set result in a tests_done element, to be read by xharness in runonly CI test */

src/mono/wasm/runtime/.eslintrc.cjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ module.exports = {
2929
"indent": [
3030
"error",
3131
4,
32-
{ SwitchCase: 1 }
32+
{
33+
SwitchCase: 1,
34+
"ignoredNodes": ["VariableDeclaration[declarations.length=0]"] // fixes https://github.com/microsoft/vscode-eslint/issues/1149
35+
}
3336
],
3437
"linebreak-style": "off",
3538
"quotes": [

src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,39 @@
44

55
"use strict";
66

7+
#if USE_PTHREADS
8+
const usePThreads = `true`;
9+
const isPThread = `ENVIRONMENT_IS_PTHREAD`;
10+
#else
11+
const usePThreads = `false`;
12+
const isPThread = `false`;
13+
#endif
14+
715
const DotnetSupportLib = {
816
$DOTNET: {},
917
// these lines will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE
1018
// we replace implementation of readAsync and fetch
1119
// replacement of require is there for consistency with ES6 code
1220
$DOTNET__postset: `
13-
let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews};
21+
let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
22+
if (${usePThreads}) {
23+
__dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
24+
__dotnet_replacement_PThread.threadInit = PThread.threadInit;
25+
}
26+
let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
1427
let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
15-
{ isESM:false, isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile, quit_, ExitStatus, requirePromise:Promise.resolve(require)},
28+
{ isESM:false, isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, locateFile, quit_, ExitStatus, requirePromise:Promise.resolve(require)},
1629
{ mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_exports: EXPORTS, marshaled_imports: IMPORTS },
1730
__dotnet_replacements);
1831
updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
1932
readAsync = __dotnet_replacements.readAsync;
2033
var fetch = __dotnet_replacements.fetch;
2134
require = __dotnet_replacements.requireOut;
2235
var noExitRuntime = __dotnet_replacements.noExitRuntime;
36+
if (${usePThreads}) {
37+
PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
38+
PThread.threadInit = __dotnet_replacements.pthreadReplacements.threadInit;
39+
}
2340
`,
2441
};
2542

@@ -73,6 +90,11 @@ const linked_functions = [
7390
"dotnet_browser_can_use_subtle_crypto_impl",
7491
"dotnet_browser_simple_digest_hash",
7592
"dotnet_browser_sign",
93+
94+
/// mono-threads-wasm.c
95+
#if USE_PTHREADS
96+
"mono_wasm_pthread_on_pthread_attached",
97+
#endif
7698
];
7799

78100
// -- this javascript file is evaluated by emcc during compilation! --

src/mono/wasm/runtime/es6/dotnet.es6.lib.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
"use strict";
66

7+
#if USE_PTHREADS
8+
const usePThreads = `true`;
9+
const isPThread = `ENVIRONMENT_IS_PTHREAD`;
10+
#else
11+
const usePThreads = `false`;
12+
const isPThread = `false`;
13+
#endif
14+
715
const DotnetSupportLib = {
816
$DOTNET: {},
917
// this line will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE
@@ -14,7 +22,12 @@ const DotnetSupportLib = {
1422
// Emscripten's getBinaryPromise is not async for NodeJs, but we would like to have it async, so we replace it.
1523
// We also replace implementation of readAsync and fetch
1624
$DOTNET__postset: `
17-
let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews};
25+
let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
26+
if (${usePThreads}) {
27+
__dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
28+
__dotnet_replacement_PThread.threadInit = PThread.threadInit;
29+
}
30+
let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
1831
if (ENVIRONMENT_IS_NODE) {
1932
__dotnet_replacements.requirePromise = import(/* webpackIgnore: true */'module').then(mod => {
2033
const require = mod.createRequire(import.meta.url);
@@ -49,14 +62,18 @@ if (ENVIRONMENT_IS_NODE) {
4962
}
5063
}
5164
let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
52-
{ isESM:true, isGlobal:false, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile, quit_, ExitStatus, requirePromise:__dotnet_replacements.requirePromise },
65+
{ isESM:true, isGlobal:false, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, locateFile, quit_, ExitStatus, requirePromise:__dotnet_replacements.requirePromise },
5366
{ mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_exports: EXPORTS, marshaled_imports: IMPORTS },
5467
__dotnet_replacements);
5568
updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
5669
readAsync = __dotnet_replacements.readAsync;
5770
var fetch = __dotnet_replacements.fetch;
5871
require = __dotnet_replacements.requireOut;
5972
var noExitRuntime = __dotnet_replacements.noExitRuntime;
73+
if (${usePThreads}) {
74+
PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
75+
PThread.threadInit = __dotnet_replacements.pthreadReplacements.threadInit;
76+
}
6077
`,
6178
};
6279

@@ -110,6 +127,11 @@ const linked_functions = [
110127
"dotnet_browser_can_use_subtle_crypto_impl",
111128
"dotnet_browser_simple_digest_hash",
112129
"dotnet_browser_sign",
130+
131+
/// mono-threads-wasm.c
132+
#if USE_PTHREADS
133+
"mono_wasm_pthread_on_pthread_attached",
134+
#endif
113135
];
114136

115137
// -- this javascript file is evaluated by emcc during compilation! --

src/mono/wasm/runtime/exports.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import ProductVersion from "consts:productVersion";
55
import Configuration from "consts:configuration";
6+
import MonoWasmThreads from "consts:monoWasmThreads";
67

78
import {
89
mono_wasm_new_root, mono_wasm_release_roots, mono_wasm_new_external_root,
@@ -74,6 +75,8 @@ import {
7475
} from "./crypto-worker";
7576
import { mono_wasm_cancel_promise_ref } from "./cancelable-promise";
7677
import { mono_wasm_web_socket_open_ref, mono_wasm_web_socket_send, mono_wasm_web_socket_receive, mono_wasm_web_socket_close_ref, mono_wasm_web_socket_abort } from "./web-socket";
78+
import { mono_wasm_pthread_on_pthread_attached, afterThreadInit } from "./pthreads/worker";
79+
import { afterLoadWasmModuleToWorker } from "./pthreads/browser";
7780

7881
const MONO = {
7982
// current "public" MONO API
@@ -184,14 +187,20 @@ export type BINDINGType = typeof BINDING;
184187

185188
let exportedAPI: DotnetPublicAPI;
186189

190+
// We need to replace some of the methods in the Emscripten PThreads support with our own
191+
type PThreadReplacements = {
192+
loadWasmModuleToWorker: Function,
193+
threadInit: Function
194+
}
195+
187196
// this is executed early during load of emscripten runtime
188197
// it exports methods to global objects MONO, BINDING and Module in backward compatible way
189198
// At runtime this will be referred to as 'createDotnetRuntime'
190199
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
191200
function initializeImportsAndExports(
192-
imports: { isESM: boolean, isGlobal: boolean, isNode: boolean, isWorker: boolean, isShell: boolean, isWeb: boolean, locateFile: Function, quit_: Function, ExitStatus: ExitStatusError, requirePromise: Promise<Function> },
201+
imports: { isESM: boolean, isGlobal: boolean, isNode: boolean, isWorker: boolean, isShell: boolean, isWeb: boolean, isPThread: boolean, locateFile: Function, quit_: Function, ExitStatus: ExitStatusError, requirePromise: Promise<Function> },
193202
exports: { mono: any, binding: any, internal: any, module: any, marshaled_exports: any, marshaled_imports: any },
194-
replacements: { fetch: any, readAsync: any, require: any, requireOut: any, noExitRuntime: boolean, updateGlobalBufferAndViews: Function },
203+
replacements: { fetch: any, readAsync: any, require: any, requireOut: any, noExitRuntime: boolean, updateGlobalBufferAndViews: Function, pthreadReplacements: PThreadReplacements | undefined | null },
195204
): DotnetPublicAPI {
196205
const module = exports.module as DotnetModule;
197206
const globalThisAny = globalThis as any;
@@ -258,6 +267,19 @@ function initializeImportsAndExports(
258267

259268
replacements.noExitRuntime = ENVIRONMENT_IS_WEB;
260269

270+
if (replacements.pthreadReplacements) {
271+
const originalLoadWasmModuleToWorker = replacements.pthreadReplacements.loadWasmModuleToWorker;
272+
replacements.pthreadReplacements.loadWasmModuleToWorker = (worker: Worker, onFinishedLoading: Function): void => {
273+
originalLoadWasmModuleToWorker(worker, onFinishedLoading);
274+
afterLoadWasmModuleToWorker(worker);
275+
};
276+
const originalThreadInit = replacements.pthreadReplacements.threadInit;
277+
replacements.pthreadReplacements.threadInit = (): void => {
278+
originalThreadInit();
279+
afterThreadInit();
280+
};
281+
}
282+
261283
if (typeof module.disableDotnet6Compatibility === "undefined") {
262284
module.disableDotnet6Compatibility = imports.isESM;
263285
}
@@ -328,6 +350,13 @@ function initializeImportsAndExports(
328350

329351
export const __initializeImportsAndExports: any = initializeImportsAndExports; // don't want to export the type
330352

353+
// the methods would be visible to EMCC linker
354+
// --- keep in sync with dotnet.cjs.lib.js ---
355+
const mono_wasm_threads_exports = !MonoWasmThreads ? undefined : {
356+
// mono-threads-wasm.c
357+
mono_wasm_pthread_on_pthread_attached,
358+
};
359+
331360
// the methods would be visible to EMCC linker
332361
// --- keep in sync with dotnet.cjs.lib.js ---
333362
export const __linker_exports: any = {
@@ -376,7 +405,10 @@ export const __linker_exports: any = {
376405
// pal_crypto_webworker.c
377406
dotnet_browser_can_use_subtle_crypto_impl,
378407
dotnet_browser_simple_digest_hash,
379-
dotnet_browser_sign
408+
dotnet_browser_sign,
409+
410+
// threading exports, if threading is enabled
411+
...mono_wasm_threads_exports,
380412
};
381413

382414
const INTERNAL: any = {
@@ -450,4 +482,4 @@ class RuntimeList {
450482

451483
export function get_dotnet_instance(): DotnetPublicAPI {
452484
return exportedAPI;
453-
}
485+
}

src/mono/wasm/runtime/imports.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export let ENVIRONMENT_IS_NODE: boolean;
2121
export let ENVIRONMENT_IS_SHELL: boolean;
2222
export let ENVIRONMENT_IS_WEB: boolean;
2323
export let ENVIRONMENT_IS_WORKER: boolean;
24+
export let ENVIRONMENT_IS_PTHREAD: boolean;
2425
export let locateFile: Function;
2526
export let quit: Function;
2627
export let ExitStatus: ExitStatusError;
@@ -33,7 +34,7 @@ export interface ExitStatusError {
3334

3435
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
3536
export function setImportsAndExports(
36-
imports: { isESM: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, isWorker: boolean, locateFile: Function, ExitStatus: ExitStatusError, quit_: Function, requirePromise: Promise<Function> },
37+
imports: { isESM: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, isWorker: boolean, isPThread: boolean, locateFile: Function, ExitStatus: ExitStatusError, quit_: Function, requirePromise: Promise<Function> },
3738
exports: { mono: any, binding: any, internal: any, module: any, marshaled_exports: any, marshaled_imports: any },
3839
): void {
3940
MONO = exports.mono;
@@ -49,6 +50,7 @@ export function setImportsAndExports(
4950
ENVIRONMENT_IS_SHELL = imports.isShell;
5051
ENVIRONMENT_IS_WEB = imports.isWeb;
5152
ENVIRONMENT_IS_WORKER = imports.isWorker;
53+
ENVIRONMENT_IS_PTHREAD = imports.isPThread;
5254
locateFile = imports.locateFile;
5355
quit = imports.quit_;
5456
ExitStatus = imports.ExitStatus;

0 commit comments

Comments
 (0)