forked from cryptool-org/wasm-webterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWasmWorker.js
112 lines (82 loc) · 3.75 KB
/
WasmWorker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import * as Comlink from "comlink" // todo: maybe only import Comlink.expose?
import WasmRunner from "./WasmRunner"
class WasmWorker extends WasmRunner {
_pauseBuffer
_stdinBuffer
constructor(pauseBuffer, stdinBuffer) { super()
// buffers can be accessed both from the main thread and the worker
this._pauseBuffer = pauseBuffer // used to pause/resume worker execution
this._stdinBuffer = stdinBuffer // used to pass user inputs to worker
}
// note: running commands is handled by parent class
/* pausing and resuming */
pauseExecution() {
console.log("pausing worker execution")
Atomics.store(this._pauseBuffer, 0, 1) // mem[0] = 1 (means hold)
Atomics.wait(this._pauseBuffer, 0, 1) // wait while value is 1
console.log("resuming worker execution")
}
resumeExecution() {
console.log("resuming worker execution")
Atomics.store(this._pauseBuffer, 0, 0) // mem[0] = 0 (means do not hold)
// note: this method is just for completeness (the worker will be
// resumed from outside by changing the pause buffer value)
}
/* input output handling */
_readStdinBuffer(index = null) { // null = read all
if(index != null) return Atomics.load(this._stdinBuffer, index)
let result = []
for(let i = 0; i < this._stdinBuffer.length; i++) {
const value = Atomics.load(this._stdinBuffer, i)
if(value === 0) break // 0 marks end of input
result.push(value)
}
return result
}
// handles stdin calls from emscr (pause -> call stdin proxy -> deliver)
_onEmscrStdinCall(tty, stdinProxy, stdoutProxy, stderrProxy) {
if(tty.input.length == 0) {
// read input (will set stdin buffer)
stdinProxy(this.outputBuffer.split(/\r?\n/g).pop())
this.pauseExecution() // resumes after input
// copy stdin buffer to tty input
tty.input = this._readStdinBuffer()
this.outputBuffer += tty.input.map(c => String.fromCharCode(c)).join("")
if(tty.input.length == 0) return null
else tty.input.push(null) // marks end
}
// deliver input
return tty.input.shift()
}
// handles stdin calls from wasmer
_wasmerStdinCallCounter = 0
_onWasmerStdinCall(stdinBuffer, stdinProxy, stdoutProxy, stderrProxy) {
// second read means end of string
if(this._wasmerStdinCallCounter % 2 !== 0) {
this._wasmerStdinCallCounter++; return 0 }
// read input (will set stdin buffer)
stdinProxy(this.outputBuffer.split(/\r?\n/g).pop())
this.pauseExecution() // resumes after input
// copy stdin buffer to stdinBuffer
const _stdinBuffer = this._readStdinBuffer()
_stdinBuffer.forEach((char, i) => stdinBuffer[i] = char)
this.outputBuffer += _stdinBuffer.map(c => String.fromCharCode(c)).join("")
// indicate we've read once
this._wasmerStdinCallCounter++
// return how much to read
return _stdinBuffer.length
}
/* expose (sets up comlink communication) */
static expose() {
if(typeof Comlink == "undefined" && WasmWorker.isWorkerScope())
importScripts("https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/comlink.min.js")
// note: the bundle would get smaller if we would always load Comlink from CDN ..
Comlink.expose(WasmWorker)
}
static isWorkerScope() { // checks if script is executed in worker or main thread
return (typeof WorkerGlobalScope != "undefined" && self instanceof WorkerGlobalScope)
}
}
// if this runs in worker scope -> expose
if(WasmWorker.isWorkerScope()) WasmWorker.expose()
export default WasmWorker