diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2024-03-10 18:13:33 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2024-03-10 18:13:33 +0530 |
commit | 305b87aaa0c5a5fcab4295f83744831a5cb8586e (patch) | |
tree | 5979f725a00ae5f012068436f69e0856d714a5a3 /projects/chip8emu/chip8emu.worker.js | |
parent | c1927ab79c96435b325be26eaefda430e929d442 (diff) |
progress
Diffstat (limited to 'projects/chip8emu/chip8emu.worker.js')
-rw-r--r-- | projects/chip8emu/chip8emu.worker.js | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/projects/chip8emu/chip8emu.worker.js b/projects/chip8emu/chip8emu.worker.js new file mode 100644 index 0000000..50d45de --- /dev/null +++ b/projects/chip8emu/chip8emu.worker.js @@ -0,0 +1,189 @@ +/** + * @license + * Copyright 2015 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +// Pthread Web Worker startup routine: +// This is the entry point file that is loaded first by each Web Worker +// that executes pthreads on the Emscripten application. + +'use strict'; + +var Module = {}; + +// Node.js support +var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string'; +if (ENVIRONMENT_IS_NODE) { + // Create as web-worker-like an environment as we can. + + var nodeWorkerThreads = require('worker_threads'); + + var parentPort = nodeWorkerThreads.parentPort; + + parentPort.on('message', (data) => onmessage({ data: data })); + + var fs = require('fs'); + var vm = require('vm'); + + Object.assign(global, { + self: global, + require, + Module, + location: { + href: __filename + }, + Worker: nodeWorkerThreads.Worker, + importScripts: (f) => vm.runInThisContext(fs.readFileSync(f, 'utf8'), {filename: f}), + postMessage: (msg) => parentPort.postMessage(msg), + performance: global.performance || { now: Date.now }, + }); +} + +// Thread-local guard variable for one-time init of the JS state +var initializedJS = false; + +function assert(condition, text) { + if (!condition) abort('Assertion failed: ' + text); +} + +function threadPrintErr() { + var text = Array.prototype.slice.call(arguments).join(' '); + // See https://github.com/emscripten-core/emscripten/issues/14804 + if (ENVIRONMENT_IS_NODE) { + fs.writeSync(2, text + '\n'); + return; + } + console.error(text); +} +function threadAlert() { + var text = Array.prototype.slice.call(arguments).join(' '); + postMessage({cmd: 'alert', text, threadId: Module['_pthread_self']()}); +} +// We don't need out() for now, but may need to add it if we want to use it +// here. Or, if this code all moves into the main JS, that problem will go +// away. (For now, adding it here increases code size for no benefit.) +var out = () => { throw 'out() is not defined in worker.js.'; } +var err = threadPrintErr; +self.alert = threadAlert; +var dbg = threadPrintErr; + +Module['instantiateWasm'] = (info, receiveInstance) => { + // Instantiate from the module posted from the main thread. + // We can just use sync instantiation in the worker. + var module = Module['wasmModule']; + // We don't need the module anymore; new threads will be spawned from the main thread. + Module['wasmModule'] = null; + var instance = new WebAssembly.Instance(module, info); + // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, + // the above line no longer optimizes out down to the following line. + // When the regression is fixed, we can remove this if/else. + return receiveInstance(instance); +} + +// Turn unhandled rejected promises into errors so that the main thread will be +// notified about them. +self.onunhandledrejection = (e) => { + throw e.reason || e; +}; + +function handleMessage(e) { + try { + if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code. + + // Until we initialize the runtime, queue up any further incoming messages. + let messageQueue = []; + self.onmessage = (e) => messageQueue.push(e); + + // And add a callback for when the runtime is initialized. + self.startWorker = (instance) => { + // Notify the main thread that this thread has loaded. + postMessage({ 'cmd': 'loaded' }); + // Process any messages that were queued before the thread was ready. + for (let msg of messageQueue) { + handleMessage(msg); + } + // Restore the real message handler. + self.onmessage = handleMessage; + }; + + // Module and memory were sent from main thread + Module['wasmModule'] = e.data.wasmModule; + + // Use `const` here to ensure that the variable is scoped only to + // that iteration, allowing safe reference from a closure. + for (const handler of e.data.handlers) { + Module[handler] = (...args) => { + postMessage({ cmd: 'callHandler', handler, args: args }); + } + } + + Module['wasmMemory'] = e.data.wasmMemory; + + Module['buffer'] = Module['wasmMemory'].buffer; + + Module['workerID'] = e.data.workerID; + + Module['ENVIRONMENT_IS_PTHREAD'] = true; + + if (typeof e.data.urlOrBlob == 'string') { + importScripts(e.data.urlOrBlob); + } else { + var objectUrl = URL.createObjectURL(e.data.urlOrBlob); + importScripts(objectUrl); + URL.revokeObjectURL(objectUrl); + } + } else if (e.data.cmd === 'run') { + // Pass the thread address to wasm to store it for fast access. + Module['__emscripten_thread_init'](e.data.pthread_ptr, /*is_main=*/0, /*is_runtime=*/0, /*can_block=*/1); + + // Await mailbox notifications with `Atomics.waitAsync` so we can start + // using the fast `Atomics.notify` notification path. + Module['__emscripten_thread_mailbox_await'](e.data.pthread_ptr); + + assert(e.data.pthread_ptr); + // Also call inside JS module to set up the stack frame for this pthread in JS module scope + Module['establishStackSpace'](); + Module['PThread'].receiveObjectTransfer(e.data); + Module['PThread'].threadInitTLS(); + + if (!initializedJS) { + initializedJS = true; + } + + try { + Module['invokeEntryPoint'](e.data.start_routine, e.data.arg); + } catch(ex) { + if (ex != 'unwind') { + // The pthread "crashed". Do not call `_emscripten_thread_exit` (which + // would make this thread joinable). Instead, re-throw the exception + // and let the top level handler propagate it back to the main thread. + throw ex; + } + } + } else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread. + if (Module['_pthread_self']()) { + Module['__emscripten_thread_exit'](-1); + } + } else if (e.data.target === 'setimmediate') { + // no-op + } else if (e.data.cmd === 'checkMailbox') { + if (initializedJS) { + Module['checkMailbox'](); + } + } else if (e.data.cmd) { + // The received message looks like something that should be handled by this message + // handler, (since there is a e.data.cmd field present), but is not one of the + // recognized commands: + err(`worker.js received unknown command ${e.data.cmd}`); + err(e.data); + } + } catch(ex) { + err(`worker.js onmessage() captured an uncaught exception: ${ex}`); + if (ex?.stack) err(ex.stack); + Module['__emscripten_thread_crashed']?.(); + throw ex; + } +}; + +self.onmessage = handleMessage; |