dcp-client 4.1.13 → 4.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dcp-client.js +2 -1
- package/dist/dcp-client-bundle.js +102 -88
- package/generated/sandbox-definitions.json +1 -1
- package/index.js +3 -3
- package/lib/standaloneWorker.js +11 -1
- package/libexec/evaluator-node.js +27 -22
- package/libexec/sandbox/access-lists.js +3 -2
- package/libexec/sandbox/bootstrap.js +4 -4
- package/libexec/sandbox/bravojs-env.js +1 -1
- package/libexec/sandbox/calculate-capabilities.js +1 -1
- package/libexec/sandbox/event-loop-virtualization.js +140 -123
- package/libexec/sandbox/native-event-loop.js +237 -0
- package/libexec/sandbox/primitive-timers.js +6 -0
- package/libexec/sandbox/sa-ww-simulation.js +6 -23
- package/libexec/sandbox/script-load-wrapper.js +16 -1
- package/libexec/sandbox/wrap-event-listeners.js +38 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"browser":["deny-node","kvin/kvin.js","script-load-wrapper","
|
|
1
|
+
{"browser":["deny-node","kvin/kvin.js","script-load-wrapper","wrap-event-listeners","event-loop-virtualization","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"node":["kvin/kvin.js","sa-ww-simulation","script-load-wrapper","wrap-event-listeners","event-loop-virtualization","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"native":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","event-loop-virtualization","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap"],"webGpuNative":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","event-loop-virtualization","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","webgpu-worker-environment.js","bootstrap"],"nodeTesting":["kvin/kvin.js","sa-ww-simulation","script-load-wrapper","wrap-event-listeners","event-loop-virtualization","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap","testing.js"],"testing":["deny-node","kvin/kvin.js","sa-ww-simulation","script-load-wrapper","native-event-loop","wrap-event-listeners","event-loop-virtualization","access-lists","bravojs-init","bravojs/bravo.js","bravojs-env","calculate-capabilities","bootstrap","testing.js"]}
|
package/index.js
CHANGED
|
@@ -29,6 +29,7 @@ const os = require('os');
|
|
|
29
29
|
const fs = require('fs')
|
|
30
30
|
const path = require('path');
|
|
31
31
|
const process = require('process');
|
|
32
|
+
const kvin = require('kvin');
|
|
32
33
|
const moduleSystem = require('module');
|
|
33
34
|
const { spawnSync } = require('child_process');
|
|
34
35
|
const { createContext, runInContext } = require('vm');
|
|
@@ -690,7 +691,6 @@ exports.initSync = function dcpClient$$initSync() {
|
|
|
690
691
|
finalBundleCode = exports.fetchSync(finalBundleURL);
|
|
691
692
|
} catch(e) {
|
|
692
693
|
console.error('Error downloading autoUpdate bundle from ' + finalBundleURL);
|
|
693
|
-
console.log(require('dcp/utils').justFetchPrettyError(e));
|
|
694
694
|
throw e;
|
|
695
695
|
}
|
|
696
696
|
}
|
|
@@ -810,7 +810,7 @@ exports.createAggregateConfig = async function dcpClient$$createAggregateConfig(
|
|
|
810
810
|
if (!aggrConfig.scheduler.configLocation &&
|
|
811
811
|
aggrConfig.scheduler.configLocation !== false) {
|
|
812
812
|
addConfigs(aggrConfig.scheduler, localConfig.scheduler, {
|
|
813
|
-
configLocation: new URL(`${aggrConfig.scheduler.location}etc/dcp-config.
|
|
813
|
+
configLocation: new URL(`${aggrConfig.scheduler.location}etc/dcp-config.kvin`)
|
|
814
814
|
});
|
|
815
815
|
}
|
|
816
816
|
|
|
@@ -822,9 +822,9 @@ exports.createAggregateConfig = async function dcpClient$$createAggregateConfig(
|
|
|
822
822
|
try {
|
|
823
823
|
debugging() && console.debug(` * Loading configuration from ${aggrConfig.scheduler.configLocation.href}`);
|
|
824
824
|
remoteConfigCode = await require('dcp/protocol').fetchSchedulerConfig(aggrConfig.scheduler.configLocation);
|
|
825
|
+
remoteConfigCode = kvin.deserialize(remoteConfigCode);
|
|
825
826
|
} catch(e) {
|
|
826
827
|
console.error('Error: dcp-client::init could not fetch scheduler configuration at', '' + aggrConfig.scheduler.configLocation);
|
|
827
|
-
console.log(require('dcp/utils').justFetchPrettyError(e));
|
|
828
828
|
throw e;
|
|
829
829
|
}
|
|
830
830
|
if (remoteConfigCode.length === 0)
|
package/lib/standaloneWorker.js
CHANGED
|
@@ -93,6 +93,10 @@ function StandaloneWorker(options = {}) {
|
|
|
93
93
|
socket.setNoDelay(dcpConfig.worker ? dcpConfig.worker.nagle : true);
|
|
94
94
|
socket.connect(port, hostname);
|
|
95
95
|
socket.on('connect', beginSession.bind(this));
|
|
96
|
+
socket.on('end', () => {
|
|
97
|
+
connected = false;
|
|
98
|
+
ee.emit('end')
|
|
99
|
+
})
|
|
96
100
|
socket.on('error', function saWorker$$socket$errorHandler(e) {
|
|
97
101
|
connecting = false;
|
|
98
102
|
if (!dcpConfig.standaloneWorker.quiet)
|
|
@@ -279,7 +283,7 @@ function StandaloneWorker(options = {}) {
|
|
|
279
283
|
/* Shutdown the stream(s) which are connected to the evaluator */
|
|
280
284
|
shutdown = (e) => {
|
|
281
285
|
if (connectTimer) {
|
|
282
|
-
|
|
286
|
+
clearBackoffInterval(connectTimer);
|
|
283
287
|
connectTimer = true;
|
|
284
288
|
}
|
|
285
289
|
|
|
@@ -309,6 +313,7 @@ function StandaloneWorker(options = {}) {
|
|
|
309
313
|
* type DIE:, which in turn eventuallys triggers shutdown.
|
|
310
314
|
*/
|
|
311
315
|
this.terminate = function standaloneWorker$$Worker$terminate () {
|
|
316
|
+
debugging() && console.log(`312: saw.terminate on Evaluator ${this.serial}`);
|
|
312
317
|
var wrappedMessage = this.serialize({ type: 'die' }) + '\n'
|
|
313
318
|
|
|
314
319
|
try {
|
|
@@ -317,6 +322,11 @@ function StandaloneWorker(options = {}) {
|
|
|
317
322
|
// Socket may have already been destroyed
|
|
318
323
|
}
|
|
319
324
|
|
|
325
|
+
if (connectTimer) {
|
|
326
|
+
clearBackoffInterval(connectTimer);
|
|
327
|
+
connectTimer = true;
|
|
328
|
+
}
|
|
329
|
+
|
|
320
330
|
/* If DIE: response doesn't arrive in a reasonable time -- clean up */
|
|
321
331
|
dieTimer = setTimeout(shutdown, 7000);
|
|
322
332
|
}
|
|
@@ -84,29 +84,34 @@ exports.Evaluator = function Evaluator(inputStream, outputStream, files) {
|
|
|
84
84
|
codeGeneration: { strings: true, wasm: true },
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
if(files) {
|
|
88
|
+
for(const file of files) {
|
|
89
|
+
fd = fs.openSync(file, 'r');
|
|
90
|
+
if (mmap) {
|
|
91
|
+
fs.flockSync(fd, 'sh');
|
|
92
|
+
bootstrapCode = mmap.map(fs.fstatSync(fd).size, mmap.PROT_READ, mmap.MAP_SHARED, fd, 0, mmap.MADV_SEQUENTIAL).toString('utf8');
|
|
93
|
+
} else {
|
|
94
|
+
bootstrapCode = fs.readFileSync(fd, 'utf-8');
|
|
95
|
+
}
|
|
96
|
+
fs.closeSync(fd);
|
|
97
|
+
|
|
98
|
+
vm.runInContext(bootstrapCode, this.sandboxGlobal, {
|
|
99
|
+
filename: path.basename(file),
|
|
100
|
+
lineOffset: 0,
|
|
101
|
+
columnOffset: 0,
|
|
102
|
+
contextName: 'Evaluator #' + this.id,
|
|
103
|
+
contextCodeGeneration: {
|
|
104
|
+
wasm: true,
|
|
105
|
+
strings: true
|
|
106
|
+
},
|
|
107
|
+
displayErrors: true,
|
|
108
|
+
timeout: 3600 * 1000, /* gives us our own event loop; this is max time for one pass run-to-completion */
|
|
109
|
+
breakOnSigInt: true /* also gives us our own event loop */
|
|
110
|
+
});
|
|
94
111
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
filename: path.basename(file),
|
|
99
|
-
lineOffset: 0,
|
|
100
|
-
columnOffset: 0,
|
|
101
|
-
contextName: 'Evaluator #' + this.id,
|
|
102
|
-
contextCodeGeneration: {
|
|
103
|
-
wasm: true,
|
|
104
|
-
strings: true
|
|
105
|
-
},
|
|
106
|
-
displayErrors: true,
|
|
107
|
-
timeout: 3600 * 1000, /* gives us our own event loop; this is max time for one pass run-to-completion */
|
|
108
|
-
breakOnSigInt: true /* also gives us our own event loop */
|
|
109
|
-
});
|
|
112
|
+
} else {
|
|
113
|
+
console.error('There are no files to run in the node evaluator -- this is ok in the presence of other errors.');
|
|
114
|
+
process.exit(1);
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
/* Pass any new data on the input stream to the onreadln()
|
|
@@ -84,6 +84,7 @@ self.wrapScriptLoading({ scriptName: 'access-lists', ringTransition: true }, (ri
|
|
|
84
84
|
'Set',
|
|
85
85
|
'setInterval',
|
|
86
86
|
'setTimeout',
|
|
87
|
+
'setImmediate',
|
|
87
88
|
'sleep',
|
|
88
89
|
'String',
|
|
89
90
|
'Symbol',
|
|
@@ -560,11 +561,11 @@ self.wrapScriptLoading({ scriptName: 'access-lists', ringTransition: true }, (ri
|
|
|
560
561
|
|
|
561
562
|
addEventListener('message', async (event) => {
|
|
562
563
|
try {
|
|
563
|
-
if (event.
|
|
564
|
+
if (event.request === 'applyRequirements') {
|
|
564
565
|
// This event is fired when the worker is initialized with job requirements,
|
|
565
566
|
// apply restrictions to the environment based on the requirements.
|
|
566
567
|
// Assume the scheduler gave us a nicely-shaped req object.
|
|
567
|
-
const requirements = event.
|
|
568
|
+
const requirements = event.requirements;
|
|
568
569
|
blockList.OffscreenCanvas = !requirements.environment.offscreenCanvas;
|
|
569
570
|
applyAllAccessLists();
|
|
570
571
|
|
|
@@ -22,11 +22,11 @@ self.wrapScriptLoading({ scriptName: 'bootstrap', finalScript: true }, (ring2Pos
|
|
|
22
22
|
addEventListener('message', async (event) => {
|
|
23
23
|
try {
|
|
24
24
|
var indirectEval = eval // eslint-disable-line
|
|
25
|
-
if (event.
|
|
25
|
+
if (event.request === 'eval') {
|
|
26
26
|
try {
|
|
27
|
-
let result = await indirectEval(event.data
|
|
27
|
+
let result = await indirectEval(event.data, event.filename)
|
|
28
28
|
ring2PostMessage({
|
|
29
|
-
request: `evalResult::${event.
|
|
29
|
+
request: `evalResult::${event.msgId}`,
|
|
30
30
|
data: result
|
|
31
31
|
})
|
|
32
32
|
} catch (error) {
|
|
@@ -42,7 +42,7 @@ self.wrapScriptLoading({ scriptName: 'bootstrap', finalScript: true }, (ring2Pos
|
|
|
42
42
|
}
|
|
43
43
|
})
|
|
44
44
|
}
|
|
45
|
-
} else if (event.
|
|
45
|
+
} else if (event.request === 'resetState') {
|
|
46
46
|
// This event is fired when the web worker is about to be reused with another slice
|
|
47
47
|
lastProgress = 0;
|
|
48
48
|
postMessageSentTime = 0;
|
|
@@ -23,7 +23,7 @@ self.wrapScriptLoading({ scriptName: 'bravojs-env', ringTransition: true }, (rin
|
|
|
23
23
|
}
|
|
24
24
|
//Listens for postMessage from the sandbox
|
|
25
25
|
addEventListener('message', async (event) => {
|
|
26
|
-
let message = event
|
|
26
|
+
let message = event
|
|
27
27
|
let indirectEval = eval // eslint-disable-line
|
|
28
28
|
switch (message.request) {
|
|
29
29
|
case 'moduleGroup': /* Outside environment is sending us a module group */
|
|
@@ -173,7 +173,7 @@ self.wrapScriptLoading(
|
|
|
173
173
|
|
|
174
174
|
addEventListener('message', async (event) => {
|
|
175
175
|
try {
|
|
176
|
-
if (event.
|
|
176
|
+
if (event.request === 'describe') {
|
|
177
177
|
const capabilities = await getCapabilities();
|
|
178
178
|
ring2PostMessage({
|
|
179
179
|
capabilities,
|
|
@@ -5,87 +5,71 @@
|
|
|
5
5
|
* This gives DCP introspection capability to see how long a job
|
|
6
6
|
* should take, and how we can pay DCCs accordingly.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* should need servicing based on the information provided to nextTimer().
|
|
13
|
-
* - nextTimer() sets when the next timer will be fired (in ms)
|
|
14
|
-
* - evalTimer evaluates using either the actual setImmediate/setTimeout or uses
|
|
15
|
-
* Promise.resolve.then as a fallback
|
|
16
|
-
*
|
|
17
|
-
* Once this file has run, the following methods will be
|
|
18
|
-
* available on the global object for every evaluator:
|
|
19
|
-
* - setTimeout() execute callback after minimum timeout time in ms
|
|
20
|
-
* - clearTimeout() clear the timeout created by setTimeout
|
|
21
|
-
* - setInterval() recurringly execute callback after minimum timeout time in ms
|
|
22
|
-
* - clearInterval() clear the interval created by setInterval
|
|
23
|
-
* - queueMicrotask() add a microtask to the microtask queue, bypassing 4ms timeout clamping
|
|
8
|
+
* All evaluators have their own implementation of the event loop at this
|
|
9
|
+
* point, with corresponding timeout functions for their loop. This file will
|
|
10
|
+
* create a wrapper for each of the timeouts, with a virtual event loop
|
|
11
|
+
* to control code execution.
|
|
24
12
|
*
|
|
25
|
-
*
|
|
26
|
-
* @date
|
|
13
|
+
* Ryan Saweczko, ryansaweczko@kingsds.network
|
|
14
|
+
* @date January 2022
|
|
27
15
|
*
|
|
28
|
-
* @note Unusual function scoping is done to eliminate spurious symbols
|
|
29
|
-
* from being accessible from the global object, to mitigate
|
|
30
|
-
* certain classes of security risks. The global object here is
|
|
31
|
-
* the top of the scope chain (ie global object) for all code run
|
|
32
|
-
* by hosts in this environment.
|
|
33
16
|
*/
|
|
34
|
-
/* globals self
|
|
17
|
+
/* globals self */
|
|
18
|
+
|
|
35
19
|
|
|
36
20
|
self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, (ring0PostMessage) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
timers.serial = 0; /* If this isn't set, it becomes NaN */
|
|
46
|
-
|
|
47
|
-
function sortTimers() {
|
|
48
|
-
timers.sort(function (a, b) { return a.when - b.when; });
|
|
21
|
+
|
|
22
|
+
(function privateScope(realSetTimeout, realSetInterval, realSetImmediate, realClearTimeout, realClearInterval, realClearImmediate) {
|
|
23
|
+
let totalCPUTime = 0;
|
|
24
|
+
const events = [];
|
|
25
|
+
events.serial = 0;
|
|
26
|
+
|
|
27
|
+
function sortEvents() {
|
|
28
|
+
events.sort(function (a, b) { return a.when - b.when; });
|
|
49
29
|
}
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
31
|
+
function serviceEvents()
|
|
32
|
+
{
|
|
33
|
+
serviceEvents.timeout = null;
|
|
34
|
+
serviceEvents.nextTimeout = null;
|
|
35
|
+
serviceEvents.servicing = true;
|
|
56
36
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
let timer = timers[i];
|
|
60
|
-
if (timer.when > now) {
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
37
|
+
const startTime = performance.now();
|
|
38
|
+
let now = Date.now();
|
|
63
39
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
40
|
+
sortEvents();
|
|
41
|
+
if (events[0].when <= now)
|
|
42
|
+
{
|
|
43
|
+
const event = events.shift();
|
|
44
|
+
if (event.eventType === 'timer')
|
|
45
|
+
{
|
|
46
|
+
serviceEvents.executingTimeout = realSetTimeout(event.fn, 0, event.args);
|
|
47
|
+
if (event.recur)
|
|
48
|
+
{
|
|
49
|
+
event.when = Date.now() + event.recur;
|
|
50
|
+
events.push(event);
|
|
51
|
+
sortEvents();
|
|
70
52
|
}
|
|
71
|
-
|
|
72
|
-
lastTimeStamp = performance.now();
|
|
73
|
-
await timer.fn();
|
|
74
|
-
lastTimeStamp = performance.now();
|
|
75
53
|
}
|
|
76
|
-
|
|
54
|
+
// Can add handles for events to the event loop as needed (ie messages)
|
|
55
|
+
}
|
|
77
56
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
57
|
+
// Measure the time on the event loop after everything has executed
|
|
58
|
+
serviceEvents.measurerTimeout = realSetTimeout(endOfRealEventCycle,1);
|
|
59
|
+
function endOfRealEventCycle()
|
|
60
|
+
{
|
|
61
|
+
serviceEvents.servicing = false;
|
|
62
|
+
const endTime = performance.now();
|
|
63
|
+
totalCPUTime += endTime - startTime;
|
|
64
|
+
|
|
65
|
+
// Set timeout to rerun this function if there are events remaining that just can't be used yet
|
|
66
|
+
if (events.length > 0)
|
|
67
|
+
{
|
|
68
|
+
serviceEvents.nextTimeout = events[0].when
|
|
69
|
+
serviceEvents.timeout = realSetTimeout(serviceEvents, events[0].when - Date.now());
|
|
82
70
|
}
|
|
83
71
|
}
|
|
84
|
-
|
|
85
|
-
sortTimers();
|
|
86
|
-
nextTimer(timers[0].when);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
72
|
+
}
|
|
89
73
|
|
|
90
74
|
/** Execute callback after at least timeout ms.
|
|
91
75
|
*
|
|
@@ -94,7 +78,8 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, (ring0PostMe
|
|
|
94
78
|
* @param arg array of arguments to be applied to the callback function
|
|
95
79
|
* @returns {object} A value which may be used as the timeoutId parameter of clearTimeout()
|
|
96
80
|
*/
|
|
97
|
-
|
|
81
|
+
setTimeout = function eventLoop$$Worker$setTimeout(callback, timeout, arg) {
|
|
82
|
+
timeout = timeout || 0;
|
|
98
83
|
let timer, args;
|
|
99
84
|
if (typeof callback === 'string') {
|
|
100
85
|
let code = callback;
|
|
@@ -112,18 +97,30 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, (ring0PostMe
|
|
|
112
97
|
callback = () => fn.apply(fn, args); // apply the arguments to the callback function
|
|
113
98
|
}
|
|
114
99
|
|
|
115
|
-
|
|
100
|
+
events.serial = +events.serial + 1;
|
|
116
101
|
timer = {
|
|
102
|
+
eventType: 'timer',
|
|
117
103
|
fn: callback,
|
|
118
104
|
when: Date.now() + (+timeout || 0),
|
|
119
|
-
serial:
|
|
105
|
+
serial: events.serial,
|
|
120
106
|
valueOf: function () { return this.serial; }
|
|
121
107
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
108
|
+
events.push(timer);
|
|
109
|
+
sortEvents();
|
|
110
|
+
if (!serviceEvents.servicing)
|
|
111
|
+
{
|
|
112
|
+
if (!serviceEvents.nextTimeout)
|
|
113
|
+
{
|
|
114
|
+
realSetTimeout(serviceEvents, events[0].when - Date.now());
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
{
|
|
118
|
+
if (serviceEvents.nextTimeout > events[0].when)
|
|
119
|
+
{
|
|
120
|
+
realClearTimeout(serviceEvents.timeout);
|
|
121
|
+
realSetTimeout(serviceEvents, events[0].when - Date.now())
|
|
122
|
+
}
|
|
123
|
+
}
|
|
127
124
|
}
|
|
128
125
|
return timer;
|
|
129
126
|
}
|
|
@@ -133,42 +130,38 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, (ring0PostMe
|
|
|
133
130
|
*
|
|
134
131
|
* @param timeoutId {object} The value, returned from setTimeout(), identifying the timer.
|
|
135
132
|
*/
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
*
|
|
147
|
-
* for example:
|
|
148
|
-
* const timeout = setTimeout(() => console.log("hi"), 10000);
|
|
149
|
-
* clearTimeout(timeout);
|
|
150
|
-
*
|
|
151
|
-
* used to still wait 10 seconds before closing the program, despite never printing hi to the console
|
|
152
|
-
*/
|
|
153
|
-
if (timers.length) {
|
|
154
|
-
nextTimer(timers[0].when);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
nextTimer(0);
|
|
133
|
+
clearTimeout = function eventLoop$$Worker$clearTimeout(timeoutId)
|
|
134
|
+
{
|
|
135
|
+
function checkService()
|
|
136
|
+
{
|
|
137
|
+
if (!serviceEvents.servicing)
|
|
138
|
+
{
|
|
139
|
+
if (events.length)
|
|
140
|
+
{
|
|
141
|
+
realClearTimeout(serviceEvents.timeout);
|
|
142
|
+
realSetTimeout(serviceEvents, events[0].when - Date.now())
|
|
158
143
|
}
|
|
144
|
+
else
|
|
145
|
+
realClearTimeout(serviceEvents.timeout);
|
|
159
146
|
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
147
|
+
}
|
|
148
|
+
if (typeof timeoutId === "object")
|
|
149
|
+
{
|
|
150
|
+
let i = events.indexOf(timeoutId);
|
|
151
|
+
if (i !== -1)
|
|
152
|
+
events.splice(i, 1);
|
|
153
|
+
if (i === 0)
|
|
154
|
+
checkService()
|
|
155
|
+
}
|
|
156
|
+
else if (typeof timeoutId === "number")
|
|
157
|
+
{ /* slow path - object has been reinterpreted in terms of valueOf() */
|
|
158
|
+
for (let i = 0; i < events.length; i++)
|
|
159
|
+
{
|
|
160
|
+
if (events[i].serial === timeoutId)
|
|
161
|
+
{
|
|
162
|
+
events.splice(i, 1);
|
|
163
|
+
if (i === 0)
|
|
164
|
+
checkService()
|
|
172
165
|
break;
|
|
173
166
|
}
|
|
174
167
|
}
|
|
@@ -182,41 +175,63 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, (ring0PostMe
|
|
|
182
175
|
* @param arg array of arguments to be applied to the callback function
|
|
183
176
|
* @returns {object} A value which may be used as the intervalId paramter of clearInterval()
|
|
184
177
|
*/
|
|
185
|
-
|
|
186
|
-
|
|
178
|
+
setInterval = function eventLoop$$Worker$setInterval(callback, interval, arg)
|
|
179
|
+
{
|
|
180
|
+
let timer = setTimeout(callback, +interval || 0, arg);
|
|
187
181
|
timer.recur = interval;
|
|
188
182
|
return timer;
|
|
189
183
|
}
|
|
184
|
+
/** Execute callback after 0 ms, immediately when the event loop allows.
|
|
185
|
+
*
|
|
186
|
+
* @param callback {function} Callback function to fire after a minimum callback time
|
|
187
|
+
* @param arg array of arguments to be applied to the callback function
|
|
188
|
+
* @returns {object} A value which may be used as the intervalId paramter of clearImmediate()
|
|
189
|
+
*/
|
|
190
|
+
setImmediate = function eventLoop$$Worker$setImmediate(callback, arg) {
|
|
191
|
+
let timer = setTimeout(callback, 0, arg);
|
|
192
|
+
return timer;
|
|
193
|
+
}
|
|
190
194
|
|
|
191
195
|
/** Remove an interval timer from the list of pending interval timers, regardless of its current
|
|
192
196
|
* status. (Same as clearTimeout)
|
|
193
197
|
*
|
|
194
198
|
* @param intervalId {object} The value, returned from setInterval(), identifying the timer.
|
|
195
199
|
*/
|
|
196
|
-
|
|
200
|
+
clearInterval = clearTimeout;
|
|
201
|
+
clearImmediate = clearTimeout
|
|
197
202
|
|
|
198
203
|
/** queues a microtask to be executed at a safe time prior to control returning to the event loop
|
|
199
204
|
*
|
|
200
205
|
* @param callback {function} Callback function to fire
|
|
201
206
|
*/
|
|
202
|
-
|
|
207
|
+
queueMicrotask = function eventLoop$$Worker$queueMicrotask(callback) {
|
|
203
208
|
Promise.resolve().then(callback);
|
|
204
209
|
}
|
|
205
210
|
|
|
206
211
|
function clearAllTimers() {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
212
|
+
events.length = 0;
|
|
213
|
+
realClearTimeout(serviceEvents.timeout);
|
|
214
|
+
realClearTimeout(serviceEvents.measurerTimeout);
|
|
215
|
+
realClearTimeout(serviceEvents.executingTimeout);
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
addEventListener('message', async (event) => {
|
|
213
219
|
try {
|
|
214
|
-
if (event.
|
|
220
|
+
if (event.request === 'clearTimers') {
|
|
215
221
|
clearAllTimers();
|
|
216
222
|
ring0PostMessage({
|
|
217
223
|
request: 'clearTimersDone',
|
|
218
224
|
});
|
|
219
225
|
}
|
|
226
|
+
else if (event.request === 'resetAndGetCPUTime')
|
|
227
|
+
{
|
|
228
|
+
const cpuTime = totalCPUTime;
|
|
229
|
+
totalCPUTime = 0;
|
|
230
|
+
ring0PostMessage({
|
|
231
|
+
request: 'totalCPUTime',
|
|
232
|
+
CPU: cpuTime
|
|
233
|
+
})
|
|
234
|
+
}
|
|
220
235
|
} catch (error) {
|
|
221
236
|
ring0PostMessage({
|
|
222
237
|
request: 'error',
|
|
@@ -228,10 +243,12 @@ self.wrapScriptLoading({ scriptName: 'event-loop-virtualization' }, (ring0PostMe
|
|
|
228
243
|
});
|
|
229
244
|
}
|
|
230
245
|
});
|
|
231
|
-
})(self.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
246
|
+
})(self.setTimeout, self.setInterval, self.setImmediate, self.clearTimeout, self.clearInterval, self.clearImmediate);
|
|
247
|
+
|
|
248
|
+
self.setTimeout = setTimeout;
|
|
249
|
+
self.setInterval = setInterval;
|
|
250
|
+
self.setImmediate = setImmediate;
|
|
251
|
+
self.clearTimeout = clearTimeout;
|
|
252
|
+
self.clearInterval = clearInterval;
|
|
253
|
+
self.clearImmediate = clearImmediate;
|
|
237
254
|
});
|