@daugasauron/dolly 0.0.0-stage → 0.1.4-rc.1
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/LICENSE +21 -0
- package/README.md +89 -2
- package/dist/dolly-build-id.mjs +1 -0
- package/dist/dolly-dso-0.wasm +0 -0
- package/dist/dolly-image-build-id.mjs +1 -0
- package/dist/dolly-kernel-plugin-abi.mjs +2 -0
- package/dist/dolly-process-0.wasm +0 -0
- package/dist/dolly-process-abi.mjs +1 -0
- package/dist/dolly-process-dso.mjs +1575 -0
- package/dist/dolly-process-gate-0.wasm +0 -0
- package/dist/dolly-process-stack.mjs +50 -0
- package/dist/dolly-process-worker.mjs +275 -0
- package/dist/dolly-threads-0.wasm +0 -0
- package/dist/dolly.wasm +0 -0
- package/host/abi.mjs +5 -0
- package/host/dso/abi.mjs +13 -0
- package/host/dso/dso.mjs +26 -0
- package/host/dso/module.json +15 -0
- package/host/http/abi.mjs +28 -0
- package/host/http/broker.mjs +325 -0
- package/host/http/http.mjs +74 -0
- package/host/http/local-services.mjs +37 -0
- package/host/http/module.json +15 -0
- package/host/http/policy.mjs +293 -0
- package/host/modules.mjs +373 -0
- package/host/nena/abi.mjs +19 -0
- package/host/nena/module.json +15 -0
- package/host/nena/nena.mjs +131 -0
- package/host/packages/module.json +13 -0
- package/host/packages/packages.mjs +15 -0
- package/host/packages/service.mjs +59 -0
- package/host/requirements.mjs +62 -0
- package/host/runtime/abi.mjs +8 -0
- package/host/runtime/boot-files.mjs +45 -0
- package/host/runtime/grower.mjs +14 -0
- package/host/runtime/lease-bridge.mjs +65 -0
- package/host/runtime/module.json +16 -0
- package/host/runtime/runtime.mjs +209 -0
- package/host/snapshot/abi.mjs +16 -0
- package/host/snapshot/module.json +15 -0
- package/host/snapshot/snapshot.mjs +138 -0
- package/host/snapshot/transport.mjs +132 -0
- package/host/snapshot/ui.mjs +207 -0
- package/host/stack/abi.mjs +5 -0
- package/host/stack/module.json +17 -0
- package/host/stack/stack.mjs +19 -0
- package/host/threads/abi.mjs +8 -0
- package/host/threads/module.json +13 -0
- package/host/threads/threads.mjs +36 -0
- package/package.json +12 -4
- package/src/alphabetical.mjs +4 -0
- package/src/browser.mjs +237 -0
- package/src/build-log.mjs +30 -0
- package/src/image-entry.mjs +29 -0
- package/src/image-inputs.mjs +20 -0
- package/src/image-names.mjs +11 -0
- package/src/images.mjs +10 -0
- package/src/kernel-plugin.mjs +77 -0
- package/src/packaged-snapshot.mjs +175 -0
- package/src/page-chords.mjs +43 -0
- package/src/page-indicators.mjs +27 -0
- package/src/process-abi.mjs +69 -0
- package/src/process-constants.mjs +242 -0
- package/src/process-supervisor.mjs +1002 -0
- package/src/runtime-worker.mjs +55 -0
- package/src/session-store.mjs +198 -0
- package/src/snapshot-records.mjs +109 -0
- package/src/static-asset.mjs +97 -0
- package/src/terminal-text.mjs +72 -0
- package/src/version.mjs +3 -0
- package/src/wasm-interface.mjs +440 -0
- package/src/worker-image.mjs +137 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// What a recipe may name: an image, and the paths no image retains.
|
|
2
|
+
|
|
3
|
+
// Image names: [a-z][a-z0-9]*(-[a-z0-9]+|\.[0-9]+)*, at most 32 bytes. A dot
|
|
4
|
+
// starts a run of version digits, so a documentation copy such as
|
|
5
|
+
// Dollyfile-example.txt is never a recipe.
|
|
6
|
+
export const validName = name => /^[a-z][a-z0-9]*(?:-[a-z0-9]+|\.[0-9]+)*$/.test(name) && name.length <= 32;
|
|
7
|
+
|
|
8
|
+
// No image retains scratch space.
|
|
9
|
+
export function unretainedPath(value) {
|
|
10
|
+
return ["/tmp", "/workspace"].some((prefix) => value === prefix || value.startsWith(`${prefix}/`));
|
|
11
|
+
}
|
package/src/images.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// The images a page runs and where their files are. An image directory holds
|
|
2
|
+
// dist/dolly-images.mjs (its catalog), each image's metadata and packs under
|
|
3
|
+
// dist/, and the recipes and sources at their site paths. The site is one such
|
|
4
|
+
// directory; an embedding names its own (boot's `images`). The page and the
|
|
5
|
+
// Worker each load it once, before anything reads it.
|
|
6
|
+
export let DOLLY_IMAGES = [], DOLLY_STATIC_SOURCES = [], imageBase;
|
|
7
|
+
export async function loadImages(base) {
|
|
8
|
+
imageBase = new URL(base);
|
|
9
|
+
({ DOLLY_IMAGES, DOLLY_STATIC_SOURCES } = await import(new URL("dist/dolly-images.mjs", imageBase).href));
|
|
10
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { DOLLY_KERNEL_PLUGIN_ABI_DIGEST, DOLLY_KERNEL_PLUGIN_IMPORTS } from "../dist/dolly-kernel-plugin-abi.mjs";
|
|
2
|
+
import { hex } from "./static-asset.mjs";
|
|
3
|
+
import { Reader } from "./wasm-interface.mjs";
|
|
4
|
+
|
|
5
|
+
// Boot-only Wasm linking, not a browser capability imported by the guest.
|
|
6
|
+
// Inputs are bytes and real kernel Wasm exports. No paths, URLs, JavaScript
|
|
7
|
+
// callbacks, dependency loading, or ambient symbol lookup enter this module.
|
|
8
|
+
const maximumBytes = 64 * 1024 * 1024;
|
|
9
|
+
|
|
10
|
+
function allocationRequirements(module) {
|
|
11
|
+
const sections = WebAssembly.Module.customSections(module, "dylink.0");
|
|
12
|
+
if (sections.length !== 1) throw new TypeError("plugin needs one dylink.0 record");
|
|
13
|
+
const reader = new Reader(new Uint8Array(sections[0]), "plugin dylink.0");
|
|
14
|
+
// This profile has exactly the memory/table allocation subsection, with no
|
|
15
|
+
// NEEDED libraries, runtime paths, or other loader extensions.
|
|
16
|
+
if (reader.unsigned(8) !== 1n) throw new TypeError("unsupported plugin linking record");
|
|
17
|
+
const record = reader.subreader(reader.u32(), "plugin allocation record");
|
|
18
|
+
const size = record.unsigned(64);
|
|
19
|
+
const alignment = record.unsigned(32);
|
|
20
|
+
const tableSize = record.unsigned(64);
|
|
21
|
+
const tableAlignment = record.unsigned(32);
|
|
22
|
+
if (!reader.done || !record.done || size > BigInt(maximumBytes) || alignment > 20n ||
|
|
23
|
+
tableSize > 65536n || tableAlignment !== 0n) {
|
|
24
|
+
throw new TypeError("unsupported plugin allocation requirements");
|
|
25
|
+
}
|
|
26
|
+
return { size, alignment: 1n << alignment, tableSize };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function instantiateKernelPlugin(bytes, kernel, memory) {
|
|
30
|
+
if (!(bytes instanceof Uint8Array) || bytes.length < 8 || bytes.length > maximumBytes) {
|
|
31
|
+
throw new TypeError("invalid resident plugin bytes");
|
|
32
|
+
}
|
|
33
|
+
const module = new WebAssembly.Module(bytes);
|
|
34
|
+
const stamps = WebAssembly.Module.customSections(module, "dolly.abi");
|
|
35
|
+
if (stamps.length !== 1 || hex(stamps[0]) !== DOLLY_KERNEL_PLUGIN_ABI_DIGEST) {
|
|
36
|
+
throw new TypeError("resident plugin has the wrong ABI stamp");
|
|
37
|
+
}
|
|
38
|
+
for (const { name } of WebAssembly.Module.exports(module)) {
|
|
39
|
+
if (name.startsWith("__em_js__") || /^__(?:start|stop)_em_(?:asm|js)$/.test(name)) {
|
|
40
|
+
throw new TypeError("resident plugins cannot contain JavaScript bindings");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const table = kernel.__indirect_function_table;
|
|
44
|
+
const env = {
|
|
45
|
+
memory,
|
|
46
|
+
__indirect_function_table: table,
|
|
47
|
+
__stack_pointer: kernel.__stack_pointer,
|
|
48
|
+
__memory_base: undefined,
|
|
49
|
+
__table_base: undefined,
|
|
50
|
+
...Object.fromEntries(DOLLY_KERNEL_PLUGIN_IMPORTS.map(name => [name, kernel[name]])),
|
|
51
|
+
};
|
|
52
|
+
for (const imported of WebAssembly.Module.imports(module)) {
|
|
53
|
+
if (imported.module !== "env" || !Object.hasOwn(env, imported.name)) {
|
|
54
|
+
throw new TypeError(`unsupported resident plugin import: ${imported.module}.${imported.name}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const { size, alignment, tableSize } = allocationRequirements(module);
|
|
58
|
+
const allocation = kernel.malloc(size + alignment);
|
|
59
|
+
if (allocation === 0n) throw new RangeError("resident plugin allocation failed");
|
|
60
|
+
const base = (allocation + alignment - 1n) & -alignment;
|
|
61
|
+
const end = base + size;
|
|
62
|
+
if (base < 0n || end > BigInt(memory.buffer.byteLength)) {
|
|
63
|
+
throw new RangeError("resident plugin allocation is outside kernel memory");
|
|
64
|
+
}
|
|
65
|
+
// Code, table entries, and static data are resident until the kernel dies.
|
|
66
|
+
// In particular, never free storage after a partially instantiated module
|
|
67
|
+
// might have installed table entries pointing at it.
|
|
68
|
+
new Uint8Array(memory.buffer, Number(base), Number(size)).fill(0);
|
|
69
|
+
env.__memory_base = new WebAssembly.Global({ value: "i64" }, base);
|
|
70
|
+
env.__table_base = new WebAssembly.Global({ value: "i64" }, table.grow(tableSize));
|
|
71
|
+
// These are actual Wasm function exports, not JS forwarding wrappers. The
|
|
72
|
+
// engine checks their exact function types at this instantiation boundary.
|
|
73
|
+
const instance = new WebAssembly.Instance(module, { env });
|
|
74
|
+
instance.exports.__wasm_apply_data_relocs?.();
|
|
75
|
+
instance.exports.__wasm_call_ctors?.();
|
|
76
|
+
return instance;
|
|
77
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// The images of an image directory as the page and the Worker load them: each
|
|
2
|
+
// one's metadata, checked against the catalog and the recipes the directory
|
|
3
|
+
// serves, and its packs, streamed or whole.
|
|
4
|
+
import { DOLLY_IMAGE_BUILD_ID } from "../dist/dolly-image-build-id.mjs";
|
|
5
|
+
import { DOLLY_IMAGES, imageBase } from "./images.mjs";
|
|
6
|
+
import { imageInputs, imageInputsMatch } from "./image-inputs.mjs";
|
|
7
|
+
import { hostRequirements } from "../host/requirements.mjs";
|
|
8
|
+
import { siteReference, sitePath, decodeStaticAsset, sha256 } from "./static-asset.mjs";
|
|
9
|
+
import { mergeSnapshotRecords, validateSnapshotPacks, MAX_SNAPSHOT_BYTES as snapshotSizeLimit } from "./snapshot-records.mjs";
|
|
10
|
+
import { unretainedPath } from "./image-names.mjs";
|
|
11
|
+
const definitionOf = image => DOLLY_IMAGES.find(definition => definition.image === image);
|
|
12
|
+
const encoder = new TextEncoder();
|
|
13
|
+
const expectedRecipes = image => definitionOf(image).recipes;
|
|
14
|
+
|
|
15
|
+
function validSnapshotPath(path) {
|
|
16
|
+
return typeof path === "string" && path.startsWith("/") && path.length > 1 &&
|
|
17
|
+
path.length <= 4096 && !path.includes("\\") && !path.includes("\0") &&
|
|
18
|
+
!path.includes("//") &&
|
|
19
|
+
!path.split("/").some((part) => part === "." || part === "..") &&
|
|
20
|
+
!unretainedPath(path);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function verifyVisibleRecipes(recipes) {
|
|
24
|
+
for (const recipe of recipes) {
|
|
25
|
+
const response = await fetch(new URL(sitePath(recipe.sourcePath).slice(1), imageBase), {
|
|
26
|
+
cache: "no-store", credentials: "same-origin", redirect: "error",
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) throw new Error(`${recipe.sourcePath} returned HTTP ${response.status}`);
|
|
29
|
+
const bytes = await response.arrayBuffer();
|
|
30
|
+
if (bytes.byteLength !== recipe.byteLength || await sha256(bytes) !== recipe.sha256) {
|
|
31
|
+
throw new Error(`${recipe.sourcePath} does not match the packaged snapshot recipe`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function loadPackagedSnapshotMetadata(image, checked = new Map(), active = new Set()) {
|
|
37
|
+
if (checked.has(image)) return checked.get(image);
|
|
38
|
+
if (active.has(image)) throw new Error("packaged image cycle");
|
|
39
|
+
active.add(image);
|
|
40
|
+
const metadataUrl = new URL(
|
|
41
|
+
`dist/dolly-${image}-system-snapshot.mjs`, imageBase,
|
|
42
|
+
);
|
|
43
|
+
let metadata;
|
|
44
|
+
try {
|
|
45
|
+
({ DOLLY_SYSTEM_SNAPSHOT: metadata } = await import(metadataUrl.href));
|
|
46
|
+
} catch {
|
|
47
|
+
throw new Error(`The packaged ${image} snapshot is missing. Run npm run image -- ${image} first.`);
|
|
48
|
+
}
|
|
49
|
+
const recipes = expectedRecipes(image);
|
|
50
|
+
if (metadata === null || typeof metadata !== "object" ||
|
|
51
|
+
metadata.image !== image || metadata.buildId !== DOLLY_IMAGE_BUILD_ID ||
|
|
52
|
+
metadata.formatVersion !== 2 || metadata.identityVersion !== 2 ||
|
|
53
|
+
JSON.stringify(metadata.recipes) !== JSON.stringify(recipes) ||
|
|
54
|
+
JSON.stringify(hostRequirements(metadata.hostRequirements)) !== JSON.stringify(definitionOf(image).hostRequirements ?? []) ||
|
|
55
|
+
!Number.isSafeInteger(metadata.byteLength) || metadata.byteLength <= 0 ||
|
|
56
|
+
metadata.byteLength > snapshotSizeLimit ||
|
|
57
|
+
(![undefined, "gzip", "packs"].includes(metadata.encoding)) ||
|
|
58
|
+
(metadata.encoding === "gzip" &&
|
|
59
|
+
(!Number.isSafeInteger(metadata.encodedByteLength) ||
|
|
60
|
+
metadata.encodedByteLength <= 0 || metadata.encodedByteLength > snapshotSizeLimit)) ||
|
|
61
|
+
!/^[0-9a-f]{64}$/.test(metadata.sha256) ||
|
|
62
|
+
!Array.isArray(metadata.manifest) || metadata.manifest.length === 0 ||
|
|
63
|
+
metadata.manifest.length > 100_000) {
|
|
64
|
+
throw new Error("The packaged system snapshot metadata does not match this Dolly build");
|
|
65
|
+
}
|
|
66
|
+
if (metadata.encoding === "packs") validateSnapshotPacks(metadata);
|
|
67
|
+
const inputs = imageInputs(metadata.inputs);
|
|
68
|
+
const references = [...new Set(definitionOf(image).artifacts.map(reference => reference.sha256))].sort();
|
|
69
|
+
if (JSON.stringify(inputs.map(input => input.recipeSha256)) !== JSON.stringify(references)) {
|
|
70
|
+
throw new Error("The packaged system snapshot has stale image inputs");
|
|
71
|
+
}
|
|
72
|
+
let manifestBytes = 0;
|
|
73
|
+
// The Wasm reader validates ordering by UTF-8 bytes, not JS UTF-16 strings.
|
|
74
|
+
for (const path of metadata.manifest) {
|
|
75
|
+
if (!validSnapshotPath(path)) {
|
|
76
|
+
throw new Error("The packaged system snapshot has an invalid retained-path manifest");
|
|
77
|
+
}
|
|
78
|
+
manifestBytes += encoder.encode(path).byteLength + 1;
|
|
79
|
+
}
|
|
80
|
+
if (manifestBytes > 8 * 1024 * 1024) {
|
|
81
|
+
throw new Error("The packaged system snapshot manifest is too large");
|
|
82
|
+
}
|
|
83
|
+
for (const required of [
|
|
84
|
+
"/etc/dolly/Dollyfile",
|
|
85
|
+
"/etc/dolly/environment",
|
|
86
|
+
"/etc/dolly/image",
|
|
87
|
+
"/etc/dolly/recipes.lock",
|
|
88
|
+
]) {
|
|
89
|
+
if (!metadata.manifest.includes(required)) {
|
|
90
|
+
throw new Error(`The packaged system snapshot is missing ${required}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const expectedInputs = [];
|
|
94
|
+
for (const reference of definitionOf(image).artifacts) {
|
|
95
|
+
const dependency = DOLLY_IMAGES.find(candidate =>
|
|
96
|
+
siteReference(candidate.dollyfile) === reference.location && candidate.sha256 === reference.sha256);
|
|
97
|
+
if (!dependency) throw new Error("packaged image input is missing");
|
|
98
|
+
const parent = await loadPackagedSnapshotMetadata(dependency.image, checked, active);
|
|
99
|
+
expectedInputs.push({ recipeSha256: reference.sha256, sha256: parent.sha256 });
|
|
100
|
+
}
|
|
101
|
+
if (!imageInputsMatch(inputs, expectedInputs)) throw new Error("The packaged system snapshot has stale image inputs");
|
|
102
|
+
if (active.size === 1) await verifyVisibleRecipes(recipes);
|
|
103
|
+
active.delete(image);
|
|
104
|
+
checked.set(image, metadata);
|
|
105
|
+
return metadata;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function* packagedSnapshotParts(image, metadata, signal) {
|
|
109
|
+
const packed = metadata.encoding === "packs";
|
|
110
|
+
const parts = packed ? validateSnapshotPacks(metadata) : [metadata];
|
|
111
|
+
for (const part of parts) {
|
|
112
|
+
signal?.throwIfAborted();
|
|
113
|
+
const compressed = packed || metadata.encoding === "gzip";
|
|
114
|
+
const url = packed
|
|
115
|
+
? new URL(`dist/packs/${part.sha256}.snapshot.gz`, imageBase)
|
|
116
|
+
: new URL(`dist/dolly-${image}-system.snapshot${compressed ? ".gz" : ""}`, imageBase);
|
|
117
|
+
const init = { cache: packed ? "force-cache" : "no-store", credentials: "same-origin", redirect: "error", signal };
|
|
118
|
+
const expected = compressed ? part.encodedByteLength : part.byteLength;
|
|
119
|
+
const response = await decodeStaticAsset(await fetch(url, init), url, init, expected);
|
|
120
|
+
if (!response.ok || !response.body) throw new Error(`snapshot returned HTTP ${response.status}`);
|
|
121
|
+
const declared = response.headers.get("content-length");
|
|
122
|
+
if (declared !== null && Number(declared) !== expected) throw new Error("snapshot HTTP content length mismatch");
|
|
123
|
+
const body = compressed ? response.body.pipeThrough(new DecompressionStream("gzip")) : response.body;
|
|
124
|
+
yield { ...part, body };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// The sink owns incremental hashing. Every part is checked before another is
|
|
129
|
+
// requested; the caller verifies the complete canonical image before booting.
|
|
130
|
+
export async function streamPackagedSystemSnapshot(image, metadata, write, endPart, signal) {
|
|
131
|
+
for await (const part of packagedSnapshotParts(image, metadata, signal)) {
|
|
132
|
+
const reader = part.body.getReader();
|
|
133
|
+
let size = 0;
|
|
134
|
+
try {
|
|
135
|
+
for (;;) {
|
|
136
|
+
signal?.throwIfAborted();
|
|
137
|
+
const { done, value } = await reader.read();
|
|
138
|
+
if (done) break;
|
|
139
|
+
if (value.length > part.byteLength - size) throw new Error("snapshot exceeds declared size");
|
|
140
|
+
await write(value);
|
|
141
|
+
size += value.length;
|
|
142
|
+
}
|
|
143
|
+
if (size !== part.byteLength || await endPart() !== part.sha256) throw new Error("snapshot integrity mismatch");
|
|
144
|
+
} catch (error) {
|
|
145
|
+
await reader.cancel().catch(() => {});
|
|
146
|
+
throw error;
|
|
147
|
+
} finally { reader.releaseLock(); }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function loadPackagedSystemSnapshot(image, metadata, signal) {
|
|
152
|
+
const parts = [];
|
|
153
|
+
for await (const part of packagedSnapshotParts(image, metadata, signal)) {
|
|
154
|
+
const reader = part.body.getReader(), bytes = new Uint8Array(part.byteLength);
|
|
155
|
+
let offset = 0;
|
|
156
|
+
try {
|
|
157
|
+
for (;;) {
|
|
158
|
+
signal?.throwIfAborted();
|
|
159
|
+
const { done, value } = await reader.read();
|
|
160
|
+
if (done) break;
|
|
161
|
+
if (value.length > bytes.length - offset) throw new Error("snapshot exceeds declared size");
|
|
162
|
+
bytes.set(value, offset);
|
|
163
|
+
offset += value.length;
|
|
164
|
+
}
|
|
165
|
+
if (offset !== bytes.length || await sha256(bytes) !== part.sha256) throw new Error("snapshot integrity mismatch");
|
|
166
|
+
parts.push(bytes);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
await reader.cancel().catch(() => {});
|
|
169
|
+
throw error;
|
|
170
|
+
} finally { reader.releaseLock(); }
|
|
171
|
+
}
|
|
172
|
+
const bytes = parts.length === 1 ? parts[0] : mergeSnapshotRecords(parts);
|
|
173
|
+
if (bytes.length !== metadata.byteLength || await sha256(bytes) !== metadata.sha256) throw new Error("packed snapshot integrity mismatch");
|
|
174
|
+
return bytes.buffer;
|
|
175
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { toggleIndicators } from "./page-indicators.mjs";
|
|
2
|
+
|
|
3
|
+
// The page's own keys, taken before any host module or the guest reads them:
|
|
4
|
+
// F11 toggles fullscreen and Ctrl+Shift+F the page's indicators. Listening
|
|
5
|
+
// starts with the page, so they work while an image boots.
|
|
6
|
+
export function pageChords(keyboard) {
|
|
7
|
+
async function toggleFullscreen() {
|
|
8
|
+
try {
|
|
9
|
+
if (document.fullscreenElement) {
|
|
10
|
+
await document.exitFullscreen();
|
|
11
|
+
} else {
|
|
12
|
+
await document.documentElement.requestFullscreen({ navigationUI: "hide" });
|
|
13
|
+
}
|
|
14
|
+
} catch {
|
|
15
|
+
document.documentElement.dataset.fullscreen = "failed";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Ctrl+Shift+F, and the release of an F the page took.
|
|
20
|
+
let indicatorsKeyDown = false;
|
|
21
|
+
function indicatorsChord(event) {
|
|
22
|
+
if (event.code !== "KeyF") return false;
|
|
23
|
+
const taken = event.type === "keyup" ? indicatorsKeyDown
|
|
24
|
+
: event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey;
|
|
25
|
+
indicatorsKeyDown = taken && event.type === "keydown";
|
|
26
|
+
return taken;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function take(event) {
|
|
30
|
+
const fullscreen = event.key === "F11";
|
|
31
|
+
if (!fullscreen && !indicatorsChord(event)) return;
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
event.stopImmediatePropagation();
|
|
34
|
+
if (event.type === "keydown" && !event.repeat) fullscreen ? void toggleFullscreen() : toggleIndicators();
|
|
35
|
+
}
|
|
36
|
+
window.addEventListener("keydown", take, { capture: true });
|
|
37
|
+
window.addEventListener("keyup", take, { capture: true });
|
|
38
|
+
document.addEventListener("fullscreenchange", () => {
|
|
39
|
+
document.documentElement.dataset.fullscreen = document.fullscreenElement ? "on" : "off";
|
|
40
|
+
// Firefox lets focus leave a modal dialog once the page is fullscreen.
|
|
41
|
+
if (!document.querySelector("dialog[open]")) keyboard.focus({ preventScroll: true });
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// The page's own elements over the display's corners (class page-indicator:
|
|
2
|
+
// the GPU adapter, the session Save button, download offers). They show when
|
|
3
|
+
// the page is ready and when one changes state, hide ten seconds later unless
|
|
4
|
+
// a state the user must not miss holds them, and Ctrl+Shift+F shows or hides
|
|
5
|
+
// them (page-chords.mjs). Only page code calls this; a guest reaches none of
|
|
6
|
+
// it.
|
|
7
|
+
const holders = new Set();
|
|
8
|
+
let timer;
|
|
9
|
+
const set = shown => { document.documentElement.dataset.indicators = shown ? "shown" : "hidden"; };
|
|
10
|
+
|
|
11
|
+
export function showIndicators() {
|
|
12
|
+
clearTimeout(timer);
|
|
13
|
+
set(true);
|
|
14
|
+
timer = setTimeout(() => { if (!holders.size) set(false); }, 10_000);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Holding shows them until the holder lets go, then for ten more seconds.
|
|
18
|
+
export function holdIndicators(holder, held) {
|
|
19
|
+
if (held) holders.add(holder);
|
|
20
|
+
else if (!holders.delete(holder)) return;
|
|
21
|
+
showIndicators();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function toggleIndicators() {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
set(document.documentElement.dataset.indicators === "hidden");
|
|
27
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { formatWasmType, sameWasmType } from "./wasm-interface.mjs";
|
|
2
|
+
import { hex } from "./static-asset.mjs";
|
|
3
|
+
|
|
4
|
+
export function unique(entries, key) {
|
|
5
|
+
const result = new Map();
|
|
6
|
+
for (const entry of entries) {
|
|
7
|
+
const name = key(entry);
|
|
8
|
+
if (result.has(name)) throw new TypeError(`duplicate process interface entry ${name}`);
|
|
9
|
+
result.set(name, entry);
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Both the build tools and browser admission call this exact validator on
|
|
15
|
+
// parsed bytes. The contract is assembled from abi/dolly-process-0.wat.
|
|
16
|
+
export function validateProcessInterface(contract, process, digest) {
|
|
17
|
+
const fail = message => { throw new TypeError(`${process.label}: ${message}`); };
|
|
18
|
+
const section = name => {
|
|
19
|
+
const entries = process.customSectionData.filter(x => x.name === name);
|
|
20
|
+
if (entries.length !== 1) fail(`expected exactly one ${name} section`);
|
|
21
|
+
return entries[0].data;
|
|
22
|
+
};
|
|
23
|
+
if (process.customSections.includes("dylink.0")) {
|
|
24
|
+
fail("a process executable must not be a side module");
|
|
25
|
+
}
|
|
26
|
+
const stamp = hex(section("dolly.process"));
|
|
27
|
+
if (stamp !== digest) fail("wrong dolly.process stamp");
|
|
28
|
+
const key = x => `${x.module}.${x.name}`;
|
|
29
|
+
const allowed = unique(contract.imports, key);
|
|
30
|
+
const actual = unique(process.imports, key);
|
|
31
|
+
if (allowed.size !== 2 || !allowed.has("env.memory") || !allowed.has("dolly_process_0.call")) {
|
|
32
|
+
throw new TypeError("process contract must contain only memory and call");
|
|
33
|
+
}
|
|
34
|
+
for (const name of actual.keys()) if (!allowed.has(name)) fail(`import ${name} is outside dolly-process-0`);
|
|
35
|
+
if (actual.size !== allowed.size) fail("expected exactly the two dolly-process-0 imports");
|
|
36
|
+
let memory;
|
|
37
|
+
for (const [name, expected] of allowed) {
|
|
38
|
+
const entry = actual.get(name);
|
|
39
|
+
if (!entry) fail(`missing required import ${name}`);
|
|
40
|
+
const type = entry.type;
|
|
41
|
+
if (name === "env.memory") {
|
|
42
|
+
if (type.kind !== "memory" || expected.type.kind !== "memory" ||
|
|
43
|
+
type.address64 !== expected.type.address64 || type.shared !== expected.type.shared ||
|
|
44
|
+
type.minimum < expected.type.minimum || type.maximum === null ||
|
|
45
|
+
expected.type.maximum === null || type.maximum > expected.type.maximum ||
|
|
46
|
+
type.minimum > type.maximum) {
|
|
47
|
+
fail(`process memory is outside ${formatWasmType(expected.type)}`);
|
|
48
|
+
}
|
|
49
|
+
const bytes = section("dolly.process.memory");
|
|
50
|
+
if (bytes.length !== 16) fail("expected a 16-byte dolly.process.memory section");
|
|
51
|
+
const record = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
52
|
+
if (record.getBigUint64(0, true) !== type.minimum ||
|
|
53
|
+
record.getBigUint64(8, true) !== type.maximum) {
|
|
54
|
+
fail("dolly.process.memory does not match its memory import");
|
|
55
|
+
}
|
|
56
|
+
memory = { initial: type.minimum, maximum: type.maximum };
|
|
57
|
+
} else if (!sameWasmType(type, expected.type)) {
|
|
58
|
+
fail(`import ${name} must be ${formatWasmType(expected.type)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const exports = unique(process.exports, x => x.name);
|
|
62
|
+
for (const expected of contract.exports) {
|
|
63
|
+
const entry = exports.get(expected.name);
|
|
64
|
+
if (!entry || !sameWasmType(entry.type, expected.type)) {
|
|
65
|
+
fail(`missing or incompatible process export ${expected.name}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return memory;
|
|
69
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// Generated from include/dolly/process.h.
|
|
2
|
+
export const DOLLY_PROCESS_PACKET_LIMIT = 1048576;
|
|
3
|
+
export const DOLLY_PROCESS_ARGUMENT_SIZES = 1;
|
|
4
|
+
export const DOLLY_PROCESS_ARGUMENTS = 2;
|
|
5
|
+
export const DOLLY_PROCESS_ENVIRONMENT_SIZES = 3;
|
|
6
|
+
export const DOLLY_PROCESS_ENVIRONMENT = 4;
|
|
7
|
+
export const DOLLY_PROCESS_EXIT = 5;
|
|
8
|
+
export const DOLLY_PROCESS_FD_READ = 16;
|
|
9
|
+
export const DOLLY_PROCESS_FD_WRITE = 17;
|
|
10
|
+
export const DOLLY_PROCESS_FD_CLOSE = 18;
|
|
11
|
+
export const DOLLY_PROCESS_FD_SEEK = 19;
|
|
12
|
+
export const DOLLY_PROCESS_FD_STAT = 20;
|
|
13
|
+
export const DOLLY_PROCESS_FD_SYNC = 21;
|
|
14
|
+
export const DOLLY_PROCESS_FD_DUP = 22;
|
|
15
|
+
export const DOLLY_PROCESS_FD_PIPE = 23;
|
|
16
|
+
export const DOLLY_PROCESS_FD_READ_DIRECTORY = 24;
|
|
17
|
+
export const DOLLY_PROCESS_FD_PREAD = 25;
|
|
18
|
+
export const DOLLY_PROCESS_FD_TRUNCATE = 26;
|
|
19
|
+
export const DOLLY_PROCESS_FD_STAT_FILESYSTEM = 27;
|
|
20
|
+
export const DOLLY_PROCESS_FD_SET_TIMES = 28;
|
|
21
|
+
export const DOLLY_PROCESS_FD_PWRITE = 29;
|
|
22
|
+
export const DOLLY_PROCESS_FD_GET_FLAGS = 30;
|
|
23
|
+
export const DOLLY_PROCESS_FD_SET_FLAGS = 31;
|
|
24
|
+
export const DOLLY_PROCESS_PATH_OPEN = 32;
|
|
25
|
+
export const DOLLY_PROCESS_PATH_STAT = 33;
|
|
26
|
+
export const DOLLY_PROCESS_PATH_CREATE_DIRECTORY = 34;
|
|
27
|
+
export const DOLLY_PROCESS_PATH_REMOVE = 35;
|
|
28
|
+
export const DOLLY_PROCESS_PATH_RENAME = 36;
|
|
29
|
+
export const DOLLY_PROCESS_PATH_LINK = 37;
|
|
30
|
+
export const DOLLY_PROCESS_PATH_SYMLINK = 38;
|
|
31
|
+
export const DOLLY_PROCESS_PATH_READLINK = 39;
|
|
32
|
+
export const DOLLY_PROCESS_PATH_GET_CURRENT_DIRECTORY = 40;
|
|
33
|
+
export const DOLLY_PROCESS_PATH_SET_CURRENT_DIRECTORY = 41;
|
|
34
|
+
export const DOLLY_PROCESS_PATH_STAT_FILESYSTEM = 42;
|
|
35
|
+
export const DOLLY_PROCESS_PATH_SET_TIMES = 43;
|
|
36
|
+
export const DOLLY_PROCESS_CLOCK_TIME = 48;
|
|
37
|
+
export const DOLLY_PROCESS_RANDOM = 49;
|
|
38
|
+
export const DOLLY_PROCESS_TERMINAL = 50;
|
|
39
|
+
export const DOLLY_PROCESS_CLOCK_RESOLUTION = 52;
|
|
40
|
+
export const DOLLY_PROCESS_CLOCK_SLEEP = 53;
|
|
41
|
+
export const DOLLY_PROCESS_FD_POLL = 54;
|
|
42
|
+
export const DOLLY_PROCESS_FD_GET_DESCRIPTOR_FLAGS = 55;
|
|
43
|
+
export const DOLLY_PROCESS_FD_SET_DESCRIPTOR_FLAGS = 56;
|
|
44
|
+
export const DOLLY_PROCESS_FD_LOCK = 59;
|
|
45
|
+
export const DOLLY_PROCESS_EXEC = 61;
|
|
46
|
+
export const DOLLY_PROCESS_SPAWN = 64;
|
|
47
|
+
export const DOLLY_PROCESS_WAIT = 65;
|
|
48
|
+
export const DOLLY_PROCESS_INTERRUPT_POLL = 66;
|
|
49
|
+
export const DOLLY_PROCESS_INFO = 67;
|
|
50
|
+
export const DOLLY_PROCESS_SIGNAL = 68;
|
|
51
|
+
export const DOLLY_PROCESS_SIGNAL_ACKNOWLEDGE = 69;
|
|
52
|
+
export const DOLLY_PROCESS_ALARM = 70;
|
|
53
|
+
export const DOLLY_PROCESS_ALARM_HANDLED = 71;
|
|
54
|
+
export const DOLLY_PROCESS_SPAWN_INHERIT_ENVIRONMENT = 1;
|
|
55
|
+
export const DOLLY_PROCESS_SPAWN_FOREGROUND = 2;
|
|
56
|
+
export const DOLLY_PROCESS_SPAWN_INTERACTIVE = 4;
|
|
57
|
+
export const DOLLY_PROCESS_INHERIT_FDS_NONE = 0;
|
|
58
|
+
export const DOLLY_PROCESS_INHERIT_FDS_STDIO = 1;
|
|
59
|
+
export const DOLLY_PROCESS_INHERIT_FDS_ALL = 2;
|
|
60
|
+
export const DOLLY_PROCESS_FD_CLOEXEC = 1;
|
|
61
|
+
export const DOLLY_PROCESS_FD_KEEP_LOCKS = 2;
|
|
62
|
+
export const DOLLY_PROCESS_WAIT_NONBLOCK = 1;
|
|
63
|
+
export const DOLLY_PROCESS_SIGHUP = 1;
|
|
64
|
+
export const DOLLY_PROCESS_SIGINT = 2;
|
|
65
|
+
export const DOLLY_PROCESS_SIGQUIT = 3;
|
|
66
|
+
export const DOLLY_PROCESS_SIGABRT = 6;
|
|
67
|
+
export const DOLLY_PROCESS_SIGKILL = 9;
|
|
68
|
+
export const DOLLY_PROCESS_SIGPIPE = 13;
|
|
69
|
+
export const DOLLY_PROCESS_SIGALRM = 14;
|
|
70
|
+
export const DOLLY_PROCESS_SIGTERM = 15;
|
|
71
|
+
export const DOLLY_PROCESS_SIGCHLD = 17;
|
|
72
|
+
export const DOLLY_PROCESS_SIGWINCH = 28;
|
|
73
|
+
export const DOLLY_PROCESS_SIGNAL_MASK = 268493390;
|
|
74
|
+
export const DOLLY_PROCESS_FD_DUP_MINIMUM = 1;
|
|
75
|
+
export const DOLLY_PROCESS_FD_DUP_CLOEXEC = 2;
|
|
76
|
+
export const DOLLY_PROCESS_FD_STATUS_READ = 1;
|
|
77
|
+
export const DOLLY_PROCESS_FD_STATUS_WRITE = 2;
|
|
78
|
+
export const DOLLY_PROCESS_FD_STATUS_APPEND = 4;
|
|
79
|
+
export const DOLLY_PROCESS_FD_STATUS_NONBLOCK = 8;
|
|
80
|
+
export const DOLLY_PROCESS_SEEK_SET = 0;
|
|
81
|
+
export const DOLLY_PROCESS_SEEK_CURRENT = 1;
|
|
82
|
+
export const DOLLY_PROCESS_SEEK_END = 2;
|
|
83
|
+
export const DOLLY_PROCESS_CLOCK_REALTIME = 0;
|
|
84
|
+
export const DOLLY_PROCESS_CLOCK_MONOTONIC = 1;
|
|
85
|
+
export const DOLLY_PROCESS_OPEN_READ = 1;
|
|
86
|
+
export const DOLLY_PROCESS_OPEN_WRITE = 2;
|
|
87
|
+
export const DOLLY_PROCESS_OPEN_CREATE = 4;
|
|
88
|
+
export const DOLLY_PROCESS_OPEN_EXCLUSIVE = 8;
|
|
89
|
+
export const DOLLY_PROCESS_OPEN_TRUNCATE = 16;
|
|
90
|
+
export const DOLLY_PROCESS_OPEN_APPEND = 32;
|
|
91
|
+
export const DOLLY_PROCESS_OPEN_DIRECTORY = 64;
|
|
92
|
+
export const DOLLY_PROCESS_OPEN_NOFOLLOW = 128;
|
|
93
|
+
export const DOLLY_PROCESS_OPEN_CLOEXEC = 256;
|
|
94
|
+
export const DOLLY_PROCESS_PATH_DIRECTORY = 1;
|
|
95
|
+
export const DOLLY_PROCESS_PATH_NOFOLLOW = 2;
|
|
96
|
+
export const DOLLY_PROCESS_TIME_NOW = 1;
|
|
97
|
+
export const DOLLY_PROCESS_TIME_OMIT = 2;
|
|
98
|
+
export const DOLLY_PROCESS_FILE_UNKNOWN = 0;
|
|
99
|
+
export const DOLLY_PROCESS_FILE_REGULAR = 1;
|
|
100
|
+
export const DOLLY_PROCESS_FILE_DIRECTORY = 2;
|
|
101
|
+
export const DOLLY_PROCESS_FILE_SYMBOLIC_LINK = 3;
|
|
102
|
+
export const DOLLY_PROCESS_FILE_CHARACTER_DEVICE = 4;
|
|
103
|
+
export const DOLLY_PROCESS_FILE_BLOCK_DEVICE = 5;
|
|
104
|
+
export const DOLLY_PROCESS_FILE_FIFO = 6;
|
|
105
|
+
export const DOLLY_PROCESS_FILE_SOCKET = 7;
|
|
106
|
+
export const DOLLY_PROCESS_POLL_READ = 1;
|
|
107
|
+
export const DOLLY_PROCESS_POLL_WRITE = 2;
|
|
108
|
+
export const DOLLY_PROCESS_POLL_PRIORITY = 4;
|
|
109
|
+
export const DOLLY_PROCESS_POLL_ERROR = 8;
|
|
110
|
+
export const DOLLY_PROCESS_POLL_HANGUP = 16;
|
|
111
|
+
export const DOLLY_PROCESS_POLL_INVALID = 32;
|
|
112
|
+
export const DOLLY_PROCESS_POLL_IGNORED_DESCRIPTOR = 4294967295;
|
|
113
|
+
export const DOLLY_PROCESS_TERMINAL_READ = 1;
|
|
114
|
+
export const DOLLY_PROCESS_TERMINAL_ISATTY = 2;
|
|
115
|
+
export const DOLLY_PROCESS_TERMINAL_MODE_GET = 3;
|
|
116
|
+
export const DOLLY_PROCESS_TERMINAL_MODE_SET = 4;
|
|
117
|
+
export const DOLLY_PROCESS_TERMINAL_SIZE = 5;
|
|
118
|
+
export const DOLLY_PROCESS_TERMINAL_PUBLISH_RESULT = 6;
|
|
119
|
+
export const DOLLY_PROCESS_LOCK_SHARED = 0;
|
|
120
|
+
export const DOLLY_PROCESS_LOCK_EXCLUSIVE = 1;
|
|
121
|
+
export const DOLLY_PROCESS_LOCK_UNLOCK = 2;
|
|
122
|
+
export const DOLLY_PROCESS_LOCK_DESCRIPTION = 1;
|
|
123
|
+
export const DOLLY_PROCESS_LOCK_WAIT = 2;
|
|
124
|
+
export const DOLLY_PROCESS_LOCK_TEST = 4;
|
|
125
|
+
export const DOLLY_PROCESS_FD_MAPPING_CLOSED = 4294967295;
|
|
126
|
+
export const DOLLY_ERRNO = Object.freeze({
|
|
127
|
+
E2BIG: 1,
|
|
128
|
+
EACCES: 2,
|
|
129
|
+
EADDRINUSE: 3,
|
|
130
|
+
EADDRNOTAVAIL: 4,
|
|
131
|
+
EAFNOSUPPORT: 5,
|
|
132
|
+
EAGAIN: 6,
|
|
133
|
+
EALREADY: 7,
|
|
134
|
+
EBADF: 8,
|
|
135
|
+
EBADMSG: 9,
|
|
136
|
+
EBUSY: 10,
|
|
137
|
+
ECANCELED: 11,
|
|
138
|
+
ECHILD: 12,
|
|
139
|
+
ECONNABORTED: 13,
|
|
140
|
+
ECONNREFUSED: 14,
|
|
141
|
+
ECONNRESET: 15,
|
|
142
|
+
EDEADLK: 16,
|
|
143
|
+
EDESTADDRREQ: 17,
|
|
144
|
+
EDOM: 18,
|
|
145
|
+
EDQUOT: 19,
|
|
146
|
+
EEXIST: 20,
|
|
147
|
+
EFAULT: 21,
|
|
148
|
+
EFBIG: 22,
|
|
149
|
+
EHOSTUNREACH: 23,
|
|
150
|
+
EIDRM: 24,
|
|
151
|
+
EILSEQ: 25,
|
|
152
|
+
EINPROGRESS: 26,
|
|
153
|
+
EINTR: 27,
|
|
154
|
+
EINVAL: 28,
|
|
155
|
+
EIO: 29,
|
|
156
|
+
EISCONN: 30,
|
|
157
|
+
EISDIR: 31,
|
|
158
|
+
ELOOP: 32,
|
|
159
|
+
EMFILE: 33,
|
|
160
|
+
EMLINK: 34,
|
|
161
|
+
EMSGSIZE: 35,
|
|
162
|
+
EMULTIHOP: 36,
|
|
163
|
+
ENAMETOOLONG: 37,
|
|
164
|
+
ENETDOWN: 38,
|
|
165
|
+
ENETRESET: 39,
|
|
166
|
+
ENETUNREACH: 40,
|
|
167
|
+
ENFILE: 41,
|
|
168
|
+
ENOBUFS: 42,
|
|
169
|
+
ENODEV: 43,
|
|
170
|
+
ENOENT: 44,
|
|
171
|
+
ENOEXEC: 45,
|
|
172
|
+
ENOLCK: 46,
|
|
173
|
+
ENOLINK: 47,
|
|
174
|
+
ENOMEM: 48,
|
|
175
|
+
ENOMSG: 49,
|
|
176
|
+
ENOPROTOOPT: 50,
|
|
177
|
+
ENOSPC: 51,
|
|
178
|
+
ENOSYS: 52,
|
|
179
|
+
ENOTCONN: 53,
|
|
180
|
+
ENOTDIR: 54,
|
|
181
|
+
ENOTEMPTY: 55,
|
|
182
|
+
ENOTRECOVERABLE: 56,
|
|
183
|
+
ENOTSOCK: 57,
|
|
184
|
+
ENOTTY: 59,
|
|
185
|
+
ENXIO: 60,
|
|
186
|
+
EOVERFLOW: 61,
|
|
187
|
+
EOWNERDEAD: 62,
|
|
188
|
+
EPERM: 63,
|
|
189
|
+
EPIPE: 64,
|
|
190
|
+
EPROTO: 65,
|
|
191
|
+
EPROTONOSUPPORT: 66,
|
|
192
|
+
EPROTOTYPE: 67,
|
|
193
|
+
ERANGE: 68,
|
|
194
|
+
EROFS: 69,
|
|
195
|
+
ESPIPE: 70,
|
|
196
|
+
ESRCH: 71,
|
|
197
|
+
ESTALE: 72,
|
|
198
|
+
ETIMEDOUT: 73,
|
|
199
|
+
ETXTBSY: 74,
|
|
200
|
+
EXDEV: 75,
|
|
201
|
+
ENODATA: 116,
|
|
202
|
+
ENOTSUP: 138,
|
|
203
|
+
});
|
|
204
|
+
export const DOLLY_PROCESS_SIZEOF = Object.freeze({
|
|
205
|
+
dolly_process_vector_sizes: 16,
|
|
206
|
+
dolly_process_fd_io_request: 16,
|
|
207
|
+
dolly_process_fd_pread_request: 24,
|
|
208
|
+
dolly_process_fd_truncate_request: 16,
|
|
209
|
+
dolly_process_fd_request: 8,
|
|
210
|
+
dolly_process_timestamp: 16,
|
|
211
|
+
dolly_process_fd_times_request: 40,
|
|
212
|
+
dolly_process_fd_dup_request: 16,
|
|
213
|
+
dolly_process_fd_flags: 8,
|
|
214
|
+
dolly_process_fd_lock_request: 32,
|
|
215
|
+
dolly_process_fd_lock_response: 24,
|
|
216
|
+
dolly_process_poll_request: 16,
|
|
217
|
+
dolly_process_poll_query: 8,
|
|
218
|
+
dolly_process_poll_response: 16,
|
|
219
|
+
dolly_process_poll_result: 8,
|
|
220
|
+
dolly_process_directory_entry: 24,
|
|
221
|
+
dolly_process_directory_request: 24,
|
|
222
|
+
dolly_process_stat_response: 88,
|
|
223
|
+
dolly_process_filesystem_stat_response: 96,
|
|
224
|
+
dolly_process_spawn_request: 56,
|
|
225
|
+
dolly_process_fd_mapping: 8,
|
|
226
|
+
dolly_process_exec_state: 16,
|
|
227
|
+
dolly_process_exec_request: 48,
|
|
228
|
+
dolly_process_pipe_request: 8,
|
|
229
|
+
dolly_process_two_path_request: 16,
|
|
230
|
+
dolly_process_path_times_request: 48,
|
|
231
|
+
dolly_process_terminal_request: 24,
|
|
232
|
+
dolly_process_terminal_response: 16,
|
|
233
|
+
dolly_process_clock_sleep_request: 16,
|
|
234
|
+
dolly_process_exit_request: 8,
|
|
235
|
+
dolly_process_wait_request: 8,
|
|
236
|
+
dolly_process_wait_response: 16,
|
|
237
|
+
dolly_process_signal_request: 8,
|
|
238
|
+
dolly_process_alarm: 16,
|
|
239
|
+
dolly_process_fd_seek_request: 16,
|
|
240
|
+
dolly_process_clock_request: 16,
|
|
241
|
+
dolly_process_path_request: 16,
|
|
242
|
+
});
|