| Download
Play around with sieves and benchmarking...
Project: 🧮 JSage: wasm - sagemath - zig
Views: 276Image: ubuntu2004
/**1* @license2* Copyright 2015 The Emscripten Authors3* SPDX-License-Identifier: MIT4*/56// Pthread Web Worker startup routine:7// This is the entry point file that is loaded first by each Web Worker8// that executes pthreads on the Emscripten application.910'use strict';1112var Module = {};1314// Node.js support15if (typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string') {16// Create as web-worker-like an environment as we can.1718var nodeWorkerThreads = require('worker_threads');1920var parentPort = nodeWorkerThreads.parentPort;2122parentPort.on('message', function(data) {23onmessage({ data: data });24});2526var nodeFS = require('fs');2728Object.assign(global, {29self: global,30require: require,31Module: Module,32location: {33href: __filename34},35Worker: nodeWorkerThreads.Worker,36importScripts: function(f) {37(0, eval)(nodeFS.readFileSync(f, 'utf8'));38},39postMessage: function(msg) {40parentPort.postMessage(msg);41},42performance: global.performance || {43now: function() {44return Date.now();45}46},47});48}4950// Thread-local:5152function assert(condition, text) {53if (!condition) abort('Assertion failed: ' + text);54}5556function threadPrintErr() {57var text = Array.prototype.slice.call(arguments).join(' ');58console.error(text);59}60function threadAlert() {61var text = Array.prototype.slice.call(arguments).join(' ');62postMessage({cmd: 'alert', text: text, threadId: Module['_pthread_self']()});63}64// We don't need out() for now, but may need to add it if we want to use it65// here. Or, if this code all moves into the main JS, that problem will go66// away. (For now, adding it here increases code size for no benefit.)67var out = function() {68throw 'out() is not defined in worker.js.';69}70var err = threadPrintErr;71self.alert = threadAlert;7273Module['instantiateWasm'] = function(info, receiveInstance) {74// Instantiate from the module posted from the main thread.75// We can just use sync instantiation in the worker.76var instance = new WebAssembly.Instance(Module['wasmModule'], info);77// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,78// the above line no longer optimizes out down to the following line.79// When the regression is fixed, we can remove this if/else.80receiveInstance(instance);81// We don't need the module anymore; new threads will be spawned from the main thread.82Module['wasmModule'] = null;83return instance.exports;84};8586function moduleLoaded() {87}8889self.onmessage = function(e) {90try {91if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code.9293// Module and memory were sent from main thread94Module['wasmModule'] = e.data.wasmModule;9596Module['wasmMemory'] = e.data.wasmMemory;9798Module['buffer'] = Module['wasmMemory'].buffer;99100Module['ENVIRONMENT_IS_PTHREAD'] = true;101102if (typeof e.data.urlOrBlob === 'string') {103importScripts(e.data.urlOrBlob);104} else {105var objectUrl = URL.createObjectURL(e.data.urlOrBlob);106importScripts(objectUrl);107URL.revokeObjectURL(objectUrl);108}109110// MINIMAL_RUNTIME always compiled Wasm (&Wasm2JS) asynchronously, even in pthreads. But111// regular runtime and asm.js are loaded synchronously, so in those cases112// we are now loaded, and can post back to main thread.113moduleLoaded();114115} else if (e.data.cmd === 'objectTransfer') {116Module['PThread'].receiveObjectTransfer(e.data);117} else if (e.data.cmd === 'run') {118// This worker was idle, and now should start executing its pthread entry119// point.120// performance.now() is specced to return a wallclock time in msecs since121// that Web Worker/main thread launched. However for pthreads this can122// cause subtle problems in emscripten_get_now() as this essentially123// would measure time from pthread_create(), meaning that the clocks124// between each threads would be wildly out of sync. Therefore sync all125// pthreads to the clock on the main browser thread, so that different126// threads see a somewhat coherent clock across each of them127// (+/- 0.1msecs in testing).128Module['__performance_now_clock_drift'] = performance.now() - e.data.time;129130// Pass the thread address inside the asm.js scope to store it for fast access that avoids the need for a FFI out.131Module['__emscripten_thread_init'](e.data.threadInfoStruct, /*isMainBrowserThread=*/0, /*isMainRuntimeThread=*/0);132133// Establish the stack frame for this thread in global scope134// The stack grows downwards135var max = e.data.stackBase;136var top = e.data.stackBase + e.data.stackSize;137assert(e.data.threadInfoStruct);138assert(top != 0);139assert(max != 0);140assert(top > max);141// Also call inside JS module to set up the stack frame for this pthread in JS module scope142Module['establishStackSpace'](top, max);143Module['PThread'].receiveObjectTransfer(e.data);144Module['PThread'].threadInit();145146try {147// pthread entry points are always of signature 'void *ThreadMain(void *arg)'148// Native codebases sometimes spawn threads with other thread entry point signatures,149// such as void ThreadMain(void *arg), void *ThreadMain(), or void ThreadMain().150// That is not acceptable per C/C++ specification, but x86 compiler ABI extensions151// enable that to work. If you find the following line to crash, either change the signature152// to "proper" void *ThreadMain(void *arg) form, or try linking with the Emscripten linker153// flag -s EMULATE_FUNCTION_POINTER_CASTS=1 to add in emulation for this x86 ABI extension.154var result = Module['invokeEntryPoint'](e.data.start_routine, e.data.arg);155156Module['checkStackCookie']();157if (Module['keepRuntimeAlive']()) {158Module['PThread'].setExitStatus(result);159} else {160Module['PThread'].threadExit(result);161}162} catch(ex) {163if (ex === 'Canceled!') {164Module['PThread'].threadCancel();165} else if (ex != 'unwind') {166// FIXME(sbc): Figure out if this is still needed or useful. Its not167// clear to me how this check could ever fail. In order to get into168// this try/catch block at all we have already called bunch of169// functions on `Module`.. why is this one special?170if (typeof(Module['_emscripten_futex_wake']) !== "function") {171err("Thread Initialisation failed.");172throw ex;173}174// ExitStatus not present in MINIMAL_RUNTIME175if (ex instanceof Module['ExitStatus']) {176if (Module['keepRuntimeAlive']()) {177err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' called exit(), staying alive due to noExitRuntime.');178} else {179err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' called exit(), calling threadExit.');180Module['PThread'].threadExit(ex.status);181}182}183else184{185Module['PThread'].threadExit(-2);186throw ex;187}188} else {189// else e == 'unwind', and we should fall through here and keep the pthread alive for asynchronous events.190err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' completed its pthread main entry point with an unwind, keeping the pthread worker alive for asynchronous operation.');191}192}193} else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.194if (Module['_pthread_self']()) {195Module['PThread'].threadCancel();196}197} else if (e.data.target === 'setimmediate') {198// no-op199} else if (e.data.cmd === 'processThreadQueue') {200if (Module['_pthread_self']()) { // If this thread is actually running?201Module['_emscripten_current_thread_process_queued_calls']();202}203} else {204err('worker.js received unknown command ' + e.data.cmd);205err(e.data);206}207} catch(ex) {208err('worker.js onmessage() captured an uncaught exception: ' + ex);209if (ex && ex.stack) err(ex.stack);210throw ex;211}212};213214215216217