From 80f8d7410126b70c66c31e44e0516a2df450e3e3 Mon Sep 17 00:00:00 2001 From: oligami Date: Tue, 24 Sep 2024 03:25:20 +0900 Subject: [PATCH] tab to space --- src/wasi_farm/animals.ts | 2276 +++++++-------- src/wasi_farm/farm.ts | 176 +- src/wasi_farm/park.ts | 1156 ++++---- src/wasi_farm/polyfill.js | 178 +- src/wasi_farm/sender.ts | 4 +- .../shared_array_buffer/allocator.ts | 412 +-- .../shared_array_buffer/fd_close_sender.ts | 98 +- src/wasi_farm/shared_array_buffer/index.ts | 10 +- src/wasi_farm/shared_array_buffer/park.ts | 1958 ++++++------- src/wasi_farm/shared_array_buffer/ref.ts | 2590 ++++++++--------- src/wasi_farm/shared_array_buffer/sender.ts | 434 ++- .../shared_array_buffer/thread_spawn.ts | 414 +-- src/wasi_farm/shared_array_buffer/util.ts | 132 +- .../worker_background/index.ts | 8 +- .../worker_background/minify.js | 34 +- .../worker_background/spack.config.cjs | 14 +- .../worker_background/worker.ts | 288 +- .../worker_background_ref.ts | 166 +- 18 files changed, 5172 insertions(+), 5176 deletions(-) diff --git a/src/wasi_farm/animals.ts b/src/wasi_farm/animals.ts index 122e36f..1ebdcf5 100644 --- a/src/wasi_farm/animals.ts +++ b/src/wasi_farm/animals.ts @@ -9,1200 +9,1200 @@ import type { WASIFarmRefUseArrayBufferObject } from "./shared_array_buffer/inde import { ThreadSpawner } from "./shared_array_buffer/index.js"; export class WASIFarmAnimal { - private args: Array; - private env: Array; + private args: Array; + private env: Array; - private wasi_farm_refs: WASIFarmRef[]; + private wasi_farm_refs: WASIFarmRef[]; - private id_in_wasi_farm_ref: Array; + private id_in_wasi_farm_ref: Array; - inst: { exports: { memory: WebAssembly.Memory } }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - wasiImport: { [key: string]: (...args: Array) => unknown }; + inst: { exports: { memory: WebAssembly.Memory } }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + wasiImport: { [key: string]: (...args: Array) => unknown }; - wasiThreadImport: { - "thread-spawn": (start_arg: number) => number; - }; + wasiThreadImport: { + "thread-spawn": (start_arg: number) => number; + }; - private can_array_buffer; + private can_array_buffer; - private can_thread_spawn: boolean; + private can_thread_spawn: boolean; - private thread_spawner: ThreadSpawner; + private thread_spawner: ThreadSpawner; - wait_worker_background_worker(): Promise { - return this.thread_spawner.wait_worker_background_worker(); - } + wait_worker_background_worker(): Promise { + return this.thread_spawner.wait_worker_background_worker(); + } - // Each process has a specific fd that it can access. - // If it does not exist in the map, it cannot be accessed. - // child process can access parent process's fd. - // so, it is necessary to manage the fd on global scope. - // [fd, wasi_ref_n] - protected fd_map: Array<[number, number]>; + // Each process has a specific fd that it can access. + // If it does not exist in the map, it cannot be accessed. + // child process can access parent process's fd. + // so, it is necessary to manage the fd on global scope. + // [fd, wasi_ref_n] + protected fd_map: Array<[number, number]>; - protected get_fd_and_wasi_ref( - fd: number, - ): [number | undefined, WASIFarmRef | undefined] { - const mapped_fd_and_wasi_ref_n = this.fd_map[fd]; - if (!mapped_fd_and_wasi_ref_n) { - // console.log("fd", fd, "is not found"); - return [undefined, undefined]; - } - const [mapped_fd, wasi_ref_n] = mapped_fd_and_wasi_ref_n; - // console.log("fd", fd, "is found", "mapped_fd", mapped_fd, "wasi_ref_n", wasi_ref_n); - return [mapped_fd, this.wasi_farm_refs[wasi_ref_n]]; - } + protected get_fd_and_wasi_ref( + fd: number, + ): [number | undefined, WASIFarmRef | undefined] { + const mapped_fd_and_wasi_ref_n = this.fd_map[fd]; + if (!mapped_fd_and_wasi_ref_n) { + // console.log("fd", fd, "is not found"); + return [undefined, undefined]; + } + const [mapped_fd, wasi_ref_n] = mapped_fd_and_wasi_ref_n; + // console.log("fd", fd, "is found", "mapped_fd", mapped_fd, "wasi_ref_n", wasi_ref_n); + return [mapped_fd, this.wasi_farm_refs[wasi_ref_n]]; + } - protected get_fd_and_wasi_ref_n( - fd: number, - ): [number | undefined, number | undefined] { - const mapped_fd_and_wasi_ref_n = this.fd_map[fd]; - if (!mapped_fd_and_wasi_ref_n) { - // console.log("fd", fd, "is not found"); - return [undefined, undefined]; - } - const [mapped_fd, wasi_ref_n] = mapped_fd_and_wasi_ref_n; - // console.log("fd", fd, "is found", "mapped_fd", mapped_fd, "wasi_ref_n", wasi_ref_n); - return [mapped_fd, wasi_ref_n]; - } + protected get_fd_and_wasi_ref_n( + fd: number, + ): [number | undefined, number | undefined] { + const mapped_fd_and_wasi_ref_n = this.fd_map[fd]; + if (!mapped_fd_and_wasi_ref_n) { + // console.log("fd", fd, "is not found"); + return [undefined, undefined]; + } + const [mapped_fd, wasi_ref_n] = mapped_fd_and_wasi_ref_n; + // console.log("fd", fd, "is found", "mapped_fd", mapped_fd, "wasi_ref_n", wasi_ref_n); + return [mapped_fd, wasi_ref_n]; + } - /// Start a WASI command - start(instance: { - // FIXME v0.3: close opened Fds after execution - exports: { memory: WebAssembly.Memory; _start: () => unknown }; - }) { - this.inst = instance; - try { - instance.exports._start(); - return 0; - } catch (e) { - if (e instanceof WASIProcExit) { - return e.code; - } - throw e; - } - } + /// Start a WASI command + start(instance: { + // FIXME v0.3: close opened Fds after execution + exports: { memory: WebAssembly.Memory; _start: () => unknown }; + }) { + this.inst = instance; + try { + instance.exports._start(); + return 0; + } catch (e) { + if (e instanceof WASIProcExit) { + return e.code; + } + throw e; + } + } - wasi_thread_start( - instance: { - exports: { - memory: WebAssembly.Memory; - wasi_thread_start: (thread_id: number, start_arg: number) => void; - }; - }, - thread_id: number, - start_arg: number, - ) { - this.inst = instance; - try { - instance.exports.wasi_thread_start(thread_id, start_arg); - return 0; - } catch (e) { - if (e instanceof WASIProcExit) { - return e.code; - } - throw e; - } - } + wasi_thread_start( + instance: { + exports: { + memory: WebAssembly.Memory; + wasi_thread_start: (thread_id: number, start_arg: number) => void; + }; + }, + thread_id: number, + start_arg: number, + ) { + this.inst = instance; + try { + instance.exports.wasi_thread_start(thread_id, start_arg); + return 0; + } catch (e) { + if (e instanceof WASIProcExit) { + return e.code; + } + throw e; + } + } - /// Initialize a WASI reactor - initialize(instance: { - exports: { memory: WebAssembly.Memory; _initialize?: () => unknown }; - }) { - this.inst = instance; - if (instance.exports._initialize) { - instance.exports._initialize(); - } - } + /// Initialize a WASI reactor + initialize(instance: { + exports: { memory: WebAssembly.Memory; _initialize?: () => unknown }; + }) { + this.inst = instance; + if (instance.exports._initialize) { + instance.exports._initialize(); + } + } - private mapping_fds( - wasi_farm_refs: Array, - override_fd_maps?: Array, - ) { - this.fd_map = [undefined, undefined, undefined]; + private mapping_fds( + wasi_farm_refs: Array, + override_fd_maps?: Array, + ) { + this.fd_map = [undefined, undefined, undefined]; - // console.log("wasi_farm_refs", wasi_farm_refs); - for (let i = 0; i < wasi_farm_refs.length; i++) { - // console.log("fd_map", [...this.fd_map]); + // console.log("wasi_farm_refs", wasi_farm_refs); + for (let i = 0; i < wasi_farm_refs.length; i++) { + // console.log("fd_map", [...this.fd_map]); - const wasi_farm_ref = wasi_farm_refs[i]; - // console.log("override_fd_map", wasi_farm_ref.default_fds); - const override_fd_map = override_fd_maps - ? override_fd_maps[i] - : wasi_farm_ref.default_fds; - // console.log("override_fd_map", override_fd_map); - const stdin = wasi_farm_ref.get_stdin(); - const stdout = wasi_farm_ref.get_stdout(); - const stderr = wasi_farm_ref.get_stderr(); - // console.log("stdin", stdin, "stdout", stdout, "stderr", stderr); - if (stdin !== undefined) { - if (override_fd_map.includes(stdin)) { - this.fd_map[0] = [stdin, i]; - } - } - if (stdout !== undefined) { - // console.log("stdout", stdout, i, "override_fd_map", override_fd_map); - if (override_fd_map.includes(stdout)) { - // console.log("stdout defined"); - this.fd_map[1] = [stdout, i]; - } - } - if (stderr !== undefined) { - if (override_fd_map.includes(stderr)) { - this.fd_map[2] = [stderr, i]; - } - } - for (const j of override_fd_map) { - if (j === stdin || j === stdout || j === stderr) { - continue; - } - this.map_new_fd(j, i); - } - wasi_farm_ref.set_park_fds_map(override_fd_map); + const wasi_farm_ref = wasi_farm_refs[i]; + // console.log("override_fd_map", wasi_farm_ref.default_fds); + const override_fd_map = override_fd_maps + ? override_fd_maps[i] + : wasi_farm_ref.default_fds; + // console.log("override_fd_map", override_fd_map); + const stdin = wasi_farm_ref.get_stdin(); + const stdout = wasi_farm_ref.get_stdout(); + const stderr = wasi_farm_ref.get_stderr(); + // console.log("stdin", stdin, "stdout", stdout, "stderr", stderr); + if (stdin !== undefined) { + if (override_fd_map.includes(stdin)) { + this.fd_map[0] = [stdin, i]; + } + } + if (stdout !== undefined) { + // console.log("stdout", stdout, i, "override_fd_map", override_fd_map); + if (override_fd_map.includes(stdout)) { + // console.log("stdout defined"); + this.fd_map[1] = [stdout, i]; + } + } + if (stderr !== undefined) { + if (override_fd_map.includes(stderr)) { + this.fd_map[2] = [stderr, i]; + } + } + for (const j of override_fd_map) { + if (j === stdin || j === stdout || j === stderr) { + continue; + } + this.map_new_fd(j, i); + } + wasi_farm_ref.set_park_fds_map(override_fd_map); - // console.log("fd_map", this.fd_map); - } + // console.log("fd_map", this.fd_map); + } - if (this.fd_map[0] === undefined) { - throw new Error("stdin is not found"); - } - if (this.fd_map[1] === undefined) { - throw new Error("stdout is not found"); - } - if (this.fd_map[2] === undefined) { - throw new Error("stderr is not found"); - } - } + if (this.fd_map[0] === undefined) { + throw new Error("stdin is not found"); + } + if (this.fd_map[1] === undefined) { + throw new Error("stdout is not found"); + } + if (this.fd_map[2] === undefined) { + throw new Error("stderr is not found"); + } + } - private map_new_fd(fd: number, wasi_ref_n: number): number { - let n = -1; - // 0, 1, 2 are reserved for stdin, stdout, stderr - for (let i = 3; i < this.fd_map.length; i++) { - if (this.fd_map[i] === undefined) { - n = i; - break; - } - } - if (n === -1) { - n = this.fd_map.push(undefined) - 1; - } - this.fd_map[n] = [fd, wasi_ref_n]; - return n; - } + private map_new_fd(fd: number, wasi_ref_n: number): number { + let n = -1; + // 0, 1, 2 are reserved for stdin, stdout, stderr + for (let i = 3; i < this.fd_map.length; i++) { + if (this.fd_map[i] === undefined) { + n = i; + break; + } + } + if (n === -1) { + n = this.fd_map.push(undefined) - 1; + } + this.fd_map[n] = [fd, wasi_ref_n]; + return n; + } - private map_new_fd_and_notify(fd: number, wasi_ref_n: number): number { - const n = this.map_new_fd(fd, wasi_ref_n); - // console.log("animals: fd", fd, "is mapped to", n); - // console.log("wasi_ref_n", wasi_ref_n); - this.wasi_farm_refs[wasi_ref_n].set_park_fds_map([fd]); - return n; - } + private map_new_fd_and_notify(fd: number, wasi_ref_n: number): number { + const n = this.map_new_fd(fd, wasi_ref_n); + // console.log("animals: fd", fd, "is mapped to", n); + // console.log("wasi_ref_n", wasi_ref_n); + this.wasi_farm_refs[wasi_ref_n].set_park_fds_map([fd]); + return n; + } - private map_set_fd_and_notify(fd: number, wasi_ref_n: number, index: number) { - if (this.fd_map[index] !== undefined) { - throw new Error("fd is already mapped"); - } - this.fd_map[index] = [fd, wasi_ref_n]; - this.wasi_farm_refs[wasi_ref_n].set_park_fds_map([fd]); - } + private map_set_fd_and_notify(fd: number, wasi_ref_n: number, index: number) { + if (this.fd_map[index] !== undefined) { + throw new Error("fd is already mapped"); + } + this.fd_map[index] = [fd, wasi_ref_n]; + this.wasi_farm_refs[wasi_ref_n].set_park_fds_map([fd]); + } - private check_fds() { - const rm_fds: Array<[number, number]> = []; - for (let i = 0; i < this.id_in_wasi_farm_ref.length; i++) { - const id = this.id_in_wasi_farm_ref[i]; - const removed_fds = (this.wasi_farm_refs[i] as FdCloseSender).get(id); - if (removed_fds) { - for (const fd of removed_fds) { - rm_fds.push([fd, i]); - } - } - } + private check_fds() { + const rm_fds: Array<[number, number]> = []; + for (let i = 0; i < this.id_in_wasi_farm_ref.length; i++) { + const id = this.id_in_wasi_farm_ref[i]; + const removed_fds = (this.wasi_farm_refs[i] as FdCloseSender).get(id); + if (removed_fds) { + for (const fd of removed_fds) { + rm_fds.push([fd, i]); + } + } + } - if (rm_fds.length > 0) { - for (let i = 0; i < this.fd_map.length; i++) { - const fd_and_wasi_ref_n = this.fd_map[i]; - if (fd_and_wasi_ref_n === undefined) { - continue; - } - const [fd, wasi_ref_n] = fd_and_wasi_ref_n; - for (const [rm_fd_fd, rm_fd_wasi_ref_n] of rm_fds) { - if (fd === rm_fd_fd && wasi_ref_n === rm_fd_wasi_ref_n) { - this.fd_map[i] = undefined; - // console.log("fd", i, "is removed"); - break; - } - } - // console.log("fd_and_wasi_ref_n", fd_and_wasi_ref_n); - } - // console.log("rm_fds.length", rm_fds.length); - // console.log("rm_fds", rm_fds); - } - } + if (rm_fds.length > 0) { + for (let i = 0; i < this.fd_map.length; i++) { + const fd_and_wasi_ref_n = this.fd_map[i]; + if (fd_and_wasi_ref_n === undefined) { + continue; + } + const [fd, wasi_ref_n] = fd_and_wasi_ref_n; + for (const [rm_fd_fd, rm_fd_wasi_ref_n] of rm_fds) { + if (fd === rm_fd_fd && wasi_ref_n === rm_fd_wasi_ref_n) { + this.fd_map[i] = undefined; + // console.log("fd", i, "is removed"); + break; + } + } + // console.log("fd_and_wasi_ref_n", fd_and_wasi_ref_n); + } + // console.log("rm_fds.length", rm_fds.length); + // console.log("rm_fds", rm_fds); + } + } - get_share_memory(): WebAssembly.Memory { - return this.thread_spawner.get_share_memory(); - } + get_share_memory(): WebAssembly.Memory { + return this.thread_spawner.get_share_memory(); + } - constructor( - wasi_farm_refs: WASIFarmRefObject[] | WASIFarmRefObject, - args: Array, - env: Array, - options: Options & { - can_thread_spawn?: boolean; - thread_spawn_worker_url?: string; - thread_spawn_wasm?: WebAssembly.Module; - } = {}, - override_fd_maps?: Array, - thread_spawner?: ThreadSpawner, - ) { - debug.enable(options.debug); + constructor( + wasi_farm_refs: WASIFarmRefObject[] | WASIFarmRefObject, + args: Array, + env: Array, + options: Options & { + can_thread_spawn?: boolean; + thread_spawn_worker_url?: string; + thread_spawn_wasm?: WebAssembly.Module; + } = {}, + override_fd_maps?: Array, + thread_spawner?: ThreadSpawner, + ) { + debug.enable(options.debug); - let wasi_farm_refs_tmp: WASIFarmRefObject[]; - if (Array.isArray(wasi_farm_refs)) { - wasi_farm_refs_tmp = - wasi_farm_refs as unknown as Array; - } else { - wasi_farm_refs_tmp = [wasi_farm_refs as unknown as WASIFarmRefObject]; - } + let wasi_farm_refs_tmp: WASIFarmRefObject[]; + if (Array.isArray(wasi_farm_refs)) { + wasi_farm_refs_tmp = + wasi_farm_refs as unknown as Array; + } else { + wasi_farm_refs_tmp = [wasi_farm_refs as unknown as WASIFarmRefObject]; + } - try { - new SharedArrayBuffer(4); - this.can_array_buffer = true; - } catch (_) { - this.can_array_buffer = false; - } + try { + new SharedArrayBuffer(4); + this.can_array_buffer = true; + } catch (_) { + this.can_array_buffer = false; + } - this.id_in_wasi_farm_ref = []; - this.wasi_farm_refs = []; - for (let i = 0; i < wasi_farm_refs_tmp.length; i++) { - if (this.can_array_buffer) { - this.wasi_farm_refs.push( - WASIFarmRefUseArrayBuffer.init_self( - wasi_farm_refs_tmp[i] as WASIFarmRefUseArrayBufferObject, - ), - ); - } else { - throw new Error("Non SharedArrayBuffer is not supported yet"); - } - this.id_in_wasi_farm_ref.push(this.wasi_farm_refs[i].set_id()); - } + this.id_in_wasi_farm_ref = []; + this.wasi_farm_refs = []; + for (let i = 0; i < wasi_farm_refs_tmp.length; i++) { + if (this.can_array_buffer) { + this.wasi_farm_refs.push( + WASIFarmRefUseArrayBuffer.init_self( + wasi_farm_refs_tmp[i] as WASIFarmRefUseArrayBufferObject, + ), + ); + } else { + throw new Error("Non SharedArrayBuffer is not supported yet"); + } + this.id_in_wasi_farm_ref.push(this.wasi_farm_refs[i].set_id()); + } - // console.log("this.wasi_farm_refs", this.wasi_farm_refs); + // console.log("this.wasi_farm_refs", this.wasi_farm_refs); - if (options.can_thread_spawn) { - this.can_thread_spawn = options.can_thread_spawn; + if (options.can_thread_spawn) { + this.can_thread_spawn = options.can_thread_spawn; - if (thread_spawner) { - if (!(thread_spawner instanceof ThreadSpawner)) { - throw new Error("thread_spawner is not ThreadSpawner"); - } + if (thread_spawner) { + if (!(thread_spawner instanceof ThreadSpawner)) { + throw new Error("thread_spawner is not ThreadSpawner"); + } - this.thread_spawner = thread_spawner; - } else { - if (options.thread_spawn_worker_url === undefined) { - throw new Error("thread_spawn_worker_url is not defined"); - } - if (options.thread_spawn_wasm === undefined) { - throw new Error("thread_spawn_wasm is not defined"); - } + this.thread_spawner = thread_spawner; + } else { + if (options.thread_spawn_worker_url === undefined) { + throw new Error("thread_spawn_worker_url is not defined"); + } + if (options.thread_spawn_wasm === undefined) { + throw new Error("thread_spawn_wasm is not defined"); + } - this.thread_spawner = new ThreadSpawner( - options.thread_spawn_worker_url, - wasi_farm_refs_tmp, - undefined, - undefined, - undefined, - options.thread_spawn_wasm, - ); - } - } + this.thread_spawner = new ThreadSpawner( + options.thread_spawn_worker_url, + wasi_farm_refs_tmp, + undefined, + undefined, + undefined, + options.thread_spawn_wasm, + ); + } + } - this.mapping_fds(this.wasi_farm_refs, override_fd_maps); + this.mapping_fds(this.wasi_farm_refs, override_fd_maps); - // console.log("this.fd_map", this.fd_map); + // console.log("this.fd_map", this.fd_map); - this.args = args; - this.env = env; - const self = this; - this.wasiImport = { - args_sizes_get(argc: number, argv_buf_size: number): number { - self.check_fds(); - const buffer = new DataView(self.inst.exports.memory.buffer); - buffer.setUint32(argc, self.args.length, true); - let buf_size = 0; - for (const arg of self.args) { - buf_size += arg.length + 1; - } - buffer.setUint32(argv_buf_size, buf_size, true); - // debug.log( - // buffer.getUint32(argc, true), - // buffer.getUint32(argv_buf_size, true), - // ); - debug.log("read args_sizes_get: len", self.args.length); - return 0; - }, - args_get(argv: number, argv_buf: number): number { - self.check_fds(); - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const orig_argv_buf = argv_buf; - for (let i = 0; i < self.args.length; i++) { - buffer.setUint32(argv, argv_buf, true); - argv += 4; - const arg = new TextEncoder().encode(self.args[i]); - buffer8.set(arg, argv_buf); - buffer.setUint8(argv_buf + arg.length, 0); - argv_buf += arg.length + 1; - } - // if (debug.enabled) { - debug.log( - "read args_get: args", - new TextDecoder("utf-8").decode( - buffer8.slice(orig_argv_buf, argv_buf), - ), - ); - // } - return 0; - }, - environ_sizes_get(environ_count: number, environ_size: number): number { - self.check_fds(); - const buffer = new DataView(self.inst.exports.memory.buffer); - buffer.setUint32(environ_count, self.env.length, true); - let buf_size = 0; - for (const environ of self.env) { - buf_size += environ.length + 1; - } - buffer.setUint32(environ_size, buf_size, true); - // debug.log( - // buffer.getUint32(environ_count, true), - // buffer.getUint32(environ_size, true), - // ); - debug.log("read environ_sizes_get: len", self.env.length); - return 0; - }, - environ_get(environ: number, environ_buf: number): number { - self.check_fds(); - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const orig_environ_buf = environ_buf; - for (let i = 0; i < self.env.length; i++) { - buffer.setUint32(environ, environ_buf, true); - environ += 4; - const e = new TextEncoder().encode(self.env[i]); - buffer8.set(e, environ_buf); - buffer.setUint8(environ_buf + e.length, 0); - environ_buf += e.length + 1; - } - // if (debug.enabled) { - debug.log( - "read environ_get: environ", - new TextDecoder("utf-8").decode( - buffer8.slice(orig_environ_buf, environ_buf), - ), - ); - // } - return 0; - }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - clock_res_get(id: number, res_ptr: number): number { - self.check_fds(); - let resolutionValue: bigint; - switch (id) { - case wasi.CLOCKID_MONOTONIC: { - // https://developer.mozilla.org/en-US/docs/Web/API/Performance/now - // > Resolution in isolated contexts: 5 microseconds - resolutionValue = 5_000n; // 5 microseconds - break; - } - case wasi.CLOCKID_REALTIME: { - resolutionValue = 1_000_000n; // 1 millisecond? - break; - } - default: - return wasi.ERRNO_NOSYS; - } - const view = new DataView(self.inst.exports.memory.buffer); - view.setBigUint64(res_ptr, resolutionValue, true); - return wasi.ERRNO_SUCCESS; - }, - clock_time_get(id: number, precision: bigint, time: number): number { - self.check_fds(); - const buffer = new DataView(self.inst.exports.memory.buffer); - if (id === wasi.CLOCKID_REALTIME) { - buffer.setBigUint64( - time, - BigInt(new Date().getTime()) * 1_000_000n, - true, - ); - } else if (id === wasi.CLOCKID_MONOTONIC) { - let monotonic_time: bigint; - try { - monotonic_time = BigInt(Math.round(performance.now() * 1000000)); - } catch (e) { - // performance.now() is only available in browsers. - // TODO use the perf_hooks builtin module for NodeJS - monotonic_time = 0n; - } - buffer.setBigUint64(time, monotonic_time, true); - } else { - // TODO - buffer.setBigUint64(time, 0n, true); - } - return 0; - }, - fd_advise( - fd: number, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - offset: bigint, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - len: bigint, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - advice: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_advise(mapped_fd); - }, - fd_allocate(fd: number, offset: bigint, len: bigint) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_allocate(mapped_fd, offset, len); - }, - fd_close(fd: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const ret = wasi_farm_ref.fd_close(mapped_fd); - self.check_fds(); - return ret; - }, - fd_datasync(fd: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_datasync(mapped_fd); - }, - fd_fdstat_get(fd: number, fdstat_ptr: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const [fdstat, ret] = wasi_farm_ref.fd_fdstat_get(mapped_fd); - if (fdstat) { - fdstat.write_bytes( - new DataView(self.inst.exports.memory.buffer), - fdstat_ptr, - ); - } - return ret; - }, - fd_fdstat_set_flags(fd: number, flags: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_fdstat_set_flags(mapped_fd, flags); - }, - fd_fdstat_set_rights( - fd: number, - fs_rights_base: bigint, - fs_rights_inheriting: bigint, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_fdstat_set_rights( - mapped_fd, - fs_rights_base, - fs_rights_inheriting, - ); - }, - fd_filestat_get(fd: number, filestat_ptr: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const [filestat, ret] = wasi_farm_ref.fd_filestat_get(mapped_fd); - if (filestat) { - filestat.write_bytes( - new DataView(self.inst.exports.memory.buffer), - filestat_ptr, - ); - } - return ret; - }, - fd_filestat_set_size(fd: number, size: bigint) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_filestat_set_size(mapped_fd, size); - }, - fd_filestat_set_times( - fd: number, - atim: bigint, - mtim: bigint, - fst_flags: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_filestat_set_times( - mapped_fd, - atim, - mtim, - fst_flags, - ); - }, - fd_pread( - fd: number, - iovs_ptr: number, - iovs_len: number, - offset: bigint, - nread_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const iovs_view = new Uint32Array( - buffer.buffer, - iovs_ptr, - iovs_len * 2, - ); - const [nerad_and_read_data, ret] = wasi_farm_ref.fd_pread( - mapped_fd, - iovs_view, - offset, - ); - if (nerad_and_read_data) { - const iovecs = wasi.Iovec.read_bytes_array( - buffer, - iovs_ptr, - iovs_len, - ); - const [nread, read_data] = nerad_and_read_data; - buffer.setUint32(nread_ptr, nread, true); - let nreaded = 0; - for (const iovec of iovecs) { - if (nreaded + iovec.buf_len >= read_data.length) { - buffer8.set(read_data, iovec.buf); - break; - } - buffer8.set( - read_data.slice(nreaded, nreaded + iovec.buf_len), - iovec.buf, - ); - nreaded += iovec.buf_len; - } - } - return ret; - }, - fd_prestat_get(fd: number, prestat_ptr: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const [prestat, ret] = wasi_farm_ref.fd_prestat_get(mapped_fd); - if (prestat) { - const [tag, name_len] = prestat; - const buffer = new DataView(self.inst.exports.memory.buffer); - buffer.setUint32(prestat_ptr, tag, true); - buffer.setUint32(prestat_ptr + 4, name_len, true); - } - return ret; - }, - fd_prestat_dir_name(fd: number, path_ptr: number, path_len: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - // console.log("fd_prestat_dir_name: fd", mapped_fd, "path_len", path_len); - const [path, ret] = wasi_farm_ref.fd_prestat_dir_name( - mapped_fd, - path_len, - ); - if (path) { - // console.log("fd_prestat_dir_name", new TextDecoder().decode(path)); - // console.log("fd_prestat_dir_name", path); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - buffer8.set(path, path_ptr); - } - return ret; - }, - fd_pwrite( - fd: number, - iovs_ptr: number, - iovs_len: number, - offset: bigint, - nwritten_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len); - const data = new Uint8Array( - iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0), - ); - let nwritten = 0; - for (const iovec of iovecs) { - data.set( - buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len), - nwritten, - ); - nwritten += iovec.buf_len; - } - const [written, ret] = wasi_farm_ref.fd_pwrite(mapped_fd, data, offset); - if (written) { - buffer.setUint32(nwritten_ptr, written, true); - } - return ret; - }, - fd_read( - fd: number, - iovs_ptr: number, - iovs_len: number, - nread_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const iovs_view = new Uint32Array( - buffer.buffer, - iovs_ptr, - iovs_len * 2, - ); + this.args = args; + this.env = env; + const self = this; + this.wasiImport = { + args_sizes_get(argc: number, argv_buf_size: number): number { + self.check_fds(); + const buffer = new DataView(self.inst.exports.memory.buffer); + buffer.setUint32(argc, self.args.length, true); + let buf_size = 0; + for (const arg of self.args) { + buf_size += arg.length + 1; + } + buffer.setUint32(argv_buf_size, buf_size, true); + // debug.log( + // buffer.getUint32(argc, true), + // buffer.getUint32(argv_buf_size, true), + // ); + debug.log("read args_sizes_get: len", self.args.length); + return 0; + }, + args_get(argv: number, argv_buf: number): number { + self.check_fds(); + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const orig_argv_buf = argv_buf; + for (let i = 0; i < self.args.length; i++) { + buffer.setUint32(argv, argv_buf, true); + argv += 4; + const arg = new TextEncoder().encode(self.args[i]); + buffer8.set(arg, argv_buf); + buffer.setUint8(argv_buf + arg.length, 0); + argv_buf += arg.length + 1; + } + // if (debug.enabled) { + debug.log( + "read args_get: args", + new TextDecoder("utf-8").decode( + buffer8.slice(orig_argv_buf, argv_buf), + ), + ); + // } + return 0; + }, + environ_sizes_get(environ_count: number, environ_size: number): number { + self.check_fds(); + const buffer = new DataView(self.inst.exports.memory.buffer); + buffer.setUint32(environ_count, self.env.length, true); + let buf_size = 0; + for (const environ of self.env) { + buf_size += environ.length + 1; + } + buffer.setUint32(environ_size, buf_size, true); + // debug.log( + // buffer.getUint32(environ_count, true), + // buffer.getUint32(environ_size, true), + // ); + debug.log("read environ_sizes_get: len", self.env.length); + return 0; + }, + environ_get(environ: number, environ_buf: number): number { + self.check_fds(); + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const orig_environ_buf = environ_buf; + for (let i = 0; i < self.env.length; i++) { + buffer.setUint32(environ, environ_buf, true); + environ += 4; + const e = new TextEncoder().encode(self.env[i]); + buffer8.set(e, environ_buf); + buffer.setUint8(environ_buf + e.length, 0); + environ_buf += e.length + 1; + } + // if (debug.enabled) { + debug.log( + "read environ_get: environ", + new TextDecoder("utf-8").decode( + buffer8.slice(orig_environ_buf, environ_buf), + ), + ); + // } + return 0; + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + clock_res_get(id: number, res_ptr: number): number { + self.check_fds(); + let resolutionValue: bigint; + switch (id) { + case wasi.CLOCKID_MONOTONIC: { + // https://developer.mozilla.org/en-US/docs/Web/API/Performance/now + // > Resolution in isolated contexts: 5 microseconds + resolutionValue = 5_000n; // 5 microseconds + break; + } + case wasi.CLOCKID_REALTIME: { + resolutionValue = 1_000_000n; // 1 millisecond? + break; + } + default: + return wasi.ERRNO_NOSYS; + } + const view = new DataView(self.inst.exports.memory.buffer); + view.setBigUint64(res_ptr, resolutionValue, true); + return wasi.ERRNO_SUCCESS; + }, + clock_time_get(id: number, precision: bigint, time: number): number { + self.check_fds(); + const buffer = new DataView(self.inst.exports.memory.buffer); + if (id === wasi.CLOCKID_REALTIME) { + buffer.setBigUint64( + time, + BigInt(new Date().getTime()) * 1_000_000n, + true, + ); + } else if (id === wasi.CLOCKID_MONOTONIC) { + let monotonic_time: bigint; + try { + monotonic_time = BigInt(Math.round(performance.now() * 1000000)); + } catch (e) { + // performance.now() is only available in browsers. + // TODO use the perf_hooks builtin module for NodeJS + monotonic_time = 0n; + } + buffer.setBigUint64(time, monotonic_time, true); + } else { + // TODO + buffer.setBigUint64(time, 0n, true); + } + return 0; + }, + fd_advise( + fd: number, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + offset: bigint, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + len: bigint, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + advice: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_advise(mapped_fd); + }, + fd_allocate(fd: number, offset: bigint, len: bigint) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_allocate(mapped_fd, offset, len); + }, + fd_close(fd: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const ret = wasi_farm_ref.fd_close(mapped_fd); + self.check_fds(); + return ret; + }, + fd_datasync(fd: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_datasync(mapped_fd); + }, + fd_fdstat_get(fd: number, fdstat_ptr: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const [fdstat, ret] = wasi_farm_ref.fd_fdstat_get(mapped_fd); + if (fdstat) { + fdstat.write_bytes( + new DataView(self.inst.exports.memory.buffer), + fdstat_ptr, + ); + } + return ret; + }, + fd_fdstat_set_flags(fd: number, flags: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_fdstat_set_flags(mapped_fd, flags); + }, + fd_fdstat_set_rights( + fd: number, + fs_rights_base: bigint, + fs_rights_inheriting: bigint, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_fdstat_set_rights( + mapped_fd, + fs_rights_base, + fs_rights_inheriting, + ); + }, + fd_filestat_get(fd: number, filestat_ptr: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const [filestat, ret] = wasi_farm_ref.fd_filestat_get(mapped_fd); + if (filestat) { + filestat.write_bytes( + new DataView(self.inst.exports.memory.buffer), + filestat_ptr, + ); + } + return ret; + }, + fd_filestat_set_size(fd: number, size: bigint) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_filestat_set_size(mapped_fd, size); + }, + fd_filestat_set_times( + fd: number, + atim: bigint, + mtim: bigint, + fst_flags: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_filestat_set_times( + mapped_fd, + atim, + mtim, + fst_flags, + ); + }, + fd_pread( + fd: number, + iovs_ptr: number, + iovs_len: number, + offset: bigint, + nread_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const iovs_view = new Uint32Array( + buffer.buffer, + iovs_ptr, + iovs_len * 2, + ); + const [nerad_and_read_data, ret] = wasi_farm_ref.fd_pread( + mapped_fd, + iovs_view, + offset, + ); + if (nerad_and_read_data) { + const iovecs = wasi.Iovec.read_bytes_array( + buffer, + iovs_ptr, + iovs_len, + ); + const [nread, read_data] = nerad_and_read_data; + buffer.setUint32(nread_ptr, nread, true); + let nreaded = 0; + for (const iovec of iovecs) { + if (nreaded + iovec.buf_len >= read_data.length) { + buffer8.set(read_data, iovec.buf); + break; + } + buffer8.set( + read_data.slice(nreaded, nreaded + iovec.buf_len), + iovec.buf, + ); + nreaded += iovec.buf_len; + } + } + return ret; + }, + fd_prestat_get(fd: number, prestat_ptr: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const [prestat, ret] = wasi_farm_ref.fd_prestat_get(mapped_fd); + if (prestat) { + const [tag, name_len] = prestat; + const buffer = new DataView(self.inst.exports.memory.buffer); + buffer.setUint32(prestat_ptr, tag, true); + buffer.setUint32(prestat_ptr + 4, name_len, true); + } + return ret; + }, + fd_prestat_dir_name(fd: number, path_ptr: number, path_len: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + // console.log("fd_prestat_dir_name: fd", mapped_fd, "path_len", path_len); + const [path, ret] = wasi_farm_ref.fd_prestat_dir_name( + mapped_fd, + path_len, + ); + if (path) { + // console.log("fd_prestat_dir_name", new TextDecoder().decode(path)); + // console.log("fd_prestat_dir_name", path); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + buffer8.set(path, path_ptr); + } + return ret; + }, + fd_pwrite( + fd: number, + iovs_ptr: number, + iovs_len: number, + offset: bigint, + nwritten_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len); + const data = new Uint8Array( + iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0), + ); + let nwritten = 0; + for (const iovec of iovecs) { + data.set( + buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len), + nwritten, + ); + nwritten += iovec.buf_len; + } + const [written, ret] = wasi_farm_ref.fd_pwrite(mapped_fd, data, offset); + if (written) { + buffer.setUint32(nwritten_ptr, written, true); + } + return ret; + }, + fd_read( + fd: number, + iovs_ptr: number, + iovs_len: number, + nread_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const iovs_view = new Uint32Array( + buffer.buffer, + iovs_ptr, + iovs_len * 2, + ); - const [nerad_and_read_data, ret] = wasi_farm_ref.fd_read( - mapped_fd, - iovs_view, - ); - if (nerad_and_read_data) { - const iovecs = wasi.Iovec.read_bytes_array( - buffer, - iovs_ptr, - iovs_len, - ); - const [nread, read_data] = nerad_and_read_data; + const [nerad_and_read_data, ret] = wasi_farm_ref.fd_read( + mapped_fd, + iovs_view, + ); + if (nerad_and_read_data) { + const iovecs = wasi.Iovec.read_bytes_array( + buffer, + iovs_ptr, + iovs_len, + ); + const [nread, read_data] = nerad_and_read_data; - // console.log("fd_read: nread", nread, new TextDecoder().decode(read_data)); + // console.log("fd_read: nread", nread, new TextDecoder().decode(read_data)); - // fd_read: ref: 14 30 14 - // animals.ts:325 fd_read: nread 14 Hello, world! + // fd_read: ref: 14 30 14 + // animals.ts:325 fd_read: nread 14 Hello, world! - buffer.setUint32(nread_ptr, nread, true); - let nreaded = 0; - for (const iovec of iovecs) { - if (nreaded + iovec.buf_len >= read_data.length) { - buffer8.set(read_data, iovec.buf); - break; - } - buffer8.set( - read_data.slice(nreaded, nreaded + iovec.buf_len), - iovec.buf, - ); - nreaded += iovec.buf_len; - } - } - return ret; - }, - fd_readdir( - fd: number, - buf_ptr: number, - buf_len: number, - cookie: bigint, - buf_used_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const [nerad_and_read_data, ret] = wasi_farm_ref.fd_readdir( - mapped_fd, - buf_len, - cookie, - ); - if (nerad_and_read_data) { - const [read_data, buf_used] = nerad_and_read_data; - buffer.setUint32(buf_used_ptr, buf_used, true); - buffer8.set(read_data, buf_ptr); - } - return ret; - }, - fd_renumber(fd: number, to: number) { - self.check_fds(); + buffer.setUint32(nread_ptr, nread, true); + let nreaded = 0; + for (const iovec of iovecs) { + if (nreaded + iovec.buf_len >= read_data.length) { + buffer8.set(read_data, iovec.buf); + break; + } + buffer8.set( + read_data.slice(nreaded, nreaded + iovec.buf_len), + iovec.buf, + ); + nreaded += iovec.buf_len; + } + } + return ret; + }, + fd_readdir( + fd: number, + buf_ptr: number, + buf_len: number, + cookie: bigint, + buf_used_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const [nerad_and_read_data, ret] = wasi_farm_ref.fd_readdir( + mapped_fd, + buf_len, + cookie, + ); + if (nerad_and_read_data) { + const [read_data, buf_used] = nerad_and_read_data; + buffer.setUint32(buf_used_ptr, buf_used, true); + buffer8.set(read_data, buf_ptr); + } + return ret; + }, + fd_renumber(fd: number, to: number) { + self.check_fds(); - const [mapped_fd, wasi_farm_ref_n] = self.get_fd_and_wasi_ref_n(fd); - const [mapped_to, wasi_farm_ref_to] = self.get_fd_and_wasi_ref(to); + const [mapped_fd, wasi_farm_ref_n] = self.get_fd_and_wasi_ref_n(fd); + const [mapped_to, wasi_farm_ref_to] = self.get_fd_and_wasi_ref(to); - if ( - mapped_fd === undefined || - wasi_farm_ref_n === undefined || - mapped_to === undefined || - wasi_farm_ref_to === undefined - ) { - return wasi.ERRNO_BADF; - } + if ( + mapped_fd === undefined || + wasi_farm_ref_n === undefined || + mapped_to === undefined || + wasi_farm_ref_to === undefined + ) { + return wasi.ERRNO_BADF; + } - const ret = wasi_farm_ref_to.fd_close(mapped_to); - self.check_fds(); + const ret = wasi_farm_ref_to.fd_close(mapped_to); + self.check_fds(); - if (ret !== wasi.ERRNO_SUCCESS) { - return ret; - } + if (ret !== wasi.ERRNO_SUCCESS) { + return ret; + } - self.map_set_fd_and_notify(mapped_fd, wasi_farm_ref_n, to); + self.map_set_fd_and_notify(mapped_fd, wasi_farm_ref_n, to); - return wasi.ERRNO_SUCCESS; - }, - fd_seek( - fd: number, - offset: bigint, - whence: number, - newoffset_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - const [newoffset, ret] = wasi_farm_ref.fd_seek( - mapped_fd, - offset, - whence, - ); - if (newoffset) { - const buffer = new DataView(self.inst.exports.memory.buffer); + return wasi.ERRNO_SUCCESS; + }, + fd_seek( + fd: number, + offset: bigint, + whence: number, + newoffset_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + const [newoffset, ret] = wasi_farm_ref.fd_seek( + mapped_fd, + offset, + whence, + ); + if (newoffset) { + const buffer = new DataView(self.inst.exports.memory.buffer); - // wasi.ts use BigInt for offset, but API use Uint64 - buffer.setBigUint64(newoffset_ptr, newoffset, true); - } - return ret; - }, - fd_sync(fd: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - return wasi_farm_ref.fd_sync(mapped_fd); - }, - fd_tell(fd: number, newoffset_ptr: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - const [newoffset, ret] = wasi_farm_ref.fd_tell(mapped_fd); - if (newoffset) { - const buffer = new DataView(self.inst.exports.memory.buffer); - buffer.setBigUint64(newoffset_ptr, newoffset, true); - } - return ret; - }, - fd_write( - fd: number, - iovs_ptr: number, - iovs_len: number, - nwritten_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } + // wasi.ts use BigInt for offset, but API use Uint64 + buffer.setBigUint64(newoffset_ptr, newoffset, true); + } + return ret; + }, + fd_sync(fd: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + return wasi_farm_ref.fd_sync(mapped_fd); + }, + fd_tell(fd: number, newoffset_ptr: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + const [newoffset, ret] = wasi_farm_ref.fd_tell(mapped_fd); + if (newoffset) { + const buffer = new DataView(self.inst.exports.memory.buffer); + buffer.setBigUint64(newoffset_ptr, newoffset, true); + } + return ret; + }, + fd_write( + fd: number, + iovs_ptr: number, + iovs_len: number, + nwritten_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } - // console.log("fd_write", fd, iovs_ptr, iovs_len, nwritten_ptr); + // console.log("fd_write", fd, iovs_ptr, iovs_len, nwritten_ptr); - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len); - // console.log("iovecs", iovecs); - const data = new Uint8Array( - iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0), - ); - // console.log("data", data); - let nwritten = 0; - for (const iovec of iovecs) { - data.set( - buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len), - nwritten, - ); - nwritten += iovec.buf_len; - } + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len); + // console.log("iovecs", iovecs); + const data = new Uint8Array( + iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0), + ); + // console.log("data", data); + let nwritten = 0; + for (const iovec of iovecs) { + data.set( + buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len), + nwritten, + ); + nwritten += iovec.buf_len; + } - // console.log("fd_write: ", fd, new TextDecoder().decode(data)); + // console.log("fd_write: ", fd, new TextDecoder().decode(data)); - const [written, ret] = wasi_farm_ref.fd_write(mapped_fd, data); + const [written, ret] = wasi_farm_ref.fd_write(mapped_fd, data); - // console.log("fd_write end", fd, ret, written); + // console.log("fd_write end", fd, ret, written); - if (written) { - buffer.setUint32(nwritten_ptr, written, true); - } - return ret; - }, - path_create_directory(fd: number, path_ptr: number, path_len: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - return wasi_farm_ref.path_create_directory(mapped_fd, path); - }, - path_filestat_get( - fd: number, - flags: number, - path_ptr: number, - path_len: number, - filestat_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - const buffer = new DataView(self.inst.exports.memory.buffer); - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - const [filestat, ret] = wasi_farm_ref.path_filestat_get( - mapped_fd, - flags, - path, - ); - if (filestat) { - filestat.write_bytes(buffer, filestat_ptr); - } - return ret; - }, - path_filestat_set_times( - fd: number, - flags: number, - path_ptr: number, - path_len: number, - atim: bigint, - mtim: bigint, - fst_flags: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - return wasi_farm_ref.path_filestat_set_times( - mapped_fd, - flags, - path, - atim, - mtim, - fst_flags, - ); - }, - // TODO! Make it work with different wasi_farm_ref - path_link( - old_fd: number, - old_flags: number, - old_path_ptr: number, - old_path_len: number, - new_fd: number, - new_path_ptr: number, - new_path_len: number, - ) { - self.check_fds(); - const [mapped_old_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(old_fd); - const [mapped_new_fd, wasi_farm_ref_new] = - self.get_fd_and_wasi_ref(new_fd); - if ( - mapped_old_fd === undefined || - wasi_farm_ref === undefined || - mapped_new_fd === undefined || - wasi_farm_ref_new === undefined - ) { - return wasi.ERRNO_BADF; - } - if (wasi_farm_ref !== wasi_farm_ref_new) { - return wasi.ERRNO_BADF; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const old_path = buffer8.slice( - old_path_ptr, - old_path_ptr + old_path_len, - ); - const new_path = buffer8.slice( - new_path_ptr, - new_path_ptr + new_path_len, - ); - return wasi_farm_ref.path_link( - mapped_old_fd, - old_flags, - old_path, - mapped_new_fd, - new_path, - ); - }, - path_open( - fd: number, - dirflags: number, - path_ptr: number, - path_len: number, - oflags: number, - fs_rights_base: bigint, - fs_rights_inheriting: bigint, - fs_flags: number, - opened_fd_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref_n] = self.get_fd_and_wasi_ref_n(fd); - if (mapped_fd === undefined || wasi_farm_ref_n === undefined) { - return wasi.ERRNO_BADF; - } - const wasi_farm_ref = self.wasi_farm_refs[wasi_farm_ref_n]; - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - const [opened_fd, ret] = wasi_farm_ref.path_open( - mapped_fd, - dirflags, - path, - oflags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - ); - if (opened_fd) { - if (self.fd_map.includes([opened_fd, wasi_farm_ref_n])) { - throw new Error("opened_fd already exists"); - } - const mapped_opened_fd = self.map_new_fd_and_notify( - opened_fd, - wasi_farm_ref_n, - ); - const buffer = new DataView(self.inst.exports.memory.buffer); - buffer.setUint32(opened_fd_ptr, mapped_opened_fd, true); - } - return ret; - }, - path_readlink( - fd: number, - path_ptr: number, - path_len: number, - buf_ptr: number, - buf_len: number, - buf_used_ptr: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return [undefined, wasi.ERRNO_BADF]; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - const [buf, ret] = wasi_farm_ref.path_readlink( - mapped_fd, - path, - buf_len, - ); - if (buf) { - const buffer = new DataView(self.inst.exports.memory.buffer); - buffer.setUint32(buf_used_ptr, buf.length, true); - buffer8.set(buf, buf_ptr); - } - return ret; - }, - path_remove_directory(fd: number, path_ptr: number, path_len: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - return wasi_farm_ref.path_remove_directory(mapped_fd, path); - }, - // TODO! Make it work with different wasi_farm_ref - path_rename( - old_fd: number, - old_path_ptr: number, - old_path_len: number, - new_fd: number, - new_path_ptr: number, - new_path_len: number, - ) { - self.check_fds(); - const [mapped_old_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(old_fd); - const [mapped_new_fd, wasi_farm_ref_new] = - self.get_fd_and_wasi_ref(new_fd); - if ( - mapped_old_fd === undefined || - wasi_farm_ref === undefined || - mapped_new_fd === undefined || - wasi_farm_ref_new === undefined - ) { - return wasi.ERRNO_BADF; - } - if (wasi_farm_ref !== wasi_farm_ref_new) { - return wasi.ERRNO_BADF; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const old_path = buffer8.slice( - old_path_ptr, - old_path_ptr + old_path_len, - ); - const new_path = buffer8.slice( - new_path_ptr, - new_path_ptr + new_path_len, - ); - return wasi_farm_ref.path_rename( - mapped_old_fd, - old_path, - mapped_new_fd, - new_path, - ); - }, - path_symlink( - old_path_ptr: number, - old_path_len: number, - fd: number, - new_path_ptr: number, - new_path_len: number, - ) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const old_path = buffer8.slice( - old_path_ptr, - old_path_ptr + old_path_len, - ); - const new_path = buffer8.slice( - new_path_ptr, - new_path_ptr + new_path_len, - ); - return wasi_farm_ref.path_symlink(old_path, mapped_fd, new_path); - }, - path_unlink_file(fd: number, path_ptr: number, path_len: number) { - self.check_fds(); - const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); - if (mapped_fd === undefined || wasi_farm_ref === undefined) { - return wasi.ERRNO_BADF; - } - const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); - const path = buffer8.slice(path_ptr, path_ptr + path_len); - return wasi_farm_ref.path_unlink_file(mapped_fd, path); - }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - poll_oneoff(in_, out, nsubscriptions) { - self.check_fds(); - throw "async io not supported"; - }, - proc_exit(exit_code: number) { - self.check_fds(); - throw new WASIProcExit(exit_code); - }, - proc_raise(sig: number) { - self.check_fds(); - throw `raised signal ${sig}`; - }, - sched_yield() { - self.check_fds(); - }, - random_get(buf: number, buf_len: number) { - self.check_fds(); - const buffer8 = new Uint8Array( - self.inst.exports.memory.buffer, - ).subarray(buf, buf + buf_len); + if (written) { + buffer.setUint32(nwritten_ptr, written, true); + } + return ret; + }, + path_create_directory(fd: number, path_ptr: number, path_len: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + return wasi_farm_ref.path_create_directory(mapped_fd, path); + }, + path_filestat_get( + fd: number, + flags: number, + path_ptr: number, + path_len: number, + filestat_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + const buffer = new DataView(self.inst.exports.memory.buffer); + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + const [filestat, ret] = wasi_farm_ref.path_filestat_get( + mapped_fd, + flags, + path, + ); + if (filestat) { + filestat.write_bytes(buffer, filestat_ptr); + } + return ret; + }, + path_filestat_set_times( + fd: number, + flags: number, + path_ptr: number, + path_len: number, + atim: bigint, + mtim: bigint, + fst_flags: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + return wasi_farm_ref.path_filestat_set_times( + mapped_fd, + flags, + path, + atim, + mtim, + fst_flags, + ); + }, + // TODO! Make it work with different wasi_farm_ref + path_link( + old_fd: number, + old_flags: number, + old_path_ptr: number, + old_path_len: number, + new_fd: number, + new_path_ptr: number, + new_path_len: number, + ) { + self.check_fds(); + const [mapped_old_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(old_fd); + const [mapped_new_fd, wasi_farm_ref_new] = + self.get_fd_and_wasi_ref(new_fd); + if ( + mapped_old_fd === undefined || + wasi_farm_ref === undefined || + mapped_new_fd === undefined || + wasi_farm_ref_new === undefined + ) { + return wasi.ERRNO_BADF; + } + if (wasi_farm_ref !== wasi_farm_ref_new) { + return wasi.ERRNO_BADF; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const old_path = buffer8.slice( + old_path_ptr, + old_path_ptr + old_path_len, + ); + const new_path = buffer8.slice( + new_path_ptr, + new_path_ptr + new_path_len, + ); + return wasi_farm_ref.path_link( + mapped_old_fd, + old_flags, + old_path, + mapped_new_fd, + new_path, + ); + }, + path_open( + fd: number, + dirflags: number, + path_ptr: number, + path_len: number, + oflags: number, + fs_rights_base: bigint, + fs_rights_inheriting: bigint, + fs_flags: number, + opened_fd_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref_n] = self.get_fd_and_wasi_ref_n(fd); + if (mapped_fd === undefined || wasi_farm_ref_n === undefined) { + return wasi.ERRNO_BADF; + } + const wasi_farm_ref = self.wasi_farm_refs[wasi_farm_ref_n]; + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + const [opened_fd, ret] = wasi_farm_ref.path_open( + mapped_fd, + dirflags, + path, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + ); + if (opened_fd) { + if (self.fd_map.includes([opened_fd, wasi_farm_ref_n])) { + throw new Error("opened_fd already exists"); + } + const mapped_opened_fd = self.map_new_fd_and_notify( + opened_fd, + wasi_farm_ref_n, + ); + const buffer = new DataView(self.inst.exports.memory.buffer); + buffer.setUint32(opened_fd_ptr, mapped_opened_fd, true); + } + return ret; + }, + path_readlink( + fd: number, + path_ptr: number, + path_len: number, + buf_ptr: number, + buf_len: number, + buf_used_ptr: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return [undefined, wasi.ERRNO_BADF]; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + const [buf, ret] = wasi_farm_ref.path_readlink( + mapped_fd, + path, + buf_len, + ); + if (buf) { + const buffer = new DataView(self.inst.exports.memory.buffer); + buffer.setUint32(buf_used_ptr, buf.length, true); + buffer8.set(buf, buf_ptr); + } + return ret; + }, + path_remove_directory(fd: number, path_ptr: number, path_len: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + return wasi_farm_ref.path_remove_directory(mapped_fd, path); + }, + // TODO! Make it work with different wasi_farm_ref + path_rename( + old_fd: number, + old_path_ptr: number, + old_path_len: number, + new_fd: number, + new_path_ptr: number, + new_path_len: number, + ) { + self.check_fds(); + const [mapped_old_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(old_fd); + const [mapped_new_fd, wasi_farm_ref_new] = + self.get_fd_and_wasi_ref(new_fd); + if ( + mapped_old_fd === undefined || + wasi_farm_ref === undefined || + mapped_new_fd === undefined || + wasi_farm_ref_new === undefined + ) { + return wasi.ERRNO_BADF; + } + if (wasi_farm_ref !== wasi_farm_ref_new) { + return wasi.ERRNO_BADF; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const old_path = buffer8.slice( + old_path_ptr, + old_path_ptr + old_path_len, + ); + const new_path = buffer8.slice( + new_path_ptr, + new_path_ptr + new_path_len, + ); + return wasi_farm_ref.path_rename( + mapped_old_fd, + old_path, + mapped_new_fd, + new_path, + ); + }, + path_symlink( + old_path_ptr: number, + old_path_len: number, + fd: number, + new_path_ptr: number, + new_path_len: number, + ) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const old_path = buffer8.slice( + old_path_ptr, + old_path_ptr + old_path_len, + ); + const new_path = buffer8.slice( + new_path_ptr, + new_path_ptr + new_path_len, + ); + return wasi_farm_ref.path_symlink(old_path, mapped_fd, new_path); + }, + path_unlink_file(fd: number, path_ptr: number, path_len: number) { + self.check_fds(); + const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd); + if (mapped_fd === undefined || wasi_farm_ref === undefined) { + return wasi.ERRNO_BADF; + } + const buffer8 = new Uint8Array(self.inst.exports.memory.buffer); + const path = buffer8.slice(path_ptr, path_ptr + path_len); + return wasi_farm_ref.path_unlink_file(mapped_fd, path); + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + poll_oneoff(in_, out, nsubscriptions) { + self.check_fds(); + throw "async io not supported"; + }, + proc_exit(exit_code: number) { + self.check_fds(); + throw new WASIProcExit(exit_code); + }, + proc_raise(sig: number) { + self.check_fds(); + throw `raised signal ${sig}`; + }, + sched_yield() { + self.check_fds(); + }, + random_get(buf: number, buf_len: number) { + self.check_fds(); + const buffer8 = new Uint8Array( + self.inst.exports.memory.buffer, + ).subarray(buf, buf + buf_len); - if ( - "crypto" in globalThis && - !(self.inst.exports.memory.buffer instanceof SharedArrayBuffer) - ) { - for (let i = 0; i < buf_len; i += 65536) { - crypto.getRandomValues(buffer8.subarray(i, i + 65536)); - } - } else { - for (let i = 0; i < buf_len; i++) { - buffer8[i] = (Math.random() * 256) | 0; - } - } - }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - sock_recv(fd: number, ri_data, ri_flags) { - self.check_fds(); - throw "sockets not supported"; - }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - sock_send(fd: number, si_data, si_flags) { - self.check_fds(); - throw "sockets not supported"; - }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - sock_shutdown(fd: number, how) { - self.check_fds(); - throw "sockets not supported"; - }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - sock_accept(fd: number, flags) { - self.check_fds(); - throw "sockets not supported"; - }, - }; + if ( + "crypto" in globalThis && + !(self.inst.exports.memory.buffer instanceof SharedArrayBuffer) + ) { + for (let i = 0; i < buf_len; i += 65536) { + crypto.getRandomValues(buffer8.subarray(i, i + 65536)); + } + } else { + for (let i = 0; i < buf_len; i++) { + buffer8[i] = (Math.random() * 256) | 0; + } + } + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + sock_recv(fd: number, ri_data, ri_flags) { + self.check_fds(); + throw "sockets not supported"; + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + sock_send(fd: number, si_data, si_flags) { + self.check_fds(); + throw "sockets not supported"; + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + sock_shutdown(fd: number, how) { + self.check_fds(); + throw "sockets not supported"; + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + sock_accept(fd: number, flags) { + self.check_fds(); + throw "sockets not supported"; + }, + }; - this.wasiThreadImport = { - "thread-spawn": (start_arg: number) => { - self.check_fds(); - if (!self.can_thread_spawn) { - throw new Error("thread_spawn is not allowed"); - } + this.wasiThreadImport = { + "thread-spawn": (start_arg: number) => { + self.check_fds(); + if (!self.can_thread_spawn) { + throw new Error("thread_spawn is not allowed"); + } - const thread_id = self.thread_spawner.thread_spawn( - start_arg, - self.args, - self.env, - self.fd_map, - ); + const thread_id = self.thread_spawner.thread_spawn( + start_arg, + self.args, + self.env, + self.fd_map, + ); - return thread_id; - }, - }; - } + return thread_id; + }, + }; + } } diff --git a/src/wasi_farm/farm.ts b/src/wasi_farm/farm.ts index 64090e9..7966339 100644 --- a/src/wasi_farm/farm.ts +++ b/src/wasi_farm/farm.ts @@ -6,106 +6,106 @@ import type { WASIFarmRefObject } from "./ref.js"; import { WASIFarmParkUseArrayBuffer } from "./shared_array_buffer/index.js"; export class WASIFarm { - private fds: Array; - private park: WASIFarmPark; + private fds: Array; + private park: WASIFarmPark; - private can_array_buffer; + private can_array_buffer; - constructor( - stdin?: Fd, - stdout?: Fd, - stderr?: Fd, - fds: Array = [], - options: Options & { - allocator_size?: number; - } = {}, - ) { - debug.enable(options.debug); + constructor( + stdin?: Fd, + stdout?: Fd, + stderr?: Fd, + fds: Array = [], + options: Options & { + allocator_size?: number; + } = {}, + ) { + debug.enable(options.debug); - const new_fds = []; - let stdin_ = undefined; - let stdout_ = undefined; - let stderr_ = undefined; - if (stdin) { - new_fds.push(stdin); - stdin_ = new_fds.length - 1; - } - if (stdout) { - new_fds.push(stdout); - stdout_ = new_fds.length - 1; - } - if (stderr) { - new_fds.push(stderr); - stderr_ = new_fds.length - 1; - } - new_fds.push(...fds); + const new_fds = []; + let stdin_ = undefined; + let stdout_ = undefined; + let stderr_ = undefined; + if (stdin) { + new_fds.push(stdin); + stdin_ = new_fds.length - 1; + } + if (stdout) { + new_fds.push(stdout); + stdout_ = new_fds.length - 1; + } + if (stderr) { + new_fds.push(stderr); + stderr_ = new_fds.length - 1; + } + new_fds.push(...fds); - const default_allow_fds = []; - for (let i = 0; i < new_fds.length; i++) { - default_allow_fds.push(i); - } + const default_allow_fds = []; + for (let i = 0; i < new_fds.length; i++) { + default_allow_fds.push(i); + } - this.fds = new_fds; + this.fds = new_fds; - // WebAssembly.Memory can be used to create a SharedArrayBuffer, but it cannot be transferred by postMessage. - // Uncaught (in promise) DataCloneError: - // Failed to execute 'postMessage' on 'Worker': - // SharedArrayBuffer transfer requires self.crossOriginIsolated. - try { - new SharedArrayBuffer(4); - this.can_array_buffer = true; - } catch (e) { - this.can_array_buffer = false; - console.warn("SharedArrayBuffer is not supported:", e); + // WebAssembly.Memory can be used to create a SharedArrayBuffer, but it cannot be transferred by postMessage. + // Uncaught (in promise) DataCloneError: + // Failed to execute 'postMessage' on 'Worker': + // SharedArrayBuffer transfer requires self.crossOriginIsolated. + try { + new SharedArrayBuffer(4); + this.can_array_buffer = true; + } catch (e) { + this.can_array_buffer = false; + console.warn("SharedArrayBuffer is not supported:", e); - if (!crossOriginIsolated) { - console.warn( - "SharedArrayBuffer is not supported because crossOriginIsolated is not enabled.", - ); - } - } + if (!crossOriginIsolated) { + console.warn( + "SharedArrayBuffer is not supported because crossOriginIsolated is not enabled.", + ); + } + } - if (this.can_array_buffer) { - this.park = new WASIFarmParkUseArrayBuffer( - this.fds_ref(), - stdin_, - stdout_, - stderr_, - default_allow_fds, - options?.allocator_size, - ); - } else { - throw new Error("Non SharedArrayBuffer is not supported yet"); - } + if (this.can_array_buffer) { + this.park = new WASIFarmParkUseArrayBuffer( + this.fds_ref(), + stdin_, + stdout_, + stderr_, + default_allow_fds, + options?.allocator_size, + ); + } else { + throw new Error("Non SharedArrayBuffer is not supported yet"); + } - this.park.listen(); - } + this.park.listen(); + } - private fds_ref(): Array { - const fds = new Proxy([] as Array, { - get: (_, prop) => { - // console.log("fds", prop); + private fds_ref(): Array { + const fds = new Proxy([] as Array, { + get: (_, prop) => { + // console.log("fds", prop); - if (prop === "push") { - return (fd: Fd) => { - const len = this.fds.push(fd); - return len; - }; - } - return this.fds[prop]; - }, + if (prop === "push") { + return (fd: Fd) => { + const len = this.fds.push(fd); + return len; + }; + } + return this.fds[prop]; + }, - set: (_, prop, value) => { - // console.log("fds", prop, value); - this.fds[prop] = value; - return true; - }, - }); + set: (_, prop, value) => { + // console.log("fds", prop, value); + this.fds[prop] = value; + return true; + }, + }); - return fds; - } + return fds; + } - get_ref(): WASIFarmRefObject { - return this.park.get_ref(); - } + get_ref(): WASIFarmRefObject { + return this.park.get_ref(); + } } diff --git a/src/wasi_farm/park.ts b/src/wasi_farm/park.ts index 1294062..03e6119 100644 --- a/src/wasi_farm/park.ts +++ b/src/wasi_farm/park.ts @@ -4,582 +4,582 @@ import * as wasi from "../wasi_defs.js"; import type { WASIFarmRefObject } from "./ref.js"; export abstract class WASIFarmPark { - abstract get_ref(): WASIFarmRefObject; - abstract listen(): void; - abstract notify_set_fd(fd: number): void; - abstract notify_rm_fd(fd: number): void; - abstract can_set_new_fd(fd: number): [boolean, Promise | undefined]; - - protected fds: Array; - protected stdin: number | undefined; - protected stdout: number | undefined; - protected stderr: number | undefined; - protected default_allow_fds: Array; - - constructor( - fds: Array, - stdin: number | undefined, - stdout: number | undefined, - stderr: number | undefined, - default_allow_fds: Array, - ) { - this.fds = fds; - this.stdin = stdin; - this.stdout = stdout; - this.stderr = stderr; - this.default_allow_fds = default_allow_fds; - this.fds_map = new Array(fds.length); - for (let i = 0; i < fds.length; i++) { - this.fds_map[i] = []; - } - // console.log("first fds_map", this.fds_map); - } - - private get_new_fd_lock = new Array<() => Promise>(); - - // fdに対して、現在そのfdにidがアクセス可能かを示す。 - protected fds_map: Array; - - // If the reassigned value is accessed after being closed, - // it will be strange, - // but the programmer should have written it - // so that this does not happen in the first place. - private async get_new_fd(): Promise<[() => Promise, number]> { - const promise = new Promise<[() => Promise, number]>((resolve) => { - const len = this.get_new_fd_lock.push(async () => { - let ret = -1; - for (let i = 0; i < this.fds.length; i++) { - if (this.fds[i] === undefined) { - ret = i; - break; - } - } - if (ret === -1) { - ret = this.fds.length; - // console.log("push_fd", this.fds.length) - this.fds.push(undefined); - this.fds_map.push([]); - // console.log("push_fd", this.fds.length) - } - - const [can, promise] = this.can_set_new_fd(ret); - if (!can) { - await promise; - } - - // If it's assigned, it's resolved. - resolve([ - async () => { - this.get_new_fd_lock.shift(); - const fn = this.get_new_fd_lock[0]; - if (fn !== undefined) { - fn(); - } - // assigned and notify - await this.notify_set_fd(ret); - }, - ret, - ]); - }); - if (len === 1) { - this.get_new_fd_lock[0](); - } - }); - return promise; - } - - protected fd_advise(fd: number): number { - if (this.fds[fd] !== undefined) { - return wasi.ERRNO_SUCCESS; - } - return wasi.ERRNO_BADF; - } - - protected fd_allocate(fd: number, offset: bigint, len: bigint): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_allocate(offset, len); - } - return wasi.ERRNO_BADF; - } - - protected async fd_close(fd: number): Promise { - if (this.fds[fd] !== undefined) { - const ret = this.fds[fd].fd_close(); - this.fds[fd] = undefined; - // console.log("fd_close1", fd); - await this.notify_rm_fd(fd); - // console.log("fd_close2", fd); - return ret; - } - return wasi.ERRNO_BADF; - } - - protected fd_datasync(fd: number): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_sync(); - } - return wasi.ERRNO_BADF; - } - - protected fd_fdstat_get(fd: number): [wasi.Fdstat | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, fdstat } = this.fds[fd].fd_fdstat_get(); - if (fdstat != null) { - return [fdstat, ret]; - } - return [undefined, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_fdstat_set_flags(fd: number, flags: number): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_fdstat_set_flags(flags); - } - return wasi.ERRNO_BADF; - } - - protected fd_fdstat_set_rights( - fd: number, - fs_rights_base: bigint, - fs_rights_inheriting: bigint, - ): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_fdstat_set_rights( - fs_rights_base, - fs_rights_inheriting, - ); - } - return wasi.ERRNO_BADF; - } - - protected fd_filestat_get(fd: number): [wasi.Filestat | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, filestat } = this.fds[fd].fd_filestat_get(); - if (filestat != null) { - return [filestat, ret]; - } - return [undefined, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_filestat_set_size(fd: number, size: bigint): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_filestat_set_size(size); - } - return wasi.ERRNO_BADF; - } - - protected fd_filestat_set_times( - fd: number, - atim: bigint, - mtim: bigint, - fst_flags: number, - ): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_filestat_set_times(atim, mtim, fst_flags); - } - return wasi.ERRNO_BADF; - } - - protected fd_pread( - fd: number, - iovecs: Array, - offset: bigint, - ): [[number, Uint8Array] | undefined, number] { - if (this.fds[fd] !== undefined) { - let nread = 0; - - let buffer8 = new Uint8Array(0); - for (const iovec of iovecs) { - const { ret, data } = this.fds[fd].fd_pread(iovec.buf_len, offset); - if (ret !== wasi.ERRNO_SUCCESS) { - return [[nread, buffer8], ret]; - } - const new_buffer = new Uint8Array(buffer8.byteLength + data.byteLength); - new_buffer.set(buffer8); - new_buffer.set(data, buffer8.byteLength); - buffer8 = new_buffer; - nread += data.byteLength; - if (data.byteLength !== iovec.buf_len) { - break; - } - } - return [[nread, buffer8], wasi.ERRNO_SUCCESS]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_prestat_get(fd: number): [wasi.Prestat | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, prestat } = this.fds[fd].fd_prestat_get(); - if (prestat != null) { - return [prestat, ret]; - } - return [undefined, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_prestat_dir_name( - fd: number, - path_len: number, - ): [Uint8Array | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, prestat } = this.fds[fd].fd_prestat_get(); - if (prestat) { - const prestat_dir_name = prestat.inner.pr_name; - - // console.log("fd_prestat_dir_name: park: inner: ", prestat_dir_name); - // console.log("fd_prestat_dir_name: park: inner: ", new TextDecoder().decode(prestat_dir_name)); - - // console.log("fd_prestat_dir_name: park: path_len: ", path_len); - - if (prestat_dir_name.length <= path_len) { - // console.log("fd_prestat_dir_name: park: A"); - return [prestat_dir_name, ret]; - } - - // console.log("fd_prestat_dir_name: park: B"); - return [prestat_dir_name.slice(0, path_len), wasi.ERRNO_NAMETOOLONG]; - } - // console.log("fd_prestat_dir_name: park: C"); - return [undefined, ret]; - } - // console.log("fd_prestat_dir_name: park: D"); - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_pwrite( - fd: number, - write_data: Uint8Array, - offset: bigint, - ): [number | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, nwritten } = this.fds[fd].fd_pwrite(write_data, offset); - return [nwritten, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_read( - fd: number, - iovecs: Array, - ): [[number, Uint8Array] | undefined, number] { - if (this.fds[fd] !== undefined) { - let nread = 0; - - // console.log("fd_read: park: iovecs: ", iovecs); - - // const sum_len = iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0); - - // console.warn("fd_read: park: sum_len: ", sum_len); - - let buffer8 = new Uint8Array(0); - for (const iovec of iovecs) { - const { ret, data } = this.fds[fd].fd_read(iovec.buf_len); - // console.log("fd_read: park: data: ", data); - if (ret !== wasi.ERRNO_SUCCESS) { - return [[nread, buffer8], ret]; - } - const new_buffer = new Uint8Array(buffer8.byteLength + data.byteLength); - new_buffer.set(buffer8); - new_buffer.set(data, buffer8.byteLength); - buffer8 = new_buffer; - nread += data.byteLength; - if (data.byteLength !== iovec.buf_len) { - break; - } - } - - // console.log("fd_read: park: nread: ", nread); - - return [[nread, buffer8], wasi.ERRNO_SUCCESS]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_readdir( - fd: number, - buf_len: number, - cookie: bigint, - ): [[Uint8Array, number] | undefined, number] { - if (this.fds[fd] !== undefined) { - const array = new Uint8Array(buf_len); - - let buf_used = 0; - let offset = 0; - - // eslint-disable-next-line no-constant-condition - while (true) { - const { ret, dirent } = this.fds[fd].fd_readdir_single(cookie); - if (ret !== wasi.ERRNO_SUCCESS) { - return [[array, buf_used], ret]; - } - if (dirent == null) { - break; - } - if (buf_len - buf_used < dirent.head_length()) { - buf_used = buf_len; - break; - } - - const head_bytes = new ArrayBuffer(dirent.head_length()); - dirent.write_head_bytes(new DataView(head_bytes), 0); - array.set( - new Uint8Array(head_bytes).slice( - 0, - Math.min(head_bytes.byteLength, buf_len - buf_used), - ), - offset, - ); - offset += head_bytes.byteLength; - buf_used += head_bytes.byteLength; - - if (buf_len - buf_used < dirent.name_length()) { - buf_used = buf_len; - break; - } - - dirent.write_name_bytes(array, offset, buf_len - buf_used); - offset += dirent.name_length(); - buf_used += dirent.name_length(); - - cookie = dirent.d_next; - } - - return [[array, buf_used], wasi.ERRNO_SUCCESS]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - // protected async fd_renumber(fd: number, to: number): Promise { - // if (this.fds[fd] != undefined) { - // const ret = this.fds[to].fd_close(); - // if (ret != wasi.ERRNO_SUCCESS) { - // return ret; - // } - // this.fds[to] = this.fds[fd]; - // this.fds[fd] = undefined; - // await this.notify_rm_fd(fd); - // return wasi.ERRNO_SUCCESS; - // } else { - // return wasi.ERRNO_BADF; - // } - // } - - protected fd_seek( - fd: number, - offset: bigint, - whence: number, - ): [bigint | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, offset: new_offset } = this.fds[fd].fd_seek(offset, whence); - return [new_offset, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_sync(fd: number): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].fd_sync(); - } - return wasi.ERRNO_BADF; - } - - protected fd_tell(fd: number): [bigint | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, offset } = this.fds[fd].fd_tell(); - return [offset, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected fd_write( - fd: number, - write_data: Uint8Array, - ): [number | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, nwritten } = this.fds[fd].fd_write(write_data); - return [nwritten, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected path_create_directory(fd: number, path: string): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].path_create_directory(path); - } - return wasi.ERRNO_BADF; - } - - protected path_filestat_get( - fd: number, - flags: number, - path: string, - ): [wasi.Filestat | undefined, number] { - if (this.fds[fd] !== undefined) { - const { ret, filestat } = this.fds[fd].path_filestat_get(flags, path); - if (filestat != null) { - return [filestat, ret]; - } - return [undefined, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected path_filestat_set_times( - fd: number, - flags: number, - path: string, - atim: bigint, - mtim: bigint, - fst_flags: number, - ): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].path_filestat_set_times( - flags, - path, - atim, - mtim, - fst_flags, - ); - } - return wasi.ERRNO_BADF; - } - - protected path_link( - old_fd: number, - old_flags: number, - old_path: string, - new_fd: number, - new_path: string, - ): number { - if (this.fds[old_fd] !== undefined && this.fds[new_fd] !== undefined) { - const { ret, inode_obj } = this.fds[old_fd].path_lookup( - old_path, - old_flags, - ); - if (inode_obj == null) { - return ret; - } - return this.fds[new_fd].path_link(new_path, inode_obj, false); - } - return wasi.ERRNO_BADF; - } - - protected async path_open( - fd: number, - dirflags: number, - path: string, - oflags: number, - fs_rights_base: bigint, - fs_rights_inheriting: bigint, - fs_flags: number, - ): Promise<[number | undefined, number]> { - if (this.fds[fd] !== undefined) { - debug.log("path_open", path); - const { ret, fd_obj } = this.fds[fd].path_open( - dirflags, - path, - oflags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - ); - // console.log("path_open: park: ", ret, fd_obj); - if (ret !== wasi.ERRNO_SUCCESS) { - return [undefined, ret]; - } - - const [resolve, opened_fd] = await this.get_new_fd(); - - // console.log("path_open: park: ", path, "opened_fd" ,opened_fd); - - this.fds[opened_fd] = fd_obj; - - await resolve(); - - // console.log("path_open: park: len: ", len); - - // console.log("path_open: park: ", opened_fd); - - return [opened_fd, wasi.ERRNO_SUCCESS]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected path_readlink( - fd: number, - path: string, - buf_len: number, - ): [Uint8Array | undefined, number] { - if (this.fds[fd] !== undefined) { - debug.log("path_readlink", path); - const { ret, data } = this.fds[fd].path_readlink(path); - if (data != null) { - const data_buf = new TextEncoder().encode(data); - if (data_buf.byteLength > buf_len) { - // wasi.ts use ERRNO_BADF. I think it should be ERRNO_OVERFLOW. - return [data_buf.slice(0, buf_len), wasi.ERRNO_OVERFLOW]; - } - return [data_buf, ret]; - } - return [undefined, ret]; - } - return [undefined, wasi.ERRNO_BADF]; - } - - protected path_remove_directory(fd: number, path: string): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].path_remove_directory(path); - } - return wasi.ERRNO_BADF; - } - - protected path_rename( - old_fd: number, - old_path: string, - new_fd: number, - new_path: string, - ): number { - if (this.fds[old_fd] !== undefined && this.fds[new_fd] !== undefined) { - // eslint-disable-next-line prefer-const - let { ret, inode_obj } = this.fds[old_fd].path_unlink(old_path); - if (inode_obj == null) { - return ret; - } - ret = this.fds[new_fd].path_link(new_path, inode_obj, true); - if (ret !== wasi.ERRNO_SUCCESS) { - if ( - this.fds[old_fd].path_link(old_path, inode_obj, true) !== - wasi.ERRNO_SUCCESS - ) { - throw "path_link should always return success when relinking an inode back to the original place"; - } - } - return ret; - } - return wasi.ERRNO_BADF; - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - protected path_symlink( - old_path: string, - fd: number, - new_path: string, - ): number { - if (this.fds[fd] !== undefined) { - return wasi.ERRNO_NOTSUP; - } - return wasi.ERRNO_BADF; - } - - protected path_unlink_file(fd: number, path: string): number { - if (this.fds[fd] !== undefined) { - return this.fds[fd].path_unlink_file(path); - } - return wasi.ERRNO_BADF; - } + abstract get_ref(): WASIFarmRefObject; + abstract listen(): void; + abstract notify_set_fd(fd: number): void; + abstract notify_rm_fd(fd: number): void; + abstract can_set_new_fd(fd: number): [boolean, Promise | undefined]; + + protected fds: Array; + protected stdin: number | undefined; + protected stdout: number | undefined; + protected stderr: number | undefined; + protected default_allow_fds: Array; + + constructor( + fds: Array, + stdin: number | undefined, + stdout: number | undefined, + stderr: number | undefined, + default_allow_fds: Array, + ) { + this.fds = fds; + this.stdin = stdin; + this.stdout = stdout; + this.stderr = stderr; + this.default_allow_fds = default_allow_fds; + this.fds_map = new Array(fds.length); + for (let i = 0; i < fds.length; i++) { + this.fds_map[i] = []; + } + // console.log("first fds_map", this.fds_map); + } + + private get_new_fd_lock = new Array<() => Promise>(); + + // fdに対して、現在そのfdにidがアクセス可能かを示す。 + protected fds_map: Array; + + // If the reassigned value is accessed after being closed, + // it will be strange, + // but the programmer should have written it + // so that this does not happen in the first place. + private async get_new_fd(): Promise<[() => Promise, number]> { + const promise = new Promise<[() => Promise, number]>((resolve) => { + const len = this.get_new_fd_lock.push(async () => { + let ret = -1; + for (let i = 0; i < this.fds.length; i++) { + if (this.fds[i] === undefined) { + ret = i; + break; + } + } + if (ret === -1) { + ret = this.fds.length; + // console.log("push_fd", this.fds.length) + this.fds.push(undefined); + this.fds_map.push([]); + // console.log("push_fd", this.fds.length) + } + + const [can, promise] = this.can_set_new_fd(ret); + if (!can) { + await promise; + } + + // If it's assigned, it's resolved. + resolve([ + async () => { + this.get_new_fd_lock.shift(); + const fn = this.get_new_fd_lock[0]; + if (fn !== undefined) { + fn(); + } + // assigned and notify + await this.notify_set_fd(ret); + }, + ret, + ]); + }); + if (len === 1) { + this.get_new_fd_lock[0](); + } + }); + return promise; + } + + protected fd_advise(fd: number): number { + if (this.fds[fd] !== undefined) { + return wasi.ERRNO_SUCCESS; + } + return wasi.ERRNO_BADF; + } + + protected fd_allocate(fd: number, offset: bigint, len: bigint): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_allocate(offset, len); + } + return wasi.ERRNO_BADF; + } + + protected async fd_close(fd: number): Promise { + if (this.fds[fd] !== undefined) { + const ret = this.fds[fd].fd_close(); + this.fds[fd] = undefined; + // console.log("fd_close1", fd); + await this.notify_rm_fd(fd); + // console.log("fd_close2", fd); + return ret; + } + return wasi.ERRNO_BADF; + } + + protected fd_datasync(fd: number): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_sync(); + } + return wasi.ERRNO_BADF; + } + + protected fd_fdstat_get(fd: number): [wasi.Fdstat | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, fdstat } = this.fds[fd].fd_fdstat_get(); + if (fdstat != null) { + return [fdstat, ret]; + } + return [undefined, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_fdstat_set_flags(fd: number, flags: number): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_fdstat_set_flags(flags); + } + return wasi.ERRNO_BADF; + } + + protected fd_fdstat_set_rights( + fd: number, + fs_rights_base: bigint, + fs_rights_inheriting: bigint, + ): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_fdstat_set_rights( + fs_rights_base, + fs_rights_inheriting, + ); + } + return wasi.ERRNO_BADF; + } + + protected fd_filestat_get(fd: number): [wasi.Filestat | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, filestat } = this.fds[fd].fd_filestat_get(); + if (filestat != null) { + return [filestat, ret]; + } + return [undefined, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_filestat_set_size(fd: number, size: bigint): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_filestat_set_size(size); + } + return wasi.ERRNO_BADF; + } + + protected fd_filestat_set_times( + fd: number, + atim: bigint, + mtim: bigint, + fst_flags: number, + ): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_filestat_set_times(atim, mtim, fst_flags); + } + return wasi.ERRNO_BADF; + } + + protected fd_pread( + fd: number, + iovecs: Array, + offset: bigint, + ): [[number, Uint8Array] | undefined, number] { + if (this.fds[fd] !== undefined) { + let nread = 0; + + let buffer8 = new Uint8Array(0); + for (const iovec of iovecs) { + const { ret, data } = this.fds[fd].fd_pread(iovec.buf_len, offset); + if (ret !== wasi.ERRNO_SUCCESS) { + return [[nread, buffer8], ret]; + } + const new_buffer = new Uint8Array(buffer8.byteLength + data.byteLength); + new_buffer.set(buffer8); + new_buffer.set(data, buffer8.byteLength); + buffer8 = new_buffer; + nread += data.byteLength; + if (data.byteLength !== iovec.buf_len) { + break; + } + } + return [[nread, buffer8], wasi.ERRNO_SUCCESS]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_prestat_get(fd: number): [wasi.Prestat | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, prestat } = this.fds[fd].fd_prestat_get(); + if (prestat != null) { + return [prestat, ret]; + } + return [undefined, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_prestat_dir_name( + fd: number, + path_len: number, + ): [Uint8Array | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, prestat } = this.fds[fd].fd_prestat_get(); + if (prestat) { + const prestat_dir_name = prestat.inner.pr_name; + + // console.log("fd_prestat_dir_name: park: inner: ", prestat_dir_name); + // console.log("fd_prestat_dir_name: park: inner: ", new TextDecoder().decode(prestat_dir_name)); + + // console.log("fd_prestat_dir_name: park: path_len: ", path_len); + + if (prestat_dir_name.length <= path_len) { + // console.log("fd_prestat_dir_name: park: A"); + return [prestat_dir_name, ret]; + } + + // console.log("fd_prestat_dir_name: park: B"); + return [prestat_dir_name.slice(0, path_len), wasi.ERRNO_NAMETOOLONG]; + } + // console.log("fd_prestat_dir_name: park: C"); + return [undefined, ret]; + } + // console.log("fd_prestat_dir_name: park: D"); + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_pwrite( + fd: number, + write_data: Uint8Array, + offset: bigint, + ): [number | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, nwritten } = this.fds[fd].fd_pwrite(write_data, offset); + return [nwritten, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_read( + fd: number, + iovecs: Array, + ): [[number, Uint8Array] | undefined, number] { + if (this.fds[fd] !== undefined) { + let nread = 0; + + // console.log("fd_read: park: iovecs: ", iovecs); + + // const sum_len = iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0); + + // console.warn("fd_read: park: sum_len: ", sum_len); + + let buffer8 = new Uint8Array(0); + for (const iovec of iovecs) { + const { ret, data } = this.fds[fd].fd_read(iovec.buf_len); + // console.log("fd_read: park: data: ", data); + if (ret !== wasi.ERRNO_SUCCESS) { + return [[nread, buffer8], ret]; + } + const new_buffer = new Uint8Array(buffer8.byteLength + data.byteLength); + new_buffer.set(buffer8); + new_buffer.set(data, buffer8.byteLength); + buffer8 = new_buffer; + nread += data.byteLength; + if (data.byteLength !== iovec.buf_len) { + break; + } + } + + // console.log("fd_read: park: nread: ", nread); + + return [[nread, buffer8], wasi.ERRNO_SUCCESS]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_readdir( + fd: number, + buf_len: number, + cookie: bigint, + ): [[Uint8Array, number] | undefined, number] { + if (this.fds[fd] !== undefined) { + const array = new Uint8Array(buf_len); + + let buf_used = 0; + let offset = 0; + + // eslint-disable-next-line no-constant-condition + while (true) { + const { ret, dirent } = this.fds[fd].fd_readdir_single(cookie); + if (ret !== wasi.ERRNO_SUCCESS) { + return [[array, buf_used], ret]; + } + if (dirent == null) { + break; + } + if (buf_len - buf_used < dirent.head_length()) { + buf_used = buf_len; + break; + } + + const head_bytes = new ArrayBuffer(dirent.head_length()); + dirent.write_head_bytes(new DataView(head_bytes), 0); + array.set( + new Uint8Array(head_bytes).slice( + 0, + Math.min(head_bytes.byteLength, buf_len - buf_used), + ), + offset, + ); + offset += head_bytes.byteLength; + buf_used += head_bytes.byteLength; + + if (buf_len - buf_used < dirent.name_length()) { + buf_used = buf_len; + break; + } + + dirent.write_name_bytes(array, offset, buf_len - buf_used); + offset += dirent.name_length(); + buf_used += dirent.name_length(); + + cookie = dirent.d_next; + } + + return [[array, buf_used], wasi.ERRNO_SUCCESS]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + // protected async fd_renumber(fd: number, to: number): Promise { + // if (this.fds[fd] != undefined) { + // const ret = this.fds[to].fd_close(); + // if (ret != wasi.ERRNO_SUCCESS) { + // return ret; + // } + // this.fds[to] = this.fds[fd]; + // this.fds[fd] = undefined; + // await this.notify_rm_fd(fd); + // return wasi.ERRNO_SUCCESS; + // } else { + // return wasi.ERRNO_BADF; + // } + // } + + protected fd_seek( + fd: number, + offset: bigint, + whence: number, + ): [bigint | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, offset: new_offset } = this.fds[fd].fd_seek(offset, whence); + return [new_offset, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_sync(fd: number): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].fd_sync(); + } + return wasi.ERRNO_BADF; + } + + protected fd_tell(fd: number): [bigint | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, offset } = this.fds[fd].fd_tell(); + return [offset, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected fd_write( + fd: number, + write_data: Uint8Array, + ): [number | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, nwritten } = this.fds[fd].fd_write(write_data); + return [nwritten, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected path_create_directory(fd: number, path: string): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].path_create_directory(path); + } + return wasi.ERRNO_BADF; + } + + protected path_filestat_get( + fd: number, + flags: number, + path: string, + ): [wasi.Filestat | undefined, number] { + if (this.fds[fd] !== undefined) { + const { ret, filestat } = this.fds[fd].path_filestat_get(flags, path); + if (filestat != null) { + return [filestat, ret]; + } + return [undefined, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected path_filestat_set_times( + fd: number, + flags: number, + path: string, + atim: bigint, + mtim: bigint, + fst_flags: number, + ): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].path_filestat_set_times( + flags, + path, + atim, + mtim, + fst_flags, + ); + } + return wasi.ERRNO_BADF; + } + + protected path_link( + old_fd: number, + old_flags: number, + old_path: string, + new_fd: number, + new_path: string, + ): number { + if (this.fds[old_fd] !== undefined && this.fds[new_fd] !== undefined) { + const { ret, inode_obj } = this.fds[old_fd].path_lookup( + old_path, + old_flags, + ); + if (inode_obj == null) { + return ret; + } + return this.fds[new_fd].path_link(new_path, inode_obj, false); + } + return wasi.ERRNO_BADF; + } + + protected async path_open( + fd: number, + dirflags: number, + path: string, + oflags: number, + fs_rights_base: bigint, + fs_rights_inheriting: bigint, + fs_flags: number, + ): Promise<[number | undefined, number]> { + if (this.fds[fd] !== undefined) { + debug.log("path_open", path); + const { ret, fd_obj } = this.fds[fd].path_open( + dirflags, + path, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + ); + // console.log("path_open: park: ", ret, fd_obj); + if (ret !== wasi.ERRNO_SUCCESS) { + return [undefined, ret]; + } + + const [resolve, opened_fd] = await this.get_new_fd(); + + // console.log("path_open: park: ", path, "opened_fd" ,opened_fd); + + this.fds[opened_fd] = fd_obj; + + await resolve(); + + // console.log("path_open: park: len: ", len); + + // console.log("path_open: park: ", opened_fd); + + return [opened_fd, wasi.ERRNO_SUCCESS]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected path_readlink( + fd: number, + path: string, + buf_len: number, + ): [Uint8Array | undefined, number] { + if (this.fds[fd] !== undefined) { + debug.log("path_readlink", path); + const { ret, data } = this.fds[fd].path_readlink(path); + if (data != null) { + const data_buf = new TextEncoder().encode(data); + if (data_buf.byteLength > buf_len) { + // wasi.ts use ERRNO_BADF. I think it should be ERRNO_OVERFLOW. + return [data_buf.slice(0, buf_len), wasi.ERRNO_OVERFLOW]; + } + return [data_buf, ret]; + } + return [undefined, ret]; + } + return [undefined, wasi.ERRNO_BADF]; + } + + protected path_remove_directory(fd: number, path: string): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].path_remove_directory(path); + } + return wasi.ERRNO_BADF; + } + + protected path_rename( + old_fd: number, + old_path: string, + new_fd: number, + new_path: string, + ): number { + if (this.fds[old_fd] !== undefined && this.fds[new_fd] !== undefined) { + // eslint-disable-next-line prefer-const + let { ret, inode_obj } = this.fds[old_fd].path_unlink(old_path); + if (inode_obj == null) { + return ret; + } + ret = this.fds[new_fd].path_link(new_path, inode_obj, true); + if (ret !== wasi.ERRNO_SUCCESS) { + if ( + this.fds[old_fd].path_link(old_path, inode_obj, true) !== + wasi.ERRNO_SUCCESS + ) { + throw "path_link should always return success when relinking an inode back to the original place"; + } + } + return ret; + } + return wasi.ERRNO_BADF; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected path_symlink( + old_path: string, + fd: number, + new_path: string, + ): number { + if (this.fds[fd] !== undefined) { + return wasi.ERRNO_NOTSUP; + } + return wasi.ERRNO_BADF; + } + + protected path_unlink_file(fd: number, path: string): number { + if (this.fds[fd] !== undefined) { + return this.fds[fd].path_unlink_file(path); + } + return wasi.ERRNO_BADF; + } } diff --git a/src/wasi_farm/polyfill.js b/src/wasi_farm/polyfill.js index 815f803..bde01dd 100644 --- a/src/wasi_farm/polyfill.js +++ b/src/wasi_farm/polyfill.js @@ -34,9 +34,9 @@ */ (() => { - if (typeof Atomics.waitAsync === "function") return; + if (typeof Atomics.waitAsync === "function") return; - const helperCode = ` + const helperCode = ` onmessage = function (ev) { try { switch (ev.data[0]) { @@ -57,91 +57,91 @@ } `; - const helpers = []; - - function allocHelper() { - if (helpers.length > 0) return helpers.pop(); - const h = new Worker( - `data:application/javascript,${encodeURIComponent(helperCode)}`, - ); - return h; - } - - function freeHelper(h) { - helpers.push(h); - } - - // Atomics.waitAsync always returns a promise. Throws standard errors - // for parameter validation. The promise is resolved with a string as from - // Atomics.wait, or, in the case something went completely wrong, it is - // rejected with an error string. - - function waitAsync(ia, index_, value_, timeout_) { - if ( - typeof ia !== "object" || - !(ia instanceof Int32Array) || - !(ia.buffer instanceof SharedArrayBuffer) - ) - throw new TypeError("Expected shared memory"); - - // These conversions only approximate the desired semantics but are - // close enough for the polyfill. - - const index = index_ | 0; - const value = value_ | 0; - const timeout = - timeout_ === undefined ? Number.POSITIVE_INFINITY : +timeout_; - - // Range checking for the index. - - ia[index]; - - // Optimization, avoid the helper thread in this common case. - - if (Atomics.load(ia, index) !== value) return Promise.resolve("not-equal"); - - // General case, we must wait. - - return new Promise((resolve, reject) => { - const h = allocHelper(); - h.onmessage = (ev) => { - // Free the helper early so that it can be reused if the resolution - // needs a helper. - freeHelper(h); - switch (ev.data[0]) { - case "ok": - resolve(ev.data[1]); - break; - case "error": - // Note, rejection is not in the spec, it is an artifact of the polyfill. - // The helper already printed an error to the console. - reject(ev.data[1]); - break; - } - }; - - // It's possible to do better here if the ia is already known to the - // helper. In that case we can communicate the other data through - // shared memory and wake the agent. And it is possible to make ia - // known to the helper by waking it with a special value so that it - // checks its messages, and then posting the ia to the helper. Some - // caching / decay scheme is useful no doubt, to improve performance - // and avoid leaks. - // - // In the event we wake the helper directly, we can micro-wait here - // for a quick result. We'll need to restructure some code to make - // that work out properly, and some synchronization is necessary for - // the helper to know that we've picked up the result and no - // postMessage is necessary. - - h.postMessage(["wait", ia, index, value, timeout]); - }); - } - - Object.defineProperty(Atomics, "waitAsync", { - value: waitAsync, - configurable: true, - enumerable: false, - writable: true, - }); + const helpers = []; + + function allocHelper() { + if (helpers.length > 0) return helpers.pop(); + const h = new Worker( + `data:application/javascript,${encodeURIComponent(helperCode)}`, + ); + return h; + } + + function freeHelper(h) { + helpers.push(h); + } + + // Atomics.waitAsync always returns a promise. Throws standard errors + // for parameter validation. The promise is resolved with a string as from + // Atomics.wait, or, in the case something went completely wrong, it is + // rejected with an error string. + + function waitAsync(ia, index_, value_, timeout_) { + if ( + typeof ia !== "object" || + !(ia instanceof Int32Array) || + !(ia.buffer instanceof SharedArrayBuffer) + ) + throw new TypeError("Expected shared memory"); + + // These conversions only approximate the desired semantics but are + // close enough for the polyfill. + + const index = index_ | 0; + const value = value_ | 0; + const timeout = + timeout_ === undefined ? Number.POSITIVE_INFINITY : +timeout_; + + // Range checking for the index. + + ia[index]; + + // Optimization, avoid the helper thread in this common case. + + if (Atomics.load(ia, index) !== value) return Promise.resolve("not-equal"); + + // General case, we must wait. + + return new Promise((resolve, reject) => { + const h = allocHelper(); + h.onmessage = (ev) => { + // Free the helper early so that it can be reused if the resolution + // needs a helper. + freeHelper(h); + switch (ev.data[0]) { + case "ok": + resolve(ev.data[1]); + break; + case "error": + // Note, rejection is not in the spec, it is an artifact of the polyfill. + // The helper already printed an error to the console. + reject(ev.data[1]); + break; + } + }; + + // It's possible to do better here if the ia is already known to the + // helper. In that case we can communicate the other data through + // shared memory and wake the agent. And it is possible to make ia + // known to the helper by waking it with a special value so that it + // checks its messages, and then posting the ia to the helper. Some + // caching / decay scheme is useful no doubt, to improve performance + // and avoid leaks. + // + // In the event we wake the helper directly, we can micro-wait here + // for a quick result. We'll need to restructure some code to make + // that work out properly, and some synchronization is necessary for + // the helper to know that we've picked up the result and no + // postMessage is necessary. + + h.postMessage(["wait", ia, index, value, timeout]); + }); + } + + Object.defineProperty(Atomics, "waitAsync", { + value: waitAsync, + configurable: true, + enumerable: false, + writable: true, + }); })(); diff --git a/src/wasi_farm/sender.ts b/src/wasi_farm/sender.ts index 2b75ee4..ed9d30a 100644 --- a/src/wasi_farm/sender.ts +++ b/src/wasi_farm/sender.ts @@ -1,4 +1,4 @@ export interface FdCloseSender { - send(targets: Array, fd: number): Promise; - get(id: number): Array | undefined; + send(targets: Array, fd: number): Promise; + get(id: number): Array | undefined; } diff --git a/src/wasi_farm/shared_array_buffer/allocator.ts b/src/wasi_farm/shared_array_buffer/allocator.ts index f8b3dba..77f4bde 100644 --- a/src/wasi_farm/shared_array_buffer/allocator.ts +++ b/src/wasi_farm/shared_array_buffer/allocator.ts @@ -3,213 +3,213 @@ // import "../polyfill.js"; export type AllocatorUseArrayBufferObject = { - share_arrays_memory: SharedArrayBuffer; + share_arrays_memory: SharedArrayBuffer; }; export class AllocatorUseArrayBuffer { - // Pass a !Sized type - // The first 4 bytes are for a lock value: i32 - // The next 4 bytes are for the current number of arrays: m: i32 - // The next 4 bytes are for the length of the occupied space in share_arrays_memory: n: i32 - // Once it is no longer busy, it should become empty immediately, so reset only when it is empty. - // Even if it becomes too long, it should be fine due to the browser's virtualization. - // Using an algorithm even simpler than First-Fit - // SharedArrayBuffer.grow is supported by all major browsers except Android WebView, - // which does not support SharedArrayBuffer in the first place, - // but es2024 and the type system does not support it, - // so the size is fixed from the beginning - - // share_arrays_memory: SharedArrayBuffer = new SharedArrayBuffer(12, { - // // 10MB - // maxByteLength: 10 * 1024 * 1024, - // }); - - // Even if 100MB is allocated, due to browser virtualization, - // the memory should not actually be used until it is needed. - share_arrays_memory: SharedArrayBuffer; - - // When adding data, use Atomics.wait to wait until the first 4 bytes become 0. - // After that, use Atomics.compareExchange to set the first 4 bytes to 1. - // Then, use Atomics.add to increment the next 4 bytes by 1. - // If the return value is 0, proceed to *1. - // If the return value is 1, use Atomics.wait to wait until the first 4 bytes become 0. - // *1: Increment the second by 1 using Atomics.add. If the return value is 0, reset it. - // Add the data. Extend if there is not enough space. - // To release, just decrement by 1 using Atomics.sub. - - // Since postMessage makes the class an object, - // it must be able to receive and assign a SharedArrayBuffer. - constructor( - share_arrays_memory: SharedArrayBuffer = new SharedArrayBuffer( - 10 * 1024 * 1024, - ), - ) { - this.share_arrays_memory = share_arrays_memory; - const view = new Int32Array(this.share_arrays_memory); - Atomics.store(view, 0, 0); - Atomics.store(view, 1, 0); - Atomics.store(view, 2, 12); - } - - // Since postMessage converts classes to objects, - // it must be able to convert objects to classes. - static init_self(sl: AllocatorUseArrayBufferObject): AllocatorUseArrayBuffer { - return new AllocatorUseArrayBuffer(sl.share_arrays_memory); - } - - // Writes without blocking threads when acquiring locks - async async_write( - data: Uint8Array | Uint32Array, - memory: SharedArrayBuffer, - // ptr, len - // Pass I32Array ret_ptr - ret_ptr: number, - ): Promise { - const view = new Int32Array(this.share_arrays_memory); - // eslint-disable-next-line no-constant-condition - while (true) { - let lock: "not-equal" | "timed-out" | "ok"; - const { value } = Atomics.waitAsync(view, 0, 1); - if (value instanceof Promise) { - lock = await value; - } else { - lock = value; - } - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old !== 0) { - continue; - } - - this.write_inner(data, memory, ret_ptr); - - // release lock - Atomics.store(view, 0, 0); - Atomics.notify(view, 0, 1); - - break; - } - } - - // Blocking threads for writing when acquiring locks - block_write( - data: Uint8Array | Uint32Array, - memory: SharedArrayBuffer, - // ptr, len - ret_ptr: number, - ): [number, number] { - // eslint-disable-next-line no-constant-condition - while (true) { - const view = new Int32Array(this.share_arrays_memory); - const lock = Atomics.wait(view, 0, 1); - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old !== 0) { - continue; - } - - const ret = this.write_inner(data, memory, ret_ptr); - - // release lock - Atomics.store(view, 0, 0); - Atomics.notify(view, 0, 1); - - return ret; - } - } - - // Function to write after acquiring a lock - write_inner( - data: Uint8Array | Uint32Array, - memory: SharedArrayBuffer, - // ptr, len - ret_ptr: number, - ): [number, number] { - // console.log("data", data); - - const view = new Int32Array(this.share_arrays_memory); - const view8 = new Uint8Array(this.share_arrays_memory); - - // Indicates more users using memory - const old_num = Atomics.add(view, 1, 1); - let share_arrays_memory_kept: number; - if (old_num === 0) { - // Reset because there were no users. - // debug.log("reset allocator"); - share_arrays_memory_kept = Atomics.store(view, 2, 12); - } else { - share_arrays_memory_kept = Atomics.load(view, 2); - } - // console.log("num", Atomics.load(view, 1)); - - const memory_len = this.share_arrays_memory.byteLength; - const len = data.byteLength; - const new_memory_len = share_arrays_memory_kept + len; - if (memory_len < new_memory_len) { - // extend memory - // support from es2024 - // this.share_arrays_memory.grow(new_memory_len); - throw new Error( - "size is bigger than memory. \nTODO! fix memory limit. support big size another way.", - ); - } - - let data8: Uint8Array; - if (data instanceof Uint8Array) { - data8 = data; - } else if (data instanceof Uint32Array) { - // data to uint8 - const tmp = new ArrayBuffer(data.byteLength); - new Uint32Array(tmp).set(data); - data8 = new Uint8Array(tmp); - } - - view8.set(new Uint8Array(data8), share_arrays_memory_kept); - Atomics.store(view, 2, new_memory_len); - - const memory_view = new Int32Array(memory); - Atomics.store(memory_view, ret_ptr, share_arrays_memory_kept); - Atomics.store(memory_view, ret_ptr + 1, len); - - // console.log("allocator: allocate", share_arrays_memory_kept, len); - - return [share_arrays_memory_kept, len]; - } - - // free allocated memory - free( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - pointer: number, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - len: number, - ) { - Atomics.sub(new Int32Array(this.share_arrays_memory), 1, 1); - - // console.log("allocator: free", pointer, len); - } - - // get memory from pointer and length - get_memory(ptr: number, len: number): ArrayBuffer { - const data = new ArrayBuffer(len); - const view = new Uint8Array(data); - view.set(new Uint8Array(this.share_arrays_memory).slice(ptr, ptr + len)); - return data; - } - - // Write again to the memory before releasing - // Not used because the situation for using it does not exist. - use_defined_memory(ptr: number, len: number, data: ArrayBufferLike) { - const memory = new Uint8Array(this.share_arrays_memory); - memory.set(new Uint8Array(data).slice(0, len), ptr); - } - - get_object(): AllocatorUseArrayBufferObject { - return { - share_arrays_memory: this.share_arrays_memory, - }; - } + // Pass a !Sized type + // The first 4 bytes are for a lock value: i32 + // The next 4 bytes are for the current number of arrays: m: i32 + // The next 4 bytes are for the length of the occupied space in share_arrays_memory: n: i32 + // Once it is no longer busy, it should become empty immediately, so reset only when it is empty. + // Even if it becomes too long, it should be fine due to the browser's virtualization. + // Using an algorithm even simpler than First-Fit + // SharedArrayBuffer.grow is supported by all major browsers except Android WebView, + // which does not support SharedArrayBuffer in the first place, + // but es2024 and the type system does not support it, + // so the size is fixed from the beginning + + // share_arrays_memory: SharedArrayBuffer = new SharedArrayBuffer(12, { + // // 10MB + // maxByteLength: 10 * 1024 * 1024, + // }); + + // Even if 100MB is allocated, due to browser virtualization, + // the memory should not actually be used until it is needed. + share_arrays_memory: SharedArrayBuffer; + + // When adding data, use Atomics.wait to wait until the first 4 bytes become 0. + // After that, use Atomics.compareExchange to set the first 4 bytes to 1. + // Then, use Atomics.add to increment the next 4 bytes by 1. + // If the return value is 0, proceed to *1. + // If the return value is 1, use Atomics.wait to wait until the first 4 bytes become 0. + // *1: Increment the second by 1 using Atomics.add. If the return value is 0, reset it. + // Add the data. Extend if there is not enough space. + // To release, just decrement by 1 using Atomics.sub. + + // Since postMessage makes the class an object, + // it must be able to receive and assign a SharedArrayBuffer. + constructor( + share_arrays_memory: SharedArrayBuffer = new SharedArrayBuffer( + 10 * 1024 * 1024, + ), + ) { + this.share_arrays_memory = share_arrays_memory; + const view = new Int32Array(this.share_arrays_memory); + Atomics.store(view, 0, 0); + Atomics.store(view, 1, 0); + Atomics.store(view, 2, 12); + } + + // Since postMessage converts classes to objects, + // it must be able to convert objects to classes. + static init_self(sl: AllocatorUseArrayBufferObject): AllocatorUseArrayBuffer { + return new AllocatorUseArrayBuffer(sl.share_arrays_memory); + } + + // Writes without blocking threads when acquiring locks + async async_write( + data: Uint8Array | Uint32Array, + memory: SharedArrayBuffer, + // ptr, len + // Pass I32Array ret_ptr + ret_ptr: number, + ): Promise { + const view = new Int32Array(this.share_arrays_memory); + // eslint-disable-next-line no-constant-condition + while (true) { + let lock: "not-equal" | "timed-out" | "ok"; + const { value } = Atomics.waitAsync(view, 0, 1); + if (value instanceof Promise) { + lock = await value; + } else { + lock = value; + } + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old !== 0) { + continue; + } + + this.write_inner(data, memory, ret_ptr); + + // release lock + Atomics.store(view, 0, 0); + Atomics.notify(view, 0, 1); + + break; + } + } + + // Blocking threads for writing when acquiring locks + block_write( + data: Uint8Array | Uint32Array, + memory: SharedArrayBuffer, + // ptr, len + ret_ptr: number, + ): [number, number] { + // eslint-disable-next-line no-constant-condition + while (true) { + const view = new Int32Array(this.share_arrays_memory); + const lock = Atomics.wait(view, 0, 1); + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old !== 0) { + continue; + } + + const ret = this.write_inner(data, memory, ret_ptr); + + // release lock + Atomics.store(view, 0, 0); + Atomics.notify(view, 0, 1); + + return ret; + } + } + + // Function to write after acquiring a lock + write_inner( + data: Uint8Array | Uint32Array, + memory: SharedArrayBuffer, + // ptr, len + ret_ptr: number, + ): [number, number] { + // console.log("data", data); + + const view = new Int32Array(this.share_arrays_memory); + const view8 = new Uint8Array(this.share_arrays_memory); + + // Indicates more users using memory + const old_num = Atomics.add(view, 1, 1); + let share_arrays_memory_kept: number; + if (old_num === 0) { + // Reset because there were no users. + // debug.log("reset allocator"); + share_arrays_memory_kept = Atomics.store(view, 2, 12); + } else { + share_arrays_memory_kept = Atomics.load(view, 2); + } + // console.log("num", Atomics.load(view, 1)); + + const memory_len = this.share_arrays_memory.byteLength; + const len = data.byteLength; + const new_memory_len = share_arrays_memory_kept + len; + if (memory_len < new_memory_len) { + // extend memory + // support from es2024 + // this.share_arrays_memory.grow(new_memory_len); + throw new Error( + "size is bigger than memory. \nTODO! fix memory limit. support big size another way.", + ); + } + + let data8: Uint8Array; + if (data instanceof Uint8Array) { + data8 = data; + } else if (data instanceof Uint32Array) { + // data to uint8 + const tmp = new ArrayBuffer(data.byteLength); + new Uint32Array(tmp).set(data); + data8 = new Uint8Array(tmp); + } + + view8.set(new Uint8Array(data8), share_arrays_memory_kept); + Atomics.store(view, 2, new_memory_len); + + const memory_view = new Int32Array(memory); + Atomics.store(memory_view, ret_ptr, share_arrays_memory_kept); + Atomics.store(memory_view, ret_ptr + 1, len); + + // console.log("allocator: allocate", share_arrays_memory_kept, len); + + return [share_arrays_memory_kept, len]; + } + + // free allocated memory + free( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + pointer: number, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + len: number, + ) { + Atomics.sub(new Int32Array(this.share_arrays_memory), 1, 1); + + // console.log("allocator: free", pointer, len); + } + + // get memory from pointer and length + get_memory(ptr: number, len: number): ArrayBuffer { + const data = new ArrayBuffer(len); + const view = new Uint8Array(data); + view.set(new Uint8Array(this.share_arrays_memory).slice(ptr, ptr + len)); + return data; + } + + // Write again to the memory before releasing + // Not used because the situation for using it does not exist. + use_defined_memory(ptr: number, len: number, data: ArrayBufferLike) { + const memory = new Uint8Array(this.share_arrays_memory); + memory.set(new Uint8Array(data).slice(0, len), ptr); + } + + get_object(): AllocatorUseArrayBufferObject { + return { + share_arrays_memory: this.share_arrays_memory, + }; + } } diff --git a/src/wasi_farm/shared_array_buffer/fd_close_sender.ts b/src/wasi_farm/shared_array_buffer/fd_close_sender.ts index a191a81..a137e77 100644 --- a/src/wasi_farm/shared_array_buffer/fd_close_sender.ts +++ b/src/wasi_farm/shared_array_buffer/fd_close_sender.ts @@ -1,62 +1,62 @@ import type { FdCloseSender } from "../sender.js"; import { - ToRefSenderUseArrayBuffer, - type ToRefSenderUseArrayBufferObject, + ToRefSenderUseArrayBuffer, + type ToRefSenderUseArrayBufferObject, } from "./sender.js"; export type FdCloseSenderUseArrayBufferObject = { - max_share_arrays_memory?: number; - share_arrays_memory?: SharedArrayBuffer; + max_share_arrays_memory?: number; + share_arrays_memory?: SharedArrayBuffer; } & ToRefSenderUseArrayBufferObject; // Object to tell other processes, // such as child processes, // that the file descriptor has been closed export class FdCloseSenderUseArrayBuffer - extends ToRefSenderUseArrayBuffer - implements FdCloseSender + extends ToRefSenderUseArrayBuffer + implements FdCloseSender { - // Should be able to change the size of memory as it accumulates more and more on memory - constructor( - max_share_arrays_memory?: number, - share_arrays_memory?: SharedArrayBuffer, - ) { - super(4, max_share_arrays_memory, share_arrays_memory); - } - - // Send the closed file descriptor to the target process - async send(targets: Array, fd: number): Promise { - if (targets === undefined || targets.length === 0) { - throw new Error("targets is empty"); - } - // console.log("fd_close_sender send", targets, fd); - - await this.async_send(targets, new Uint32Array([fd])); - } - - // Get the closed file descriptor from the target process - get(id: number): Array | undefined { - const data = this.get_data(id); - if (data === undefined) { - return undefined; - } - - // console.log("fd_close_sender get", data); - - const array = []; - for (const i of data) { - array.push(i[0]); - } - - return array; - } - - // Initialize the class from object - static init_self(sl: FdCloseSenderUseArrayBufferObject): FdCloseSender { - const sel = ToRefSenderUseArrayBuffer.init_self_inner(sl); - return new FdCloseSenderUseArrayBuffer( - sel.max_share_arrays_memory, - sel.share_arrays_memory, - ); - } + // Should be able to change the size of memory as it accumulates more and more on memory + constructor( + max_share_arrays_memory?: number, + share_arrays_memory?: SharedArrayBuffer, + ) { + super(4, max_share_arrays_memory, share_arrays_memory); + } + + // Send the closed file descriptor to the target process + async send(targets: Array, fd: number): Promise { + if (targets === undefined || targets.length === 0) { + throw new Error("targets is empty"); + } + // console.log("fd_close_sender send", targets, fd); + + await this.async_send(targets, new Uint32Array([fd])); + } + + // Get the closed file descriptor from the target process + get(id: number): Array | undefined { + const data = this.get_data(id); + if (data === undefined) { + return undefined; + } + + // console.log("fd_close_sender get", data); + + const array = []; + for (const i of data) { + array.push(i[0]); + } + + return array; + } + + // Initialize the class from object + static init_self(sl: FdCloseSenderUseArrayBufferObject): FdCloseSender { + const sel = ToRefSenderUseArrayBuffer.init_self_inner(sl); + return new FdCloseSenderUseArrayBuffer( + sel.max_share_arrays_memory, + sel.share_arrays_memory, + ); + } } diff --git a/src/wasi_farm/shared_array_buffer/index.ts b/src/wasi_farm/shared_array_buffer/index.ts index 3b27bc3..0e2d34a 100644 --- a/src/wasi_farm/shared_array_buffer/index.ts +++ b/src/wasi_farm/shared_array_buffer/index.ts @@ -5,9 +5,9 @@ import { ThreadSpawner } from "./thread_spawn.js"; import { thread_spawn_on_worker } from "./thread_spawn.js"; export { - WASIFarmRefUseArrayBuffer, - type WASIFarmRefUseArrayBufferObject, - WASIFarmParkUseArrayBuffer, - ThreadSpawner, - thread_spawn_on_worker, + WASIFarmRefUseArrayBuffer, + type WASIFarmRefUseArrayBufferObject, + WASIFarmParkUseArrayBuffer, + ThreadSpawner, + thread_spawn_on_worker, }; diff --git a/src/wasi_farm/shared_array_buffer/park.ts b/src/wasi_farm/shared_array_buffer/park.ts index 9726411..861b807 100644 --- a/src/wasi_farm/shared_array_buffer/park.ts +++ b/src/wasi_farm/shared_array_buffer/park.ts @@ -11,983 +11,983 @@ export const fd_func_sig_u32_size: number = 18; export const fd_func_sig_bytes: number = fd_func_sig_u32_size * 4; export class WASIFarmParkUseArrayBuffer extends WASIFarmPark { - private allocator: AllocatorUseArrayBuffer; - - // args and env do not change, so copying them is fine. - // Functions that do not depend on fds are skipped. - // Since it is wasm32, the pointer is u32. - // errno is u8. - // https://github.com/WebAssembly/WASI/blob/4feaf733e946c375b610cc5d39ea2e1a68046e62/legacy/preview1/docs.md - // The first item is the function signature, and the second (if it exists) represents data that must be communicated in Park. If they are the same, it is not written. - // From here, direct access to fd begins. - // fd_advise: (fd: u32, offset: u64, len: u64, advice: u8) => errno; - // (fd: u32) => errno; - // fd_allocate: (fd: u32, offset: u64, len: u64) => errno; - // fd_close: (fd: u32) => errno; - // fd_datasync: (fd: u32) => errno; - // fd_fdstat_get: (fd: u32, fdstat_ptr: pointer) => errno; - // (fd: u32) => [wasi.Fdstat(u32 * 6)], errno]; - // fd_fdstat_set_flags: (fd: u32, flags: u16) => errno; - // fd_fdstat_set_rights: (fd: u32, fs_rights_base: u64, fs_rights_inheriting: u64) => errno; - // fd_filestat_get: (fd: u32, filestat_ptr: pointer) => errno; - // (fd: u32) => [wasi.Filestat(u32 * 16)], errno]; - // fd_filestat_set_size: (fd: u32, size: u64) => errno; - // fd_filestat_set_times: (fd: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; - // fd_pread: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, errno]; - // use share_arrays_memory; - // (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, data_ptr, errno]; - // fd_prestat_get: (fd: u32, prestat_ptr: pointer) => errno; - // (fd: u32) => [wasi.Prestat(u32 * 2)], errno]; - // fd_prestat_dir_name: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - // (fd: u32, path_len: u32) => [path_ptr: pointer, path_len: u32, errno]; - // fd_pwrite: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, errno]; - // use share_arrays_memory; - // (fd: u32, write_data: pointer, write_data_len: u32, offset: u64) => [u32, errno]; - // fd_read: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, errno]; - // use share_arrays_memory; - // (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, data_ptr, errno]; - // fd_readdir: (fd: u32, buf_ptr: pointer, buf_len: u32, cookie: u64) => [u32, errno]; - // use share_arrays_memory; - // (fd: u32, buf_len: u32, cookie: u64) => [buf_ptr: pointer, buf_len: u32, buf_used: u32, errno]; - // fd_renumber: (fd: u32, to: u32) => errno; - // fd_seek: (fd: u32, offset: i64, whence: u8) => [u64, errno]; - // fd_sync: (fd: u32) => errno; - // fd_tell: (fd: u32) => [u64, errno]; - // fd_write: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, errno]; - // use share_arrays_memory; - // (fd: u32, write_data: pointer, write_data_len: u32) => [u32, errno]; - // path_create_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - // path_filestat_get: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32) => [wasi.Filestat(u32 * 16), errno]; - // path_filestat_set_times: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; - // path_link: (old_fd: u32, old_flags: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; - // path_open: (fd: u32, dirflags: u32, path_ptr: pointer, path_len: u32, oflags: u32, fs_rights_base: u64, fs_rights_inheriting: u64, fdflags: u16) => [u32, errno]; - // note: fdsにpushするが、既存のfdに影響しないので、競合しない。 - // path_readlink: (fd: u32, path_ptr: pointer, path_len: u32, buf_ptr: pointer, buf_len: u32) => [u32, errno]; - // use share_arrays_memory; - // (fd: u32, path_ptr: pointer, path_len: u32, buf_len: u32) => [buf_len: u32, data_ptr: pointer, data_len: u32, errno]; - // path_remove_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - // path_rename: (old_fd: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; - // path_symlink: (old_path_ptr: pointer, old_path_len: u32, fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; - // path_unlink_file: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - - // Lock when you want to use fd - // Array<[lock, call_func]> - private lock_fds: SharedArrayBuffer; - - // 1 bytes: fds.length - // 1 bytes: wasi_farm_ref num(id) - // Actually, as long as it is working properly, fds.length is not used - private fds_len_and_num: SharedArrayBuffer; - - // listen promise keep - private listen_fds: Array> = []; - - // The largest size is u32 * 18 + 1 - // Alignment is troublesome, so make it u32 * 18 + 4 - // In other words, one size is 76 bytes - private fd_func_sig: SharedArrayBuffer; - - // listen base handle keep - private listen_base_handle: Promise; - - // listen base lock and call etc - private base_func_util: SharedArrayBuffer; - - // tell other processes that the file descriptor has been closed - private fd_close_receiver: FdCloseSender; - - // this is not send by postMessage, - // so it is not necessary to keep shared_array_buffer - // this class is not used by user, - // to avoid mistakes, all constructors are now required to be passed in. - constructor( - fds: Array, - // stdin fd number - stdin: number | undefined, - // stdout fd number - stdout: number | undefined, - // stderr fd number - stderr: number | undefined, - // wasi_farm_ref default allow fds - default_allow_fds: Array, - allocator_size?: number, - ) { - super(fds, stdin, stdout, stderr, default_allow_fds); - - if (allocator_size === undefined) { - this.allocator = new AllocatorUseArrayBuffer(); - } else { - this.allocator = new AllocatorUseArrayBuffer( - new SharedArrayBuffer(allocator_size), - ); - } - const max_fds_len = 128; - this.lock_fds = new SharedArrayBuffer(4 * max_fds_len * 3); - this.fd_func_sig = new SharedArrayBuffer( - fd_func_sig_u32_size * 4 * max_fds_len, - ); - this.fds_len_and_num = new SharedArrayBuffer(8); - - const view = new Int32Array(this.fds_len_and_num); - Atomics.store(view, 0, fds.length); - Atomics.store(view, 1, 0); - - this.fd_close_receiver = new FdCloseSenderUseArrayBuffer(); - this.base_func_util = new SharedArrayBuffer(24); - } - - /// Send this return by postMessage. - get_ref(): WASIFarmRefUseArrayBufferObject { - return { - allocator: this.allocator, - lock_fds: this.lock_fds, - fds_len_and_num: this.fds_len_and_num, - fd_func_sig: this.fd_func_sig, - base_func_util: this.base_func_util, - fd_close_receiver: this.fd_close_receiver, - stdin: this.stdin, - stdout: this.stdout, - stderr: this.stderr, - default_fds: this.default_allow_fds, - }; - } - - // abstract methods implementation - // from fd set ex) path_open - // received and listen the fd - // and set fds.length - async notify_set_fd(fd: number) { - if (this.fds[fd] === undefined) { - throw new Error("fd is not defined"); - } - if (fd >= 128) { - throw new Error("fd is too big. expand is not supported yet"); - } - if (this.listen_fds[fd] !== undefined) { - if (this.listen_fds[fd] instanceof Promise) { - console.warn("fd is already set yet"); - await this.listen_fds[fd]; - } - } - this.listen_fds[fd] = this.listen_fd(fd); - - const view = new Int32Array(this.fds_len_and_num); - Atomics.store(view, 0, this.fds.length); - // const len = Atomics.store(view, 0, this.fds.length); - // console.log("notify_set_fd: len: ", len); - } - - // abstract methods implementation - // called by fd close ex) fd_close - async notify_rm_fd(fd: number) { - (async () => { - await this.listen_fds[fd]; - this.listen_fds[fd] = undefined; - })(); - - // console.log("notify_rm_fd", fd); - // console.log("fds", this.fds); - // console.log("fds_map", this.fds_map); - - // console.log("notify_rm_fd: fds_map", this.fds_map); - // console.log("notify_rm_fd: fd", fd); - - // console.log("notify_rm_fd: fds_map[fd]", [...this.fds_map[fd]]); - - await this.fd_close_receiver.send(this.fds_map[fd], fd); - - this.fds_map[fd] = []; - } - - // abstract methods implementation - // wait to close old listener - can_set_new_fd(fd: number): [boolean, Promise | undefined] { - if (this.listen_fds[fd] instanceof Promise) { - return [false, this.listen_fds[fd]]; - } - return [true, undefined]; - } - - // listen all fds and base - // Must be called before was_ref_id is instantiated - listen() { - this.listen_fds = []; - for (let n = 0; n < this.fds.length; n++) { - this.listen_fds.push(this.listen_fd(n)); - } - this.listen_base_handle = this.listen_base(); - } - - // listen base - // ex) set_fds_map - // if close fd and send to other process, - // it need targets wasi_farm_ref id - // so, set fds_map - async listen_base() { - const lock_view = new Int32Array(this.base_func_util); - Atomics.store(lock_view, 0, 0); - Atomics.store(lock_view, 1, 0); - - // eslint-disable-next-line no-constant-condition - while (true) { - try { - let lock: "not-equal" | "timed-out" | "ok"; - - const { value } = Atomics.waitAsync(lock_view, 1, 0); - if (value instanceof Promise) { - lock = await value; - } else { - lock = value; - } - if (lock === "timed-out") { - throw new Error("timed-out"); - } - - const func_number = Atomics.load(lock_view, 2); - - switch (func_number) { - // set_fds_map: (fds_ptr: u32, fds_len: u32); - case 0: { - // console.log("set_fds_map"); - const ptr = Atomics.load(lock_view, 3); - const len = Atomics.load(lock_view, 4); - // console.log("set_fds_map", ptr, len); - const data = new Uint32Array(this.allocator.get_memory(ptr, len)); - this.allocator.free(ptr, len); - const wasi_farm_ref_id = Atomics.load(lock_view, 5); - - // console.log("listen_base set_fds_map", data, "from", wasi_farm_ref_id); - - // console.log("listen_base fds_map", this.fds_map); - - for (let i = 0; i < len / 4; i++) { - const fd = data[i]; - if (this.fds_map[fd] === undefined) { - this.fds_map[fd] = []; - console.error("listen_base fd is not defined"); - } - this.fds_map[fd].push(wasi_farm_ref_id); - // console.log("this.fds_map", this.fds_map); - // console.log("this.fds_map[fd]", this.fds_map[fd]); - // console.log("this.fds_map[1]", this.fds_map[1]); - // console.log("fd", fd, "wasi_farm_ref_id", wasi_farm_ref_id); - } - - // console.log("listen_base fds_map", this.fds_map); - - // sleep 1000ms - await new Promise((resolve) => setTimeout(resolve, 1000)); - - break; - } - } - - const old_call_lock = Atomics.exchange(lock_view, 1, 0); - if (old_call_lock !== 1) { - throw new Error("Lock is already set"); - } - const num = Atomics.notify(lock_view, 1, 1); - if (num !== 1) { - if (num === 0) { - console.warn("notify failed, waiter is late"); - continue; - } - throw new Error(`notify failed: ${num}`); - } - } catch (e) { - console.error("error", e); - Atomics.store(lock_view, 1, 0); - Atomics.notify(lock_view, 1, 1); - } - } - } - - // listen fd - async listen_fd(fd_n: number) { - const lock_view = new Int32Array(this.lock_fds, fd_n * 12); - const bytes_offset = fd_n * fd_func_sig_bytes; - const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); - const func_sig_view_i32 = new Int32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Int32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - const errno_offset = fd_func_sig_u32_size - 1; - Atomics.store(lock_view, 0, 0); - Atomics.store(lock_view, 1, 0); - Atomics.store(func_sig_view_i32, errno_offset, -1); - - // eslint-disable-next-line no-constant-condition - while (true) { - try { - let lock: "not-equal" | "timed-out" | "ok"; - - const { value } = Atomics.waitAsync(lock_view, 1, 0); - if (value instanceof Promise) { - // console.log("listen", fd_n, 1); - lock = await value; - } else { - lock = value; - } - if (lock === "timed-out") { - throw new Error("timed-out"); - } - - const func_lock = Atomics.load(lock_view, 1); - - if (func_lock !== 1) { - throw new Error(`func_lock is already set: ${func_lock}`); - } - - // console.log("func_lock", func_lock); - - // console.log("called", fd_n, 1); - - const set_error = (errno: number) => { - // console.log("set_error", errno, "pointer", errno_offset); - Atomics.store(func_sig_view_i32, errno_offset, errno); - }; - - const func_number = Atomics.load(func_sig_view_u32, 0); - - // console.log("called: func: ", get_func_name_from_number(func_number), "fd: ", fd_n); - - switch (func_number) { - // fd_advise: (fd: u32) => errno; - case 7: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const error = this.fd_advise(fd); - - set_error(error); - break; - } - // fd_allocate: (fd: u32, offset: u64, len: u64) => errno; - case 8: { - const fd = Atomics.load(func_sig_view_u32, 1); - const offset = Atomics.load(func_sig_view_u64, 1); - const len = Atomics.load(func_sig_view_u64, 2); - - const error = this.fd_allocate(fd, offset, len); - - set_error(error); - break; - } - // fd_close: (fd: u32) => errno; - case 9: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const error = await this.fd_close(fd); - - // console.log("fd_close", fd, error); - - set_error(error); - break; - } - // fd_datasync: (fd: u32) => errno; - case 10: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const error = this.fd_datasync(fd); - - set_error(error); - break; - } - // fd_fdstat_get: (fd: u32) => [wasi.Fdstat(u32 * 6)], errno]; - case 11: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const [fdstat, ret] = this.fd_fdstat_get(fd); - - if (fdstat) { - Atomics.store(func_sig_view_u8, 0, fdstat.fs_filetype); - Atomics.store(func_sig_view_u16, 2, fdstat.fs_flags); - Atomics.store(func_sig_view_u64, 1, fdstat.fs_rights_base); - Atomics.store(func_sig_view_u64, 2, fdstat.fs_rights_inherited); - } - set_error(ret); - break; - } - // fd_fdstat_set_flags: (fd: u32, flags: u16) => errno; - case 12: { - const fd = Atomics.load(func_sig_view_u32, 1); - const flags = Atomics.load(func_sig_view_u16, 4); - - const error = this.fd_fdstat_set_flags(fd, flags); - - set_error(error); - break; - } - // fd_fdstat_set_rights: (fd: u32, fs_rights_base: u64, fs_rights_inheriting: u64) => errno; - case 13: { - const fd = Atomics.load(func_sig_view_u32, 1); - const fs_rights_base = Atomics.load(func_sig_view_u64, 1); - const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 2); - - const error = this.fd_fdstat_set_rights( - fd, - fs_rights_base, - fs_rights_inheriting, - ); - - set_error(error); - break; - } - // fd_filestat_get: (fd: u32) => [wasi.Filestat(u32 * 16)], errno]; - case 14: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const [filestat, ret] = this.fd_filestat_get(fd); - - if (filestat) { - Atomics.store(func_sig_view_u64, 0, filestat.dev); - Atomics.store(func_sig_view_u64, 1, filestat.ino); - Atomics.store(func_sig_view_u8, 16, filestat.filetype); - Atomics.store(func_sig_view_u64, 3, filestat.nlink); - Atomics.store(func_sig_view_u64, 4, filestat.size); - Atomics.store(func_sig_view_u64, 5, filestat.atim); - Atomics.store(func_sig_view_u64, 6, filestat.mtim); - Atomics.store(func_sig_view_u64, 7, filestat.ctim); - } - - set_error(ret); - break; - } - // fd_filestat_set_size: (fd: u32, size: u64) => errno; - case 15: { - const fd = Atomics.load(func_sig_view_u32, 1); - const size = Atomics.load(func_sig_view_u64, 1); - - const error = this.fd_filestat_set_size(fd, size); - - set_error(error); - break; - } - // fd_filestat_set_times: (fd: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; - case 16: { - const fd = Atomics.load(func_sig_view_u32, 1); - const atim = Atomics.load(func_sig_view_u64, 1); - const mtim = Atomics.load(func_sig_view_u64, 2); - const fst_flags = Atomics.load(func_sig_view_u16, 12); - - const error = this.fd_filestat_set_times(fd, atim, mtim, fst_flags); - - set_error(error); - break; - } - // fd_pread: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, data_ptr, errno]; - case 17: { - const fd = Atomics.load(func_sig_view_u32, 1); - const iovs_ptr = Atomics.load(func_sig_view_u32, 2); - const iovs_ptr_len = Atomics.load(func_sig_view_u32, 3); - const offset = Atomics.load(func_sig_view_u64, 2); - const data = new Uint32Array( - this.allocator.get_memory(iovs_ptr, iovs_ptr_len), - ); - this.allocator.free(iovs_ptr, iovs_ptr_len); - - const iovecs = new Array(); - for (let i = 0; i < iovs_ptr_len; i += 8) { - const iovec = new wasi.Iovec(); - iovec.buf = data[i * 2]; - iovec.buf_len = data[i * 2 + 1]; - iovecs.push(iovec); - } - - const [[nread, buffer8], error] = this.fd_pread(fd, iovecs, offset); - - if (nread !== undefined) { - Atomics.store(func_sig_view_u32, 0, nread); - } - if (buffer8) { - await this.allocator.async_write( - buffer8, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 1, - ); - } - set_error(error); - break; - } - // fd_prestat_get: (fd: u32) => [wasi.Prestat(u32 * 2)], errno]; - case 18: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const [prestat, ret] = this.fd_prestat_get(fd); - - // console.log("fd_prestat_get", prestat, ret); - - if (prestat) { - Atomics.store(func_sig_view_u32, 0, prestat.tag); - Atomics.store( - func_sig_view_u32, - 1, - prestat.inner.pr_name.byteLength, - ); - } - set_error(ret); - break; - } - // fd_prestat_dir_name: (fd: u32, path_len: u32) => [path_ptr: pointer, path_len: u32, errno]; - case 19: { - const fd = Atomics.load(func_sig_view_u32, 1); - const path_len = Atomics.load(func_sig_view_u32, 2); - - const [prestat_dir_name, ret] = this.fd_prestat_dir_name( - fd, - path_len, - ); - - // console.log("fd_prestat_dir_name: park: ", prestat_dir_name); - - if ( - prestat_dir_name && - (ret === wasi.ERRNO_SUCCESS || ret === wasi.ERRNO_NAMETOOLONG) - ) { - await this.allocator.async_write( - prestat_dir_name, - this.fd_func_sig, - fd * fd_func_sig_u32_size, - ); - } - set_error(ret); - break; - } - // fd_pwrite: (fd: u32, write_data: pointer, write_data_len: u32, offset: u64) => [u32, errno]; - case 20: { - const fd = Atomics.load(func_sig_view_u32, 1); - const write_data_ptr = Atomics.load(func_sig_view_u32, 2); - const write_data_len = Atomics.load(func_sig_view_u32, 3); - const offset = Atomics.load(func_sig_view_u64, 2); - - const data = new Uint8Array( - this.allocator.get_memory(write_data_ptr, write_data_len), - ); - this.allocator.free(write_data_ptr, write_data_len); - - const [nwritten, error] = this.fd_pwrite(fd, data, offset); - - if (nwritten !== undefined) { - Atomics.store(func_sig_view_u32, 0, nwritten); - } - set_error(error); - break; - } - // fd_read: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, data_ptr, errno]; - case 21: { - const fd = Atomics.load(func_sig_view_u32, 1); - const iovs_ptr = Atomics.load(func_sig_view_u32, 2); - const iovs_ptr_len = Atomics.load(func_sig_view_u32, 3); - // console.log("fd_read: park: iovs: Uint8Array", this.allocator.get_memory(iovs_ptr, iovs_ptr_len)); - // console.log("ptr_len", iovs_ptr_len); - const iovs = new Uint32Array( - this.allocator.get_memory(iovs_ptr, iovs_ptr_len), - ); - this.allocator.free(iovs_ptr, iovs_ptr_len); - - // console.log("fd_read: park: iovs", iovs); - - const iovecs = new Array(); - for (let i = 0; i < iovs_ptr_len; i += 8) { - const iovec = new wasi.Iovec(); - iovec.buf = iovs[i * 2]; - iovec.buf_len = iovs[i * 2 + 1]; - iovecs.push(iovec); - } - - // console.log("fd_read: park: iovecs", iovecs); - - const [[nread, buffer8], error] = this.fd_read(fd, iovecs); - - // console.log("fd_read: park: buffer8", new TextDecoder().decode(buffer8)); - - if (nread !== undefined) { - Atomics.store(func_sig_view_u32, 0, nread); - } - if (buffer8) { - await this.allocator.async_write( - buffer8, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 1, - ); - } - set_error(error); - break; - } - // fd_readdir: (fd: u32, buf_len: u32, cookie: u64) => [buf_ptr: pointer, buf_len: u32, buf_used: u32, errno]; - case 22: { - const fd = Atomics.load(func_sig_view_u32, 1); - const buf_len = Atomics.load(func_sig_view_u32, 2); - const cookie = Atomics.load(func_sig_view_u64, 2); - - const [[array, buf_used], error] = this.fd_readdir( - fd, - buf_len, - cookie, - ); - - if (array) { - await this.allocator.async_write( - array, - this.fd_func_sig, - fd * fd_func_sig_u32_size, - ); - } - if (buf_used !== undefined) { - Atomics.store(func_sig_view_u32, 2, buf_used); - } - set_error(error); - break; - } - // fd_seek: (fd: u32, offset: i64, whence: u8) => [u64, errno]; - case 24: { - const fd = Atomics.load(func_sig_view_u32, 1); - const offset = Atomics.load(func_sig_view_u64, 1); - const whence = Atomics.load(func_sig_view_u8, 16); - - const [new_offset, error] = this.fd_seek(fd, offset, whence); - - if (new_offset !== undefined) { - Atomics.store(func_sig_view_u64, 0, new_offset); - } - set_error(error); - break; - } - // fd_sync: (fd: u32) => errno; - case 25: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const error = this.fd_sync(fd); - - set_error(error); - break; - } - // fd_tell: (fd: u32) => [u64, errno]; - case 26: { - const fd = Atomics.load(func_sig_view_u32, 1); - - const [offset, error] = this.fd_tell(fd); - - if (offset !== undefined) { - Atomics.store(func_sig_view_u64, 0, offset); - } - set_error(error); - break; - } - // fd_write: (fd: u32, write_data: pointer, write_data_len: u32) => [u32, errno]; - case 27: { - const fd = Atomics.load(func_sig_view_u32, 1); - const write_data_ptr = Atomics.load(func_sig_view_u32, 2); - const write_data_len = Atomics.load(func_sig_view_u32, 3); - - const data = new Uint8Array( - this.allocator.get_memory(write_data_ptr, write_data_len), - ); - this.allocator.free(write_data_ptr, write_data_len); - - // console.log("allocator", this.allocator); - - // console.log("fd_write: park: write_data", new TextDecoder().decode(data)); - - const [nwritten, error] = this.fd_write(fd, data); - - // console.log("fd_write: park: error", error); - - if (nwritten !== undefined) { - Atomics.store(func_sig_view_u32, 0, nwritten); - } - set_error(error); - break; - } - // path_create_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - case 28: { - const fd = Atomics.load(func_sig_view_u32, 1); - const path_ptr = Atomics.load(func_sig_view_u32, 2); - const path_len = Atomics.load(func_sig_view_u32, 3); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - const error = this.path_create_directory(fd, path_str); - - set_error(error); - break; - } - // path_filestat_get: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32) => [wasi.Filestat(u32 * 16), errno]; - case 29: { - const fd = Atomics.load(func_sig_view_u32, 1); - const flags = Atomics.load(func_sig_view_u32, 2); - const path_ptr = Atomics.load(func_sig_view_u32, 3); - const path_len = Atomics.load(func_sig_view_u32, 4); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - const [filestat, ret] = this.path_filestat_get(fd, flags, path_str); - - if (filestat) { - Atomics.store(func_sig_view_u64, 0, filestat.dev); - Atomics.store(func_sig_view_u64, 1, filestat.ino); - Atomics.store(func_sig_view_u8, 16, filestat.filetype); - Atomics.store(func_sig_view_u64, 3, filestat.nlink); - Atomics.store(func_sig_view_u64, 4, filestat.size); - Atomics.store(func_sig_view_u64, 5, filestat.atim); - Atomics.store(func_sig_view_u64, 6, filestat.mtim); - Atomics.store(func_sig_view_u64, 7, filestat.ctim); - } - set_error(ret); - break; - } - // path_filestat_set_times: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; - case 30: { - const fd = Atomics.load(func_sig_view_u32, 1); - const flags = Atomics.load(func_sig_view_u32, 2); - const path_ptr = Atomics.load(func_sig_view_u32, 3); - const path_len = Atomics.load(func_sig_view_u32, 4); - const atim = Atomics.load(func_sig_view_u64, 3); - const mtim = Atomics.load(func_sig_view_u64, 4); - const fst_flags = Atomics.load(func_sig_view_u16, 12); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - const error = this.path_filestat_set_times( - fd, - flags, - path_str, - atim, - mtim, - fst_flags, - ); - - set_error(error); - break; - } - // path_link: (old_fd: u32, old_flags: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; - case 31: { - const old_fd = Atomics.load(func_sig_view_u32, 1); - const old_flags = Atomics.load(func_sig_view_u32, 2); - const old_path_ptr = Atomics.load(func_sig_view_u32, 3); - const old_path_len = Atomics.load(func_sig_view_u32, 4); - const new_fd = Atomics.load(func_sig_view_u32, 5); - const new_path_ptr = Atomics.load(func_sig_view_u32, 6); - const new_path_len = Atomics.load(func_sig_view_u32, 7); - - const old_path = new Uint8Array( - this.allocator.get_memory(old_path_ptr, old_path_len), - ); - const old_path_str = new TextDecoder().decode(old_path); - this.allocator.free(old_path_ptr, old_path_len); - const new_path = new Uint8Array( - this.allocator.get_memory(new_path_ptr, new_path_len), - ); - const new_path_str = new TextDecoder().decode(new_path); - this.allocator.free(new_path_ptr, new_path_len); - - const error = this.path_link( - old_fd, - old_flags, - old_path_str, - new_fd, - new_path_str, - ); - - set_error(error); - break; - } - // path_open: (fd: u32, dirflags: u32, path_ptr: pointer, path_len: u32, oflags: u32, fs_rights_base: u64, fs_rights_inheriting: u64, fdflags: u16) => [u32, errno]; - case 32: { - const fd = Atomics.load(func_sig_view_u32, 1); - const dirflags = Atomics.load(func_sig_view_u32, 2); - const path_ptr = Atomics.load(func_sig_view_u32, 3); - const path_len = Atomics.load(func_sig_view_u32, 4); - const oflags = Atomics.load(func_sig_view_u32, 5); - const fs_rights_base = Atomics.load(func_sig_view_u64, 3); - const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 4); - const fd_flags = Atomics.load(func_sig_view_u16, 20); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - const [opened_fd, error] = await this.path_open( - fd, - dirflags, - path_str, - oflags, - fs_rights_base, - fs_rights_inheriting, - fd_flags, - ); - - // console.log("path_open: opend_fd", opened_fd, error); - - if (opened_fd !== undefined) { - Atomics.store(func_sig_view_u32, 0, opened_fd); - } - set_error(error); - break; - } - // path_readlink: (fd: u32, path_ptr: pointer, path_len: u32, buf_len: u32) => [buf_len: u32, data_ptr: pointer, data_len: u32, errno]; - case 33: { - const fd = Atomics.load(func_sig_view_u32, 1); - const path_ptr = Atomics.load(func_sig_view_u32, 2); - const path_len = Atomics.load(func_sig_view_u32, 3); - const buf_len = Atomics.load(func_sig_view_u32, 4); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - const [buf, error] = this.path_readlink(fd, path_str, buf_len); - - if (buf) { - await this.allocator.async_write( - buf, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 1, - ); - Atomics.store(func_sig_view_u32, 0, buf.byteLength); - } - set_error(error); - break; - } - // path_remove_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - case 34: { - const fd = Atomics.load(func_sig_view_u32, 1); - const path_ptr = Atomics.load(func_sig_view_u32, 2); - const path_len = Atomics.load(func_sig_view_u32, 3); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - const error = this.path_remove_directory(fd, path_str); - - set_error(error); - break; - } - // path_rename: (old_fd: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; - case 35: { - const fd = Atomics.load(func_sig_view_u32, 1); - const old_path_ptr = Atomics.load(func_sig_view_u32, 2); - const old_path_len = Atomics.load(func_sig_view_u32, 3); - const new_fd = Atomics.load(func_sig_view_u32, 4); - const new_path_ptr = Atomics.load(func_sig_view_u32, 5); - const new_path_len = Atomics.load(func_sig_view_u32, 6); - - const old_path = new Uint8Array( - this.allocator.get_memory(old_path_ptr, old_path_len), - ); - const old_path_str = new TextDecoder().decode(old_path); - this.allocator.free(old_path_ptr, old_path_len); - const new_path = new Uint8Array( - this.allocator.get_memory(new_path_ptr, new_path_len), - ); - const new_path_str = new TextDecoder().decode(new_path); - this.allocator.free(new_path_ptr, new_path_len); - - const error = this.path_rename( - fd, - old_path_str, - new_fd, - new_path_str, - ); - - set_error(error); - break; - } - // path_symlink: (old_path_ptr: pointer, old_path_len: u32, fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; - case 36: { - const old_path_ptr = Atomics.load(func_sig_view_u32, 1); - const old_path_len = Atomics.load(func_sig_view_u32, 2); - const fd = Atomics.load(func_sig_view_u32, 3); - const new_path_ptr = Atomics.load(func_sig_view_u32, 4); - const new_path_len = Atomics.load(func_sig_view_u32, 5); - - const old_path = new Uint8Array( - this.allocator.get_memory(old_path_ptr, old_path_len), - ); - const old_path_str = new TextDecoder().decode(old_path); - this.allocator.free(old_path_ptr, old_path_len); - const new_path = new Uint8Array( - this.allocator.get_memory(new_path_ptr, new_path_len), - ); - const new_path_str = new TextDecoder().decode(new_path); - this.allocator.free(new_path_ptr, new_path_len); - - set_error(this.path_symlink(old_path_str, fd, new_path_str)); - break; - } - // path_unlink_file: (fd: u32, path_ptr: pointer, path_len: u32) => errno; - case 37: { - const fd = Atomics.load(func_sig_view_u32, 1); - const path_ptr = Atomics.load(func_sig_view_u32, 2); - const path_len = Atomics.load(func_sig_view_u32, 3); - - const path = new Uint8Array( - this.allocator.get_memory(path_ptr, path_len), - ); - const path_str = new TextDecoder().decode(path); - this.allocator.free(path_ptr, path_len); - - set_error(this.path_unlink_file(fd, path_str)); - break; - } - default: { - throw new Error(`Unknown function number: ${func_number}`); - } - } - - const old_call_lock = Atomics.exchange(lock_view, 1, 0); - if (old_call_lock !== 1) { - throw new Error( - `Call is already set: ${old_call_lock}\nfunc: ${get_func_name_from_number(func_number)}\nfd: ${fd_n}`, - ); - } - - // console.log("called end: func: ", get_func_name_from_number(func_number), "fd: ", fd_n); - - const n = Atomics.notify(lock_view, 1); - if (n !== 1) { - if (n === 0) { - console.warn("notify number is 0. ref is late?"); - } else { - console.warn(`notify number is not 1: ${n}`); - } - } - - if (this.fds[fd_n] === undefined) { - break; - } - } catch (e) { - console.error(e); - - // sleep 1000ms - await new Promise((resolve) => setTimeout(resolve, 1000)); - - const lock_view = new Int32Array(this.lock_fds); - Atomics.exchange(lock_view, 1, 0); - const func_sig_view = new Int32Array(this.fd_func_sig); - Atomics.exchange(func_sig_view, 16, -1); - } - } - } + private allocator: AllocatorUseArrayBuffer; + + // args and env do not change, so copying them is fine. + // Functions that do not depend on fds are skipped. + // Since it is wasm32, the pointer is u32. + // errno is u8. + // https://github.com/WebAssembly/WASI/blob/4feaf733e946c375b610cc5d39ea2e1a68046e62/legacy/preview1/docs.md + // The first item is the function signature, and the second (if it exists) represents data that must be communicated in Park. If they are the same, it is not written. + // From here, direct access to fd begins. + // fd_advise: (fd: u32, offset: u64, len: u64, advice: u8) => errno; + // (fd: u32) => errno; + // fd_allocate: (fd: u32, offset: u64, len: u64) => errno; + // fd_close: (fd: u32) => errno; + // fd_datasync: (fd: u32) => errno; + // fd_fdstat_get: (fd: u32, fdstat_ptr: pointer) => errno; + // (fd: u32) => [wasi.Fdstat(u32 * 6)], errno]; + // fd_fdstat_set_flags: (fd: u32, flags: u16) => errno; + // fd_fdstat_set_rights: (fd: u32, fs_rights_base: u64, fs_rights_inheriting: u64) => errno; + // fd_filestat_get: (fd: u32, filestat_ptr: pointer) => errno; + // (fd: u32) => [wasi.Filestat(u32 * 16)], errno]; + // fd_filestat_set_size: (fd: u32, size: u64) => errno; + // fd_filestat_set_times: (fd: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; + // fd_pread: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, errno]; + // use share_arrays_memory; + // (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, data_ptr, errno]; + // fd_prestat_get: (fd: u32, prestat_ptr: pointer) => errno; + // (fd: u32) => [wasi.Prestat(u32 * 2)], errno]; + // fd_prestat_dir_name: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + // (fd: u32, path_len: u32) => [path_ptr: pointer, path_len: u32, errno]; + // fd_pwrite: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, errno]; + // use share_arrays_memory; + // (fd: u32, write_data: pointer, write_data_len: u32, offset: u64) => [u32, errno]; + // fd_read: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, errno]; + // use share_arrays_memory; + // (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, data_ptr, errno]; + // fd_readdir: (fd: u32, buf_ptr: pointer, buf_len: u32, cookie: u64) => [u32, errno]; + // use share_arrays_memory; + // (fd: u32, buf_len: u32, cookie: u64) => [buf_ptr: pointer, buf_len: u32, buf_used: u32, errno]; + // fd_renumber: (fd: u32, to: u32) => errno; + // fd_seek: (fd: u32, offset: i64, whence: u8) => [u64, errno]; + // fd_sync: (fd: u32) => errno; + // fd_tell: (fd: u32) => [u64, errno]; + // fd_write: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, errno]; + // use share_arrays_memory; + // (fd: u32, write_data: pointer, write_data_len: u32) => [u32, errno]; + // path_create_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + // path_filestat_get: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32) => [wasi.Filestat(u32 * 16), errno]; + // path_filestat_set_times: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; + // path_link: (old_fd: u32, old_flags: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; + // path_open: (fd: u32, dirflags: u32, path_ptr: pointer, path_len: u32, oflags: u32, fs_rights_base: u64, fs_rights_inheriting: u64, fdflags: u16) => [u32, errno]; + // note: fdsにpushするが、既存のfdに影響しないので、競合しない。 + // path_readlink: (fd: u32, path_ptr: pointer, path_len: u32, buf_ptr: pointer, buf_len: u32) => [u32, errno]; + // use share_arrays_memory; + // (fd: u32, path_ptr: pointer, path_len: u32, buf_len: u32) => [buf_len: u32, data_ptr: pointer, data_len: u32, errno]; + // path_remove_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + // path_rename: (old_fd: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; + // path_symlink: (old_path_ptr: pointer, old_path_len: u32, fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; + // path_unlink_file: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + + // Lock when you want to use fd + // Array<[lock, call_func]> + private lock_fds: SharedArrayBuffer; + + // 1 bytes: fds.length + // 1 bytes: wasi_farm_ref num(id) + // Actually, as long as it is working properly, fds.length is not used + private fds_len_and_num: SharedArrayBuffer; + + // listen promise keep + private listen_fds: Array> = []; + + // The largest size is u32 * 18 + 1 + // Alignment is troublesome, so make it u32 * 18 + 4 + // In other words, one size is 76 bytes + private fd_func_sig: SharedArrayBuffer; + + // listen base handle keep + private listen_base_handle: Promise; + + // listen base lock and call etc + private base_func_util: SharedArrayBuffer; + + // tell other processes that the file descriptor has been closed + private fd_close_receiver: FdCloseSender; + + // this is not send by postMessage, + // so it is not necessary to keep shared_array_buffer + // this class is not used by user, + // to avoid mistakes, all constructors are now required to be passed in. + constructor( + fds: Array, + // stdin fd number + stdin: number | undefined, + // stdout fd number + stdout: number | undefined, + // stderr fd number + stderr: number | undefined, + // wasi_farm_ref default allow fds + default_allow_fds: Array, + allocator_size?: number, + ) { + super(fds, stdin, stdout, stderr, default_allow_fds); + + if (allocator_size === undefined) { + this.allocator = new AllocatorUseArrayBuffer(); + } else { + this.allocator = new AllocatorUseArrayBuffer( + new SharedArrayBuffer(allocator_size), + ); + } + const max_fds_len = 128; + this.lock_fds = new SharedArrayBuffer(4 * max_fds_len * 3); + this.fd_func_sig = new SharedArrayBuffer( + fd_func_sig_u32_size * 4 * max_fds_len, + ); + this.fds_len_and_num = new SharedArrayBuffer(8); + + const view = new Int32Array(this.fds_len_and_num); + Atomics.store(view, 0, fds.length); + Atomics.store(view, 1, 0); + + this.fd_close_receiver = new FdCloseSenderUseArrayBuffer(); + this.base_func_util = new SharedArrayBuffer(24); + } + + /// Send this return by postMessage. + get_ref(): WASIFarmRefUseArrayBufferObject { + return { + allocator: this.allocator, + lock_fds: this.lock_fds, + fds_len_and_num: this.fds_len_and_num, + fd_func_sig: this.fd_func_sig, + base_func_util: this.base_func_util, + fd_close_receiver: this.fd_close_receiver, + stdin: this.stdin, + stdout: this.stdout, + stderr: this.stderr, + default_fds: this.default_allow_fds, + }; + } + + // abstract methods implementation + // from fd set ex) path_open + // received and listen the fd + // and set fds.length + async notify_set_fd(fd: number) { + if (this.fds[fd] === undefined) { + throw new Error("fd is not defined"); + } + if (fd >= 128) { + throw new Error("fd is too big. expand is not supported yet"); + } + if (this.listen_fds[fd] !== undefined) { + if (this.listen_fds[fd] instanceof Promise) { + console.warn("fd is already set yet"); + await this.listen_fds[fd]; + } + } + this.listen_fds[fd] = this.listen_fd(fd); + + const view = new Int32Array(this.fds_len_and_num); + Atomics.store(view, 0, this.fds.length); + // const len = Atomics.store(view, 0, this.fds.length); + // console.log("notify_set_fd: len: ", len); + } + + // abstract methods implementation + // called by fd close ex) fd_close + async notify_rm_fd(fd: number) { + (async () => { + await this.listen_fds[fd]; + this.listen_fds[fd] = undefined; + })(); + + // console.log("notify_rm_fd", fd); + // console.log("fds", this.fds); + // console.log("fds_map", this.fds_map); + + // console.log("notify_rm_fd: fds_map", this.fds_map); + // console.log("notify_rm_fd: fd", fd); + + // console.log("notify_rm_fd: fds_map[fd]", [...this.fds_map[fd]]); + + await this.fd_close_receiver.send(this.fds_map[fd], fd); + + this.fds_map[fd] = []; + } + + // abstract methods implementation + // wait to close old listener + can_set_new_fd(fd: number): [boolean, Promise | undefined] { + if (this.listen_fds[fd] instanceof Promise) { + return [false, this.listen_fds[fd]]; + } + return [true, undefined]; + } + + // listen all fds and base + // Must be called before was_ref_id is instantiated + listen() { + this.listen_fds = []; + for (let n = 0; n < this.fds.length; n++) { + this.listen_fds.push(this.listen_fd(n)); + } + this.listen_base_handle = this.listen_base(); + } + + // listen base + // ex) set_fds_map + // if close fd and send to other process, + // it need targets wasi_farm_ref id + // so, set fds_map + async listen_base() { + const lock_view = new Int32Array(this.base_func_util); + Atomics.store(lock_view, 0, 0); + Atomics.store(lock_view, 1, 0); + + // eslint-disable-next-line no-constant-condition + while (true) { + try { + let lock: "not-equal" | "timed-out" | "ok"; + + const { value } = Atomics.waitAsync(lock_view, 1, 0); + if (value instanceof Promise) { + lock = await value; + } else { + lock = value; + } + if (lock === "timed-out") { + throw new Error("timed-out"); + } + + const func_number = Atomics.load(lock_view, 2); + + switch (func_number) { + // set_fds_map: (fds_ptr: u32, fds_len: u32); + case 0: { + // console.log("set_fds_map"); + const ptr = Atomics.load(lock_view, 3); + const len = Atomics.load(lock_view, 4); + // console.log("set_fds_map", ptr, len); + const data = new Uint32Array(this.allocator.get_memory(ptr, len)); + this.allocator.free(ptr, len); + const wasi_farm_ref_id = Atomics.load(lock_view, 5); + + // console.log("listen_base set_fds_map", data, "from", wasi_farm_ref_id); + + // console.log("listen_base fds_map", this.fds_map); + + for (let i = 0; i < len / 4; i++) { + const fd = data[i]; + if (this.fds_map[fd] === undefined) { + this.fds_map[fd] = []; + console.error("listen_base fd is not defined"); + } + this.fds_map[fd].push(wasi_farm_ref_id); + // console.log("this.fds_map", this.fds_map); + // console.log("this.fds_map[fd]", this.fds_map[fd]); + // console.log("this.fds_map[1]", this.fds_map[1]); + // console.log("fd", fd, "wasi_farm_ref_id", wasi_farm_ref_id); + } + + // console.log("listen_base fds_map", this.fds_map); + + // sleep 1000ms + await new Promise((resolve) => setTimeout(resolve, 1000)); + + break; + } + } + + const old_call_lock = Atomics.exchange(lock_view, 1, 0); + if (old_call_lock !== 1) { + throw new Error("Lock is already set"); + } + const num = Atomics.notify(lock_view, 1, 1); + if (num !== 1) { + if (num === 0) { + console.warn("notify failed, waiter is late"); + continue; + } + throw new Error(`notify failed: ${num}`); + } + } catch (e) { + console.error("error", e); + Atomics.store(lock_view, 1, 0); + Atomics.notify(lock_view, 1, 1); + } + } + } + + // listen fd + async listen_fd(fd_n: number) { + const lock_view = new Int32Array(this.lock_fds, fd_n * 12); + const bytes_offset = fd_n * fd_func_sig_bytes; + const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); + const func_sig_view_i32 = new Int32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Int32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + const errno_offset = fd_func_sig_u32_size - 1; + Atomics.store(lock_view, 0, 0); + Atomics.store(lock_view, 1, 0); + Atomics.store(func_sig_view_i32, errno_offset, -1); + + // eslint-disable-next-line no-constant-condition + while (true) { + try { + let lock: "not-equal" | "timed-out" | "ok"; + + const { value } = Atomics.waitAsync(lock_view, 1, 0); + if (value instanceof Promise) { + // console.log("listen", fd_n, 1); + lock = await value; + } else { + lock = value; + } + if (lock === "timed-out") { + throw new Error("timed-out"); + } + + const func_lock = Atomics.load(lock_view, 1); + + if (func_lock !== 1) { + throw new Error(`func_lock is already set: ${func_lock}`); + } + + // console.log("func_lock", func_lock); + + // console.log("called", fd_n, 1); + + const set_error = (errno: number) => { + // console.log("set_error", errno, "pointer", errno_offset); + Atomics.store(func_sig_view_i32, errno_offset, errno); + }; + + const func_number = Atomics.load(func_sig_view_u32, 0); + + // console.log("called: func: ", get_func_name_from_number(func_number), "fd: ", fd_n); + + switch (func_number) { + // fd_advise: (fd: u32) => errno; + case 7: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const error = this.fd_advise(fd); + + set_error(error); + break; + } + // fd_allocate: (fd: u32, offset: u64, len: u64) => errno; + case 8: { + const fd = Atomics.load(func_sig_view_u32, 1); + const offset = Atomics.load(func_sig_view_u64, 1); + const len = Atomics.load(func_sig_view_u64, 2); + + const error = this.fd_allocate(fd, offset, len); + + set_error(error); + break; + } + // fd_close: (fd: u32) => errno; + case 9: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const error = await this.fd_close(fd); + + // console.log("fd_close", fd, error); + + set_error(error); + break; + } + // fd_datasync: (fd: u32) => errno; + case 10: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const error = this.fd_datasync(fd); + + set_error(error); + break; + } + // fd_fdstat_get: (fd: u32) => [wasi.Fdstat(u32 * 6)], errno]; + case 11: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const [fdstat, ret] = this.fd_fdstat_get(fd); + + if (fdstat) { + Atomics.store(func_sig_view_u8, 0, fdstat.fs_filetype); + Atomics.store(func_sig_view_u16, 2, fdstat.fs_flags); + Atomics.store(func_sig_view_u64, 1, fdstat.fs_rights_base); + Atomics.store(func_sig_view_u64, 2, fdstat.fs_rights_inherited); + } + set_error(ret); + break; + } + // fd_fdstat_set_flags: (fd: u32, flags: u16) => errno; + case 12: { + const fd = Atomics.load(func_sig_view_u32, 1); + const flags = Atomics.load(func_sig_view_u16, 4); + + const error = this.fd_fdstat_set_flags(fd, flags); + + set_error(error); + break; + } + // fd_fdstat_set_rights: (fd: u32, fs_rights_base: u64, fs_rights_inheriting: u64) => errno; + case 13: { + const fd = Atomics.load(func_sig_view_u32, 1); + const fs_rights_base = Atomics.load(func_sig_view_u64, 1); + const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 2); + + const error = this.fd_fdstat_set_rights( + fd, + fs_rights_base, + fs_rights_inheriting, + ); + + set_error(error); + break; + } + // fd_filestat_get: (fd: u32) => [wasi.Filestat(u32 * 16)], errno]; + case 14: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const [filestat, ret] = this.fd_filestat_get(fd); + + if (filestat) { + Atomics.store(func_sig_view_u64, 0, filestat.dev); + Atomics.store(func_sig_view_u64, 1, filestat.ino); + Atomics.store(func_sig_view_u8, 16, filestat.filetype); + Atomics.store(func_sig_view_u64, 3, filestat.nlink); + Atomics.store(func_sig_view_u64, 4, filestat.size); + Atomics.store(func_sig_view_u64, 5, filestat.atim); + Atomics.store(func_sig_view_u64, 6, filestat.mtim); + Atomics.store(func_sig_view_u64, 7, filestat.ctim); + } + + set_error(ret); + break; + } + // fd_filestat_set_size: (fd: u32, size: u64) => errno; + case 15: { + const fd = Atomics.load(func_sig_view_u32, 1); + const size = Atomics.load(func_sig_view_u64, 1); + + const error = this.fd_filestat_set_size(fd, size); + + set_error(error); + break; + } + // fd_filestat_set_times: (fd: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; + case 16: { + const fd = Atomics.load(func_sig_view_u32, 1); + const atim = Atomics.load(func_sig_view_u64, 1); + const mtim = Atomics.load(func_sig_view_u64, 2); + const fst_flags = Atomics.load(func_sig_view_u16, 12); + + const error = this.fd_filestat_set_times(fd, atim, mtim, fst_flags); + + set_error(error); + break; + } + // fd_pread: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, data_ptr, errno]; + case 17: { + const fd = Atomics.load(func_sig_view_u32, 1); + const iovs_ptr = Atomics.load(func_sig_view_u32, 2); + const iovs_ptr_len = Atomics.load(func_sig_view_u32, 3); + const offset = Atomics.load(func_sig_view_u64, 2); + const data = new Uint32Array( + this.allocator.get_memory(iovs_ptr, iovs_ptr_len), + ); + this.allocator.free(iovs_ptr, iovs_ptr_len); + + const iovecs = new Array(); + for (let i = 0; i < iovs_ptr_len; i += 8) { + const iovec = new wasi.Iovec(); + iovec.buf = data[i * 2]; + iovec.buf_len = data[i * 2 + 1]; + iovecs.push(iovec); + } + + const [[nread, buffer8], error] = this.fd_pread(fd, iovecs, offset); + + if (nread !== undefined) { + Atomics.store(func_sig_view_u32, 0, nread); + } + if (buffer8) { + await this.allocator.async_write( + buffer8, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 1, + ); + } + set_error(error); + break; + } + // fd_prestat_get: (fd: u32) => [wasi.Prestat(u32 * 2)], errno]; + case 18: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const [prestat, ret] = this.fd_prestat_get(fd); + + // console.log("fd_prestat_get", prestat, ret); + + if (prestat) { + Atomics.store(func_sig_view_u32, 0, prestat.tag); + Atomics.store( + func_sig_view_u32, + 1, + prestat.inner.pr_name.byteLength, + ); + } + set_error(ret); + break; + } + // fd_prestat_dir_name: (fd: u32, path_len: u32) => [path_ptr: pointer, path_len: u32, errno]; + case 19: { + const fd = Atomics.load(func_sig_view_u32, 1); + const path_len = Atomics.load(func_sig_view_u32, 2); + + const [prestat_dir_name, ret] = this.fd_prestat_dir_name( + fd, + path_len, + ); + + // console.log("fd_prestat_dir_name: park: ", prestat_dir_name); + + if ( + prestat_dir_name && + (ret === wasi.ERRNO_SUCCESS || ret === wasi.ERRNO_NAMETOOLONG) + ) { + await this.allocator.async_write( + prestat_dir_name, + this.fd_func_sig, + fd * fd_func_sig_u32_size, + ); + } + set_error(ret); + break; + } + // fd_pwrite: (fd: u32, write_data: pointer, write_data_len: u32, offset: u64) => [u32, errno]; + case 20: { + const fd = Atomics.load(func_sig_view_u32, 1); + const write_data_ptr = Atomics.load(func_sig_view_u32, 2); + const write_data_len = Atomics.load(func_sig_view_u32, 3); + const offset = Atomics.load(func_sig_view_u64, 2); + + const data = new Uint8Array( + this.allocator.get_memory(write_data_ptr, write_data_len), + ); + this.allocator.free(write_data_ptr, write_data_len); + + const [nwritten, error] = this.fd_pwrite(fd, data, offset); + + if (nwritten !== undefined) { + Atomics.store(func_sig_view_u32, 0, nwritten); + } + set_error(error); + break; + } + // fd_read: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, data_ptr, errno]; + case 21: { + const fd = Atomics.load(func_sig_view_u32, 1); + const iovs_ptr = Atomics.load(func_sig_view_u32, 2); + const iovs_ptr_len = Atomics.load(func_sig_view_u32, 3); + // console.log("fd_read: park: iovs: Uint8Array", this.allocator.get_memory(iovs_ptr, iovs_ptr_len)); + // console.log("ptr_len", iovs_ptr_len); + const iovs = new Uint32Array( + this.allocator.get_memory(iovs_ptr, iovs_ptr_len), + ); + this.allocator.free(iovs_ptr, iovs_ptr_len); + + // console.log("fd_read: park: iovs", iovs); + + const iovecs = new Array(); + for (let i = 0; i < iovs_ptr_len; i += 8) { + const iovec = new wasi.Iovec(); + iovec.buf = iovs[i * 2]; + iovec.buf_len = iovs[i * 2 + 1]; + iovecs.push(iovec); + } + + // console.log("fd_read: park: iovecs", iovecs); + + const [[nread, buffer8], error] = this.fd_read(fd, iovecs); + + // console.log("fd_read: park: buffer8", new TextDecoder().decode(buffer8)); + + if (nread !== undefined) { + Atomics.store(func_sig_view_u32, 0, nread); + } + if (buffer8) { + await this.allocator.async_write( + buffer8, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 1, + ); + } + set_error(error); + break; + } + // fd_readdir: (fd: u32, buf_len: u32, cookie: u64) => [buf_ptr: pointer, buf_len: u32, buf_used: u32, errno]; + case 22: { + const fd = Atomics.load(func_sig_view_u32, 1); + const buf_len = Atomics.load(func_sig_view_u32, 2); + const cookie = Atomics.load(func_sig_view_u64, 2); + + const [[array, buf_used], error] = this.fd_readdir( + fd, + buf_len, + cookie, + ); + + if (array) { + await this.allocator.async_write( + array, + this.fd_func_sig, + fd * fd_func_sig_u32_size, + ); + } + if (buf_used !== undefined) { + Atomics.store(func_sig_view_u32, 2, buf_used); + } + set_error(error); + break; + } + // fd_seek: (fd: u32, offset: i64, whence: u8) => [u64, errno]; + case 24: { + const fd = Atomics.load(func_sig_view_u32, 1); + const offset = Atomics.load(func_sig_view_u64, 1); + const whence = Atomics.load(func_sig_view_u8, 16); + + const [new_offset, error] = this.fd_seek(fd, offset, whence); + + if (new_offset !== undefined) { + Atomics.store(func_sig_view_u64, 0, new_offset); + } + set_error(error); + break; + } + // fd_sync: (fd: u32) => errno; + case 25: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const error = this.fd_sync(fd); + + set_error(error); + break; + } + // fd_tell: (fd: u32) => [u64, errno]; + case 26: { + const fd = Atomics.load(func_sig_view_u32, 1); + + const [offset, error] = this.fd_tell(fd); + + if (offset !== undefined) { + Atomics.store(func_sig_view_u64, 0, offset); + } + set_error(error); + break; + } + // fd_write: (fd: u32, write_data: pointer, write_data_len: u32) => [u32, errno]; + case 27: { + const fd = Atomics.load(func_sig_view_u32, 1); + const write_data_ptr = Atomics.load(func_sig_view_u32, 2); + const write_data_len = Atomics.load(func_sig_view_u32, 3); + + const data = new Uint8Array( + this.allocator.get_memory(write_data_ptr, write_data_len), + ); + this.allocator.free(write_data_ptr, write_data_len); + + // console.log("allocator", this.allocator); + + // console.log("fd_write: park: write_data", new TextDecoder().decode(data)); + + const [nwritten, error] = this.fd_write(fd, data); + + // console.log("fd_write: park: error", error); + + if (nwritten !== undefined) { + Atomics.store(func_sig_view_u32, 0, nwritten); + } + set_error(error); + break; + } + // path_create_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + case 28: { + const fd = Atomics.load(func_sig_view_u32, 1); + const path_ptr = Atomics.load(func_sig_view_u32, 2); + const path_len = Atomics.load(func_sig_view_u32, 3); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + const error = this.path_create_directory(fd, path_str); + + set_error(error); + break; + } + // path_filestat_get: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32) => [wasi.Filestat(u32 * 16), errno]; + case 29: { + const fd = Atomics.load(func_sig_view_u32, 1); + const flags = Atomics.load(func_sig_view_u32, 2); + const path_ptr = Atomics.load(func_sig_view_u32, 3); + const path_len = Atomics.load(func_sig_view_u32, 4); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + const [filestat, ret] = this.path_filestat_get(fd, flags, path_str); + + if (filestat) { + Atomics.store(func_sig_view_u64, 0, filestat.dev); + Atomics.store(func_sig_view_u64, 1, filestat.ino); + Atomics.store(func_sig_view_u8, 16, filestat.filetype); + Atomics.store(func_sig_view_u64, 3, filestat.nlink); + Atomics.store(func_sig_view_u64, 4, filestat.size); + Atomics.store(func_sig_view_u64, 5, filestat.atim); + Atomics.store(func_sig_view_u64, 6, filestat.mtim); + Atomics.store(func_sig_view_u64, 7, filestat.ctim); + } + set_error(ret); + break; + } + // path_filestat_set_times: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32, atim: u64, mtim: u64, fst_flags: u16) => errno; + case 30: { + const fd = Atomics.load(func_sig_view_u32, 1); + const flags = Atomics.load(func_sig_view_u32, 2); + const path_ptr = Atomics.load(func_sig_view_u32, 3); + const path_len = Atomics.load(func_sig_view_u32, 4); + const atim = Atomics.load(func_sig_view_u64, 3); + const mtim = Atomics.load(func_sig_view_u64, 4); + const fst_flags = Atomics.load(func_sig_view_u16, 12); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + const error = this.path_filestat_set_times( + fd, + flags, + path_str, + atim, + mtim, + fst_flags, + ); + + set_error(error); + break; + } + // path_link: (old_fd: u32, old_flags: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; + case 31: { + const old_fd = Atomics.load(func_sig_view_u32, 1); + const old_flags = Atomics.load(func_sig_view_u32, 2); + const old_path_ptr = Atomics.load(func_sig_view_u32, 3); + const old_path_len = Atomics.load(func_sig_view_u32, 4); + const new_fd = Atomics.load(func_sig_view_u32, 5); + const new_path_ptr = Atomics.load(func_sig_view_u32, 6); + const new_path_len = Atomics.load(func_sig_view_u32, 7); + + const old_path = new Uint8Array( + this.allocator.get_memory(old_path_ptr, old_path_len), + ); + const old_path_str = new TextDecoder().decode(old_path); + this.allocator.free(old_path_ptr, old_path_len); + const new_path = new Uint8Array( + this.allocator.get_memory(new_path_ptr, new_path_len), + ); + const new_path_str = new TextDecoder().decode(new_path); + this.allocator.free(new_path_ptr, new_path_len); + + const error = this.path_link( + old_fd, + old_flags, + old_path_str, + new_fd, + new_path_str, + ); + + set_error(error); + break; + } + // path_open: (fd: u32, dirflags: u32, path_ptr: pointer, path_len: u32, oflags: u32, fs_rights_base: u64, fs_rights_inheriting: u64, fdflags: u16) => [u32, errno]; + case 32: { + const fd = Atomics.load(func_sig_view_u32, 1); + const dirflags = Atomics.load(func_sig_view_u32, 2); + const path_ptr = Atomics.load(func_sig_view_u32, 3); + const path_len = Atomics.load(func_sig_view_u32, 4); + const oflags = Atomics.load(func_sig_view_u32, 5); + const fs_rights_base = Atomics.load(func_sig_view_u64, 3); + const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 4); + const fd_flags = Atomics.load(func_sig_view_u16, 20); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + const [opened_fd, error] = await this.path_open( + fd, + dirflags, + path_str, + oflags, + fs_rights_base, + fs_rights_inheriting, + fd_flags, + ); + + // console.log("path_open: opend_fd", opened_fd, error); + + if (opened_fd !== undefined) { + Atomics.store(func_sig_view_u32, 0, opened_fd); + } + set_error(error); + break; + } + // path_readlink: (fd: u32, path_ptr: pointer, path_len: u32, buf_len: u32) => [buf_len: u32, data_ptr: pointer, data_len: u32, errno]; + case 33: { + const fd = Atomics.load(func_sig_view_u32, 1); + const path_ptr = Atomics.load(func_sig_view_u32, 2); + const path_len = Atomics.load(func_sig_view_u32, 3); + const buf_len = Atomics.load(func_sig_view_u32, 4); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + const [buf, error] = this.path_readlink(fd, path_str, buf_len); + + if (buf) { + await this.allocator.async_write( + buf, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 1, + ); + Atomics.store(func_sig_view_u32, 0, buf.byteLength); + } + set_error(error); + break; + } + // path_remove_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + case 34: { + const fd = Atomics.load(func_sig_view_u32, 1); + const path_ptr = Atomics.load(func_sig_view_u32, 2); + const path_len = Atomics.load(func_sig_view_u32, 3); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + const error = this.path_remove_directory(fd, path_str); + + set_error(error); + break; + } + // path_rename: (old_fd: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; + case 35: { + const fd = Atomics.load(func_sig_view_u32, 1); + const old_path_ptr = Atomics.load(func_sig_view_u32, 2); + const old_path_len = Atomics.load(func_sig_view_u32, 3); + const new_fd = Atomics.load(func_sig_view_u32, 4); + const new_path_ptr = Atomics.load(func_sig_view_u32, 5); + const new_path_len = Atomics.load(func_sig_view_u32, 6); + + const old_path = new Uint8Array( + this.allocator.get_memory(old_path_ptr, old_path_len), + ); + const old_path_str = new TextDecoder().decode(old_path); + this.allocator.free(old_path_ptr, old_path_len); + const new_path = new Uint8Array( + this.allocator.get_memory(new_path_ptr, new_path_len), + ); + const new_path_str = new TextDecoder().decode(new_path); + this.allocator.free(new_path_ptr, new_path_len); + + const error = this.path_rename( + fd, + old_path_str, + new_fd, + new_path_str, + ); + + set_error(error); + break; + } + // path_symlink: (old_path_ptr: pointer, old_path_len: u32, fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno; + case 36: { + const old_path_ptr = Atomics.load(func_sig_view_u32, 1); + const old_path_len = Atomics.load(func_sig_view_u32, 2); + const fd = Atomics.load(func_sig_view_u32, 3); + const new_path_ptr = Atomics.load(func_sig_view_u32, 4); + const new_path_len = Atomics.load(func_sig_view_u32, 5); + + const old_path = new Uint8Array( + this.allocator.get_memory(old_path_ptr, old_path_len), + ); + const old_path_str = new TextDecoder().decode(old_path); + this.allocator.free(old_path_ptr, old_path_len); + const new_path = new Uint8Array( + this.allocator.get_memory(new_path_ptr, new_path_len), + ); + const new_path_str = new TextDecoder().decode(new_path); + this.allocator.free(new_path_ptr, new_path_len); + + set_error(this.path_symlink(old_path_str, fd, new_path_str)); + break; + } + // path_unlink_file: (fd: u32, path_ptr: pointer, path_len: u32) => errno; + case 37: { + const fd = Atomics.load(func_sig_view_u32, 1); + const path_ptr = Atomics.load(func_sig_view_u32, 2); + const path_len = Atomics.load(func_sig_view_u32, 3); + + const path = new Uint8Array( + this.allocator.get_memory(path_ptr, path_len), + ); + const path_str = new TextDecoder().decode(path); + this.allocator.free(path_ptr, path_len); + + set_error(this.path_unlink_file(fd, path_str)); + break; + } + default: { + throw new Error(`Unknown function number: ${func_number}`); + } + } + + const old_call_lock = Atomics.exchange(lock_view, 1, 0); + if (old_call_lock !== 1) { + throw new Error( + `Call is already set: ${old_call_lock}\nfunc: ${get_func_name_from_number(func_number)}\nfd: ${fd_n}`, + ); + } + + // console.log("called end: func: ", get_func_name_from_number(func_number), "fd: ", fd_n); + + const n = Atomics.notify(lock_view, 1); + if (n !== 1) { + if (n === 0) { + console.warn("notify number is 0. ref is late?"); + } else { + console.warn(`notify number is not 1: ${n}`); + } + } + + if (this.fds[fd_n] === undefined) { + break; + } + } catch (e) { + console.error(e); + + // sleep 1000ms + await new Promise((resolve) => setTimeout(resolve, 1000)); + + const lock_view = new Int32Array(this.lock_fds); + Atomics.exchange(lock_view, 1, 0); + const func_sig_view = new Int32Array(this.fd_func_sig); + Atomics.exchange(func_sig_view, 16, -1); + } + } + } } diff --git a/src/wasi_farm/shared_array_buffer/ref.ts b/src/wasi_farm/shared_array_buffer/ref.ts index 5cbe4b1..acae92b 100644 --- a/src/wasi_farm/shared_array_buffer/ref.ts +++ b/src/wasi_farm/shared_array_buffer/ref.ts @@ -1,1403 +1,1403 @@ import * as wasi from "../../wasi_defs.js"; import { WASIFarmRef, type WASIFarmRefObject } from "../ref.js"; import { - AllocatorUseArrayBuffer, - type AllocatorUseArrayBufferObject, + AllocatorUseArrayBuffer, + type AllocatorUseArrayBufferObject, } from "./allocator.js"; import { - FdCloseSenderUseArrayBuffer, - type FdCloseSenderUseArrayBufferObject, + FdCloseSenderUseArrayBuffer, + type FdCloseSenderUseArrayBufferObject, } from "./fd_close_sender.js"; import { fd_func_sig_bytes, fd_func_sig_u32_size } from "./park.js"; export type WASIFarmRefUseArrayBufferObject = { - allocator: AllocatorUseArrayBuffer; - lock_fds: SharedArrayBuffer; - fds_len_and_num: SharedArrayBuffer; - fd_func_sig: SharedArrayBuffer; - base_func_util: SharedArrayBuffer; + allocator: AllocatorUseArrayBuffer; + lock_fds: SharedArrayBuffer; + fds_len_and_num: SharedArrayBuffer; + fd_func_sig: SharedArrayBuffer; + base_func_util: SharedArrayBuffer; } & WASIFarmRefObject; // Transmittable objects to communicate with Park export class WASIFarmRefUseArrayBuffer extends WASIFarmRef { - // For more information on member variables, see . See /park.ts - allocator: AllocatorUseArrayBuffer; - lock_fds: SharedArrayBuffer; - // byte 1: fds_len - // byte 2: all wasi_farm_ref num - fds_len_and_num: SharedArrayBuffer; - fd_func_sig: SharedArrayBuffer; - base_func_util: SharedArrayBuffer; - - constructor( - allocator: AllocatorUseArrayBufferObject, - lock_fds: SharedArrayBuffer, - fds_len_and_num: SharedArrayBuffer, - fd_func_sig: SharedArrayBuffer, - base_func_util: SharedArrayBuffer, - fd_close_receiver: FdCloseSenderUseArrayBufferObject, - stdin: number | undefined, - stdout: number | undefined, - stderr: number | undefined, - default_fds: Array, - ) { - super( - stdin, - stdout, - stderr, - FdCloseSenderUseArrayBuffer.init_self(fd_close_receiver), - default_fds, - ); - this.allocator = AllocatorUseArrayBuffer.init_self(allocator); - this.lock_fds = lock_fds; - this.fd_func_sig = fd_func_sig; - this.base_func_util = base_func_util; - this.fds_len_and_num = fds_len_and_num; - - // console.log("fds_len_and_num", this.fds_len_and_num); - - // const view = new Int32Array(this.fds_len_and_num); - // Atomics.store(view, 0, 0); - } - - get_fds_len(): number { - const view = new Int32Array(this.fds_len_and_num); - return Atomics.load(view, 0); - } - - static init_self(sl: WASIFarmRefUseArrayBufferObject): WASIFarmRef { - return new WASIFarmRefUseArrayBuffer( - sl.allocator, - sl.lock_fds, - sl.fds_len_and_num, - sl.fd_func_sig, - sl.base_func_util, - sl.fd_close_receiver as unknown as FdCloseSenderUseArrayBufferObject, - sl.stdin, - sl.stdout, - sl.stderr, - sl.default_fds, - ); - } - - // allocate a new id on wasi_farm_ref and return it - set_id(): number { - const view = new Int32Array(this.fds_len_and_num); - const id = Atomics.add(view, 1, 1); - this.id = id; - return id; - } - - // lock base_func - private lock_base_func(): void { - const view = new Int32Array(this.base_func_util); - // eslint-disable-next-line no-constant-condition - while (true) { - const lock = Atomics.wait(view, 0, 1); - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old !== 0) { - continue; - } - break; - } - } - - // call base_func - private call_base_func(): void { - const view = new Int32Array(this.base_func_util); - const old = Atomics.exchange(view, 1, 1); - if (old !== 0) { - console.error("what happened?"); - } - Atomics.notify(view, 1, 1); - } - - // wait base_func - private wait_base_func(): void { - const view = new Int32Array(this.base_func_util); - const lock = Atomics.wait(view, 1, 1); - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - } - - // release base_func - private release_base_func(): void { - const view = new Int32Array(this.base_func_util); - Atomics.store(view, 0, 0); - Atomics.notify(view, 0, 1); - } - - // set park_fds_map - set_park_fds_map(fds: Array): void { - this.lock_base_func(); - const view = new Int32Array(this.base_func_util); - Atomics.store(view, 2, 0); - const fds_array = new Uint32Array(fds); - // console.log("fds_array", fds_array); - this.allocator.block_write(fds_array, this.base_func_util, 3); - Atomics.store(view, 5, this.id); - this.call_base_func(); - this.wait_base_func(); - this.release_base_func(); - } - - private lock_fd(fd: number) { - // console.log("lock_fd start", fd); - const view = new Int32Array(this.lock_fds, fd * 12); - // eslint-disable-next-line no-constant-condition - while (true) { - const now_value = Atomics.load(view, 0); - if (now_value !== 0) { - const value = Atomics.wait(view, 0, now_value); - if (value === "timed-out") { - console.error("lock_fd timed-out"); - continue; - } - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old === 0) { - // console.log("lock_fd success", fd); - return; - } - } - } - - private release_fd(fd: number) { - // console.log("release_fd", fd); - const view = new Int32Array(this.lock_fds, fd * 12); - Atomics.store(view, 0, 0); - Atomics.notify(view, 0, 1); - } - - private lock_double_fd(fd1: number, fd2: number) { - // console.log("lock_double_fd", fd1, fd2); - const view = new Int32Array(this.lock_fds); - // eslint-disable-next-line no-constant-condition - while (true) { - const now_value1 = Atomics.load(view, fd1 * 3); - const value = Atomics.wait(view, fd1 * 3, now_value1); - if (value === "timed-out") { - console.error("lock_double_fd timed-out"); - continue; - } - const old1 = Atomics.exchange(view, fd1 * 3, 2); - if (old1 === 0) { - const now_value2 = Atomics.load(view, fd2 * 3); - if (now_value2 === 2) { - // It's nearly deadlocked. - if (fd1 < fd2) { - // release fd1 - Atomics.store(view, fd1 * 3, 0); - Atomics.notify(view, fd1 * 3, 1); - continue; - } - } - const value = Atomics.wait(view, fd2 * 3, now_value2); - if (value === "timed-out") { - console.error("lock_double_fd timed-out"); - continue; - } - const old2 = Atomics.exchange(view, fd2 * 3, 2); - if (old2 === 0) { - return; - } - Atomics.store(view, fd1 * 3, 0); - Atomics.notify(view, fd1 * 3, 1); - } - } - } - - private release_double_fd(fd1: number, fd2: number) { - // console.log("release_double_fd", fd1, fd2); - const view = new Int32Array(this.lock_fds); - Atomics.store(view, fd1 * 3, 0); - Atomics.notify(view, fd1 * 3, 1); - Atomics.store(view, fd2 * 3, 0); - Atomics.notify(view, fd2 * 3, 1); - } - - private invoke_fd_func(fd: number): boolean { - if (fd === undefined) { - return false; - } - // console.log("invoke_fd_func", fd); - const view = new Int32Array(this.lock_fds, fd * 12 + 4); - const old = Atomics.exchange(view, 0, 1); - if (old === 1) { - console.error(`invoke_fd_func already invoked\nfd: ${fd}`); - return; - } - const n = Atomics.notify(view, 0); - if (n !== 1) { - if (n === 0) { - const len = this.get_fds_len(); - if (len <= fd) { - const lock = Atomics.exchange(view, 0, 0); - if (lock !== 1) { - console.error("what happened?"); - } - Atomics.notify(view, 0, 1); - console.error("what happened?: len", len, "fd", fd); - return true; - } - console.warn("invoke_func_loop is late"); - return true; - } - console.error("invoke_fd_func notify failed:", n); - return false; - } - return true; - } - - private wait_fd_func(fd: number) { - // console.log("wait_fd_func", fd); - const view = new Int32Array(this.lock_fds, fd * 12 + 4); - const value = Atomics.wait(view, 0, 1); - if (value === "timed-out") { - console.error("wait call park_fd_func timed-out"); - } - } - - private call_fd_func(fd: number): boolean { - if (!this.invoke_fd_func(fd)) { - return false; - } - // console.log("call_fd_func", fd); - this.wait_fd_func(fd); - // console.log("wait_fd_func", fd); - // console.log("call_fd_func released", fd); - return true; - } - - private get_error(fd: number): number { - const func_sig_view_i32 = new Int32Array( - this.fd_func_sig, - fd * fd_func_sig_bytes, - ); - const errno_offset = fd_func_sig_u32_size - 1; - // console.log("get_error: offset", errno_offset); - return Atomics.load(func_sig_view_i32, errno_offset); - } - - fd_advise(fd: number): number { - this.lock_fd(fd); - - const func_sig_view_u32 = new Uint32Array( - this.fd_func_sig, - fd * fd_func_sig_bytes, - ); - - Atomics.store(func_sig_view_u32, 0, 7); - Atomics.store(func_sig_view_u32, 1, fd); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - fd_allocate(fd: number, offset: bigint, len: bigint): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 8); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u64, 1, offset); - Atomics.store(func_sig_view_u64, 2, len); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - fd_close(fd: number): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 9); - Atomics.store(func_sig_view_u32, 1, fd); + // For more information on member variables, see . See /park.ts + allocator: AllocatorUseArrayBuffer; + lock_fds: SharedArrayBuffer; + // byte 1: fds_len + // byte 2: all wasi_farm_ref num + fds_len_and_num: SharedArrayBuffer; + fd_func_sig: SharedArrayBuffer; + base_func_util: SharedArrayBuffer; + + constructor( + allocator: AllocatorUseArrayBufferObject, + lock_fds: SharedArrayBuffer, + fds_len_and_num: SharedArrayBuffer, + fd_func_sig: SharedArrayBuffer, + base_func_util: SharedArrayBuffer, + fd_close_receiver: FdCloseSenderUseArrayBufferObject, + stdin: number | undefined, + stdout: number | undefined, + stderr: number | undefined, + default_fds: Array, + ) { + super( + stdin, + stdout, + stderr, + FdCloseSenderUseArrayBuffer.init_self(fd_close_receiver), + default_fds, + ); + this.allocator = AllocatorUseArrayBuffer.init_self(allocator); + this.lock_fds = lock_fds; + this.fd_func_sig = fd_func_sig; + this.base_func_util = base_func_util; + this.fds_len_and_num = fds_len_and_num; + + // console.log("fds_len_and_num", this.fds_len_and_num); + + // const view = new Int32Array(this.fds_len_and_num); + // Atomics.store(view, 0, 0); + } + + get_fds_len(): number { + const view = new Int32Array(this.fds_len_and_num); + return Atomics.load(view, 0); + } + + static init_self(sl: WASIFarmRefUseArrayBufferObject): WASIFarmRef { + return new WASIFarmRefUseArrayBuffer( + sl.allocator, + sl.lock_fds, + sl.fds_len_and_num, + sl.fd_func_sig, + sl.base_func_util, + sl.fd_close_receiver as unknown as FdCloseSenderUseArrayBufferObject, + sl.stdin, + sl.stdout, + sl.stderr, + sl.default_fds, + ); + } + + // allocate a new id on wasi_farm_ref and return it + set_id(): number { + const view = new Int32Array(this.fds_len_and_num); + const id = Atomics.add(view, 1, 1); + this.id = id; + return id; + } + + // lock base_func + private lock_base_func(): void { + const view = new Int32Array(this.base_func_util); + // eslint-disable-next-line no-constant-condition + while (true) { + const lock = Atomics.wait(view, 0, 1); + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old !== 0) { + continue; + } + break; + } + } + + // call base_func + private call_base_func(): void { + const view = new Int32Array(this.base_func_util); + const old = Atomics.exchange(view, 1, 1); + if (old !== 0) { + console.error("what happened?"); + } + Atomics.notify(view, 1, 1); + } + + // wait base_func + private wait_base_func(): void { + const view = new Int32Array(this.base_func_util); + const lock = Atomics.wait(view, 1, 1); + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + } + + // release base_func + private release_base_func(): void { + const view = new Int32Array(this.base_func_util); + Atomics.store(view, 0, 0); + Atomics.notify(view, 0, 1); + } + + // set park_fds_map + set_park_fds_map(fds: Array): void { + this.lock_base_func(); + const view = new Int32Array(this.base_func_util); + Atomics.store(view, 2, 0); + const fds_array = new Uint32Array(fds); + // console.log("fds_array", fds_array); + this.allocator.block_write(fds_array, this.base_func_util, 3); + Atomics.store(view, 5, this.id); + this.call_base_func(); + this.wait_base_func(); + this.release_base_func(); + } + + private lock_fd(fd: number) { + // console.log("lock_fd start", fd); + const view = new Int32Array(this.lock_fds, fd * 12); + // eslint-disable-next-line no-constant-condition + while (true) { + const now_value = Atomics.load(view, 0); + if (now_value !== 0) { + const value = Atomics.wait(view, 0, now_value); + if (value === "timed-out") { + console.error("lock_fd timed-out"); + continue; + } + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old === 0) { + // console.log("lock_fd success", fd); + return; + } + } + } + + private release_fd(fd: number) { + // console.log("release_fd", fd); + const view = new Int32Array(this.lock_fds, fd * 12); + Atomics.store(view, 0, 0); + Atomics.notify(view, 0, 1); + } + + private lock_double_fd(fd1: number, fd2: number) { + // console.log("lock_double_fd", fd1, fd2); + const view = new Int32Array(this.lock_fds); + // eslint-disable-next-line no-constant-condition + while (true) { + const now_value1 = Atomics.load(view, fd1 * 3); + const value = Atomics.wait(view, fd1 * 3, now_value1); + if (value === "timed-out") { + console.error("lock_double_fd timed-out"); + continue; + } + const old1 = Atomics.exchange(view, fd1 * 3, 2); + if (old1 === 0) { + const now_value2 = Atomics.load(view, fd2 * 3); + if (now_value2 === 2) { + // It's nearly deadlocked. + if (fd1 < fd2) { + // release fd1 + Atomics.store(view, fd1 * 3, 0); + Atomics.notify(view, fd1 * 3, 1); + continue; + } + } + const value = Atomics.wait(view, fd2 * 3, now_value2); + if (value === "timed-out") { + console.error("lock_double_fd timed-out"); + continue; + } + const old2 = Atomics.exchange(view, fd2 * 3, 2); + if (old2 === 0) { + return; + } + Atomics.store(view, fd1 * 3, 0); + Atomics.notify(view, fd1 * 3, 1); + } + } + } + + private release_double_fd(fd1: number, fd2: number) { + // console.log("release_double_fd", fd1, fd2); + const view = new Int32Array(this.lock_fds); + Atomics.store(view, fd1 * 3, 0); + Atomics.notify(view, fd1 * 3, 1); + Atomics.store(view, fd2 * 3, 0); + Atomics.notify(view, fd2 * 3, 1); + } + + private invoke_fd_func(fd: number): boolean { + if (fd === undefined) { + return false; + } + // console.log("invoke_fd_func", fd); + const view = new Int32Array(this.lock_fds, fd * 12 + 4); + const old = Atomics.exchange(view, 0, 1); + if (old === 1) { + console.error(`invoke_fd_func already invoked\nfd: ${fd}`); + return; + } + const n = Atomics.notify(view, 0); + if (n !== 1) { + if (n === 0) { + const len = this.get_fds_len(); + if (len <= fd) { + const lock = Atomics.exchange(view, 0, 0); + if (lock !== 1) { + console.error("what happened?"); + } + Atomics.notify(view, 0, 1); + console.error("what happened?: len", len, "fd", fd); + return true; + } + console.warn("invoke_func_loop is late"); + return true; + } + console.error("invoke_fd_func notify failed:", n); + return false; + } + return true; + } + + private wait_fd_func(fd: number) { + // console.log("wait_fd_func", fd); + const view = new Int32Array(this.lock_fds, fd * 12 + 4); + const value = Atomics.wait(view, 0, 1); + if (value === "timed-out") { + console.error("wait call park_fd_func timed-out"); + } + } + + private call_fd_func(fd: number): boolean { + if (!this.invoke_fd_func(fd)) { + return false; + } + // console.log("call_fd_func", fd); + this.wait_fd_func(fd); + // console.log("wait_fd_func", fd); + // console.log("call_fd_func released", fd); + return true; + } + + private get_error(fd: number): number { + const func_sig_view_i32 = new Int32Array( + this.fd_func_sig, + fd * fd_func_sig_bytes, + ); + const errno_offset = fd_func_sig_u32_size - 1; + // console.log("get_error: offset", errno_offset); + return Atomics.load(func_sig_view_i32, errno_offset); + } + + fd_advise(fd: number): number { + this.lock_fd(fd); + + const func_sig_view_u32 = new Uint32Array( + this.fd_func_sig, + fd * fd_func_sig_bytes, + ); + + Atomics.store(func_sig_view_u32, 0, 7); + Atomics.store(func_sig_view_u32, 1, fd); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + fd_allocate(fd: number, offset: bigint, len: bigint): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 8); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u64, 1, offset); + Atomics.store(func_sig_view_u64, 2, len); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + fd_close(fd: number): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 9); + Atomics.store(func_sig_view_u32, 1, fd); - // console.log("fd_close: ref", fd); + // console.log("fd_close: ref", fd); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } - // console.log("fd_close: ref2", fd); + // console.log("fd_close: ref2", fd); - const error = this.get_error(fd); + const error = this.get_error(fd); - this.release_fd(fd); + this.release_fd(fd); - // console.log("fd_close: ref3", fd); + // console.log("fd_close: ref3", fd); - return error; - } + return error; + } - fd_datasync(fd: number): number { - this.lock_fd(fd); + fd_datasync(fd: number): number { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - Atomics.store(func_sig_view_u32, 0, 10); - Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 0, 10); + Atomics.store(func_sig_view_u32, 1, fd); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - this.release_fd(fd); + this.release_fd(fd); - return error; - } + return error; + } - fd_fdstat_get(fd: number): [wasi.Fdstat | undefined, number] { - this.lock_fd(fd); + fd_fdstat_get(fd: number): [wasi.Fdstat | undefined, number] { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); - Atomics.store(func_sig_view_u32, 0, 11); - Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 0, 11); + Atomics.store(func_sig_view_u32, 1, fd); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - if (error !== wasi.ERRNO_SUCCESS) { - this.release_fd(fd); - return [undefined, error]; - } + if (error !== wasi.ERRNO_SUCCESS) { + this.release_fd(fd); + return [undefined, error]; + } - const fs_filetype = Atomics.load(func_sig_view_u8, 0); - const fs_flags = Atomics.load(func_sig_view_u16, 2); - const fs_rights_base = Atomics.load(func_sig_view_u64, 1); - const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 2); + const fs_filetype = Atomics.load(func_sig_view_u8, 0); + const fs_flags = Atomics.load(func_sig_view_u16, 2); + const fs_rights_base = Atomics.load(func_sig_view_u64, 1); + const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 2); - this.release_fd(fd); + this.release_fd(fd); - const fd_stat = new wasi.Fdstat(fs_filetype, fs_flags); - fd_stat.fs_rights_base = fs_rights_base; - fd_stat.fs_rights_inherited = fs_rights_inheriting; + const fd_stat = new wasi.Fdstat(fs_filetype, fs_flags); + fd_stat.fs_rights_base = fs_rights_base; + fd_stat.fs_rights_inherited = fs_rights_inheriting; - return [fd_stat, error]; - } + return [fd_stat, error]; + } - fd_fdstat_set_flags(fd: number, flags: number): number { - this.lock_fd(fd); + fd_fdstat_set_flags(fd: number, flags: number): number { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - Atomics.store(func_sig_view_u32, 0, 12); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u16, 4, flags); + Atomics.store(func_sig_view_u32, 0, 12); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u16, 4, flags); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - this.release_fd(fd); + this.release_fd(fd); - return error; - } + return error; + } - fd_fdstat_set_rights( - fd: number, - fs_rights_base: bigint, - fs_rights_inheriting: bigint, - ): number { - this.lock_fd(fd); + fd_fdstat_set_rights( + fd: number, + fs_rights_base: bigint, + fs_rights_inheriting: bigint, + ): number { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); - Atomics.store(func_sig_view_u32, 0, 13); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u64, 1, fs_rights_base); - Atomics.store(func_sig_view_u64, 2, fs_rights_inheriting); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - fd_filestat_get(fd: number): [wasi.Filestat | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 14); - Atomics.store(func_sig_view_u32, 1, fd); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - if (error !== wasi.ERRNO_SUCCESS) { - this.release_fd(fd); - return [undefined, error]; - } - - const fs_dev = Atomics.load(func_sig_view_u64, 0); - const fs_ino = Atomics.load(func_sig_view_u64, 1); - const fs_filetype = Atomics.load(func_sig_view_u8, 16); - const fs_nlink = Atomics.load(func_sig_view_u64, 3); - const fs_size = Atomics.load(func_sig_view_u64, 4); - const fs_atim = Atomics.load(func_sig_view_u64, 5); - const fs_mtim = Atomics.load(func_sig_view_u64, 6); - const fs_ctim = Atomics.load(func_sig_view_u64, 7); - - this.release_fd(fd); - - const file_stat = new wasi.Filestat(fs_filetype, fs_size); - file_stat.dev = fs_dev; - file_stat.ino = fs_ino; - file_stat.nlink = fs_nlink; - file_stat.atim = fs_atim; - file_stat.mtim = fs_mtim; - file_stat.ctim = fs_ctim; - - return [file_stat, error]; - } - - fd_filestat_set_size(fd: number, size: bigint): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 15); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u64, 1, size); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - fd_filestat_set_times( - fd: number, - st_atim: bigint, - st_mtim: bigint, - fst_flags: number, - ): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 16); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u64, 1, st_atim); - Atomics.store(func_sig_view_u64, 2, st_mtim); - Atomics.store(func_sig_view_u16, 12, fst_flags); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - fd_pread( - fd: number, - iovs: Uint32Array, - offset: bigint, - ): [[number, Uint8Array] | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 17); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - iovs, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - Atomics.store(func_sig_view_u64, 2, offset); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - const nread = Atomics.load(func_sig_view_u32, 0); - const buf_ptr = Atomics.load(func_sig_view_u32, 1); - const buf_len = Atomics.load(func_sig_view_u32, 2); - this.release_fd(fd); - - if (error === wasi.ERRNO_BADF) { - this.allocator.free(buf_ptr, buf_len); - return [undefined, error]; - } - - const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len)); - - if (nread !== buf_len) { - console.error("pread nread !== buf_len"); - } - - this.allocator.free(buf_ptr, buf_len); - - return [[nread, buf], error]; - } - - fd_prestat_get(fd: number): [[number, number] | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 18); - Atomics.store(func_sig_view_u32, 1, fd); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - if (error !== wasi.ERRNO_SUCCESS) { - this.release_fd(fd); - return [undefined, error]; - } - - const pr_tag = Atomics.load(func_sig_view_u32, 0); - const pr_name_len = Atomics.load(func_sig_view_u32, 1); - - this.release_fd(fd); - - return [[pr_tag, pr_name_len], error]; - } - - fd_prestat_dir_name( - fd: number, - path_len: number, - ): [Uint8Array | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 19); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u32, 2, path_len); - - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - const ret_path_ptr = Atomics.load(func_sig_view_u32, 0); - const ret_path_len = Atomics.load(func_sig_view_u32, 1); - - this.release_fd(fd); - if (error !== wasi.ERRNO_SUCCESS && error !== wasi.ERRNO_NAMETOOLONG) { - this.allocator.free(ret_path_ptr, ret_path_len); - return [undefined, error]; - } - - const ret_path = new Uint8Array( - this.allocator.get_memory(ret_path_ptr, ret_path_len), - ); - this.allocator.free(ret_path_ptr, ret_path_len); - - return [ret_path, error]; - } + Atomics.store(func_sig_view_u32, 0, 13); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u64, 1, fs_rights_base); + Atomics.store(func_sig_view_u64, 2, fs_rights_inheriting); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + fd_filestat_get(fd: number): [wasi.Filestat | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 14); + Atomics.store(func_sig_view_u32, 1, fd); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + if (error !== wasi.ERRNO_SUCCESS) { + this.release_fd(fd); + return [undefined, error]; + } + + const fs_dev = Atomics.load(func_sig_view_u64, 0); + const fs_ino = Atomics.load(func_sig_view_u64, 1); + const fs_filetype = Atomics.load(func_sig_view_u8, 16); + const fs_nlink = Atomics.load(func_sig_view_u64, 3); + const fs_size = Atomics.load(func_sig_view_u64, 4); + const fs_atim = Atomics.load(func_sig_view_u64, 5); + const fs_mtim = Atomics.load(func_sig_view_u64, 6); + const fs_ctim = Atomics.load(func_sig_view_u64, 7); + + this.release_fd(fd); + + const file_stat = new wasi.Filestat(fs_filetype, fs_size); + file_stat.dev = fs_dev; + file_stat.ino = fs_ino; + file_stat.nlink = fs_nlink; + file_stat.atim = fs_atim; + file_stat.mtim = fs_mtim; + file_stat.ctim = fs_ctim; + + return [file_stat, error]; + } + + fd_filestat_set_size(fd: number, size: bigint): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 15); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u64, 1, size); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + fd_filestat_set_times( + fd: number, + st_atim: bigint, + st_mtim: bigint, + fst_flags: number, + ): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 16); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u64, 1, st_atim); + Atomics.store(func_sig_view_u64, 2, st_mtim); + Atomics.store(func_sig_view_u16, 12, fst_flags); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + fd_pread( + fd: number, + iovs: Uint32Array, + offset: bigint, + ): [[number, Uint8Array] | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 17); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + iovs, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + Atomics.store(func_sig_view_u64, 2, offset); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + const nread = Atomics.load(func_sig_view_u32, 0); + const buf_ptr = Atomics.load(func_sig_view_u32, 1); + const buf_len = Atomics.load(func_sig_view_u32, 2); + this.release_fd(fd); + + if (error === wasi.ERRNO_BADF) { + this.allocator.free(buf_ptr, buf_len); + return [undefined, error]; + } + + const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len)); + + if (nread !== buf_len) { + console.error("pread nread !== buf_len"); + } + + this.allocator.free(buf_ptr, buf_len); + + return [[nread, buf], error]; + } + + fd_prestat_get(fd: number): [[number, number] | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 18); + Atomics.store(func_sig_view_u32, 1, fd); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + if (error !== wasi.ERRNO_SUCCESS) { + this.release_fd(fd); + return [undefined, error]; + } + + const pr_tag = Atomics.load(func_sig_view_u32, 0); + const pr_name_len = Atomics.load(func_sig_view_u32, 1); + + this.release_fd(fd); + + return [[pr_tag, pr_name_len], error]; + } + + fd_prestat_dir_name( + fd: number, + path_len: number, + ): [Uint8Array | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 19); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 2, path_len); + + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + const ret_path_ptr = Atomics.load(func_sig_view_u32, 0); + const ret_path_len = Atomics.load(func_sig_view_u32, 1); + + this.release_fd(fd); + if (error !== wasi.ERRNO_SUCCESS && error !== wasi.ERRNO_NAMETOOLONG) { + this.allocator.free(ret_path_ptr, ret_path_len); + return [undefined, error]; + } + + const ret_path = new Uint8Array( + this.allocator.get_memory(ret_path_ptr, ret_path_len), + ); + this.allocator.free(ret_path_ptr, ret_path_len); + + return [ret_path, error]; + } - fd_pwrite( - fd: number, - write_data: Uint8Array, - offset: bigint, - ): [number | undefined, number] { - this.lock_fd(fd); + fd_pwrite( + fd: number, + write_data: Uint8Array, + offset: bigint, + ): [number | undefined, number] { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); - Atomics.store(func_sig_view_u32, 0, 20); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - write_data, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - Atomics.store(func_sig_view_u64, 2, offset); + Atomics.store(func_sig_view_u32, 0, 20); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + write_data, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + Atomics.store(func_sig_view_u64, 2, offset); - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - if (error === wasi.ERRNO_BADF) { - this.release_fd(fd); - return [undefined, error]; - } - - const nwritten = Atomics.load(func_sig_view_u32, 0); - - this.release_fd(fd); - - return [nwritten, error]; - } - - fd_read( - fd: number, - iovs: Uint32Array, - ): [[number, Uint8Array] | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 21); - Atomics.store(func_sig_view_u32, 1, fd); - - // console.log("fd_read: ref: iovs", iovs); - // console.log("iovs.buffer", iovs.buffer.slice(0, iovs.byteLength)); - - const [ptr, len] = this.allocator.block_write( - iovs, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - - // console.log("fd_read: ref: iovs", iovs); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - const nread = Atomics.load(func_sig_view_u32, 0); - const buf_ptr = Atomics.load(func_sig_view_u32, 1); - const buf_len = Atomics.load(func_sig_view_u32, 2); - this.release_fd(fd); - - // console.log("fd_read: ref: ", nread, buf_ptr, buf_len); - - if (error === wasi.ERRNO_BADF) { - this.allocator.free(buf_ptr, buf_len); - return [undefined, error]; - } - - // fd_read: ref: 14 30 14 - // animals.ts:325 fd_read: nread 14 Hello, world! - // fd_read: ref: 21 52 32 - // ref.ts:655 fd_read: ref: 21 - const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len)); - // console.log("fd_read: ref: ", nread, new TextDecoder().decode(buf)); - - // console.log("fd_read: nread", nread, new TextDecoder().decode(buf)); - - if (nread !== buf_len) { - console.error("read nread !== buf_len"); - } - - this.allocator.free(buf_ptr, buf_len); - - return [[nread, buf], error]; - } - - fd_readdir( - fd: number, - limit_buf_len: number, - cookie: bigint, - ): [[Uint8Array, number] | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); + if (error === wasi.ERRNO_BADF) { + this.release_fd(fd); + return [undefined, error]; + } + + const nwritten = Atomics.load(func_sig_view_u32, 0); + + this.release_fd(fd); + + return [nwritten, error]; + } + + fd_read( + fd: number, + iovs: Uint32Array, + ): [[number, Uint8Array] | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 21); + Atomics.store(func_sig_view_u32, 1, fd); + + // console.log("fd_read: ref: iovs", iovs); + // console.log("iovs.buffer", iovs.buffer.slice(0, iovs.byteLength)); + + const [ptr, len] = this.allocator.block_write( + iovs, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + + // console.log("fd_read: ref: iovs", iovs); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + const nread = Atomics.load(func_sig_view_u32, 0); + const buf_ptr = Atomics.load(func_sig_view_u32, 1); + const buf_len = Atomics.load(func_sig_view_u32, 2); + this.release_fd(fd); + + // console.log("fd_read: ref: ", nread, buf_ptr, buf_len); + + if (error === wasi.ERRNO_BADF) { + this.allocator.free(buf_ptr, buf_len); + return [undefined, error]; + } + + // fd_read: ref: 14 30 14 + // animals.ts:325 fd_read: nread 14 Hello, world! + // fd_read: ref: 21 52 32 + // ref.ts:655 fd_read: ref: 21 + const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len)); + // console.log("fd_read: ref: ", nread, new TextDecoder().decode(buf)); + + // console.log("fd_read: nread", nread, new TextDecoder().decode(buf)); + + if (nread !== buf_len) { + console.error("read nread !== buf_len"); + } + + this.allocator.free(buf_ptr, buf_len); + + return [[nread, buf], error]; + } + + fd_readdir( + fd: number, + limit_buf_len: number, + cookie: bigint, + ): [[Uint8Array, number] | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); - Atomics.store(func_sig_view_u32, 0, 22); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u32, 2, limit_buf_len); - Atomics.store(func_sig_view_u64, 2, cookie); + Atomics.store(func_sig_view_u32, 0, 22); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 2, limit_buf_len); + Atomics.store(func_sig_view_u64, 2, cookie); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - const buf_ptr = Atomics.load(func_sig_view_u32, 0); - const buf_len = Atomics.load(func_sig_view_u32, 1); - const buf_used = Atomics.load(func_sig_view_u32, 2); - this.release_fd(fd); + const buf_ptr = Atomics.load(func_sig_view_u32, 0); + const buf_len = Atomics.load(func_sig_view_u32, 1); + const buf_used = Atomics.load(func_sig_view_u32, 2); + this.release_fd(fd); - if (error === wasi.ERRNO_BADF) { - this.allocator.free(buf_ptr, buf_len); - return [undefined, error]; - } + if (error === wasi.ERRNO_BADF) { + this.allocator.free(buf_ptr, buf_len); + return [undefined, error]; + } - const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len)); + const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len)); - this.allocator.free(buf_ptr, buf_len); + this.allocator.free(buf_ptr, buf_len); - return [[buf, buf_used], error]; - } + return [[buf, buf_used], error]; + } - // fd_renumber( - // fd: number, - // to: number, - // ): number { - // this.lock_double_fd(fd, to); + // fd_renumber( + // fd: number, + // to: number, + // ): number { + // this.lock_double_fd(fd, to); - // const bytes_offset = fd * fd_func_sig_bytes; - // const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + // const bytes_offset = fd * fd_func_sig_bytes; + // const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - // // fd - // Atomics.store(func_sig_view_u32, 0, 23); - // Atomics.store(func_sig_view_u32, 1, fd); - // Atomics.store(func_sig_view_u32, 2, to); + // // fd + // Atomics.store(func_sig_view_u32, 0, 23); + // Atomics.store(func_sig_view_u32, 1, fd); + // Atomics.store(func_sig_view_u32, 2, to); - // if (!this.call_fd_func(fd)) { - // this.release_fd(fd); - // return wasi.ERRNO_BADF; - // } + // if (!this.call_fd_func(fd)) { + // this.release_fd(fd); + // return wasi.ERRNO_BADF; + // } - // const error = this.get_error(fd); + // const error = this.get_error(fd); - // this.release_double_fd(fd, to); + // this.release_double_fd(fd, to); - // return error; - // } + // return error; + // } - fd_seek( - fd: number, - offset: bigint, - whence: number, - ): [bigint | undefined, number] { - this.lock_fd(fd); + fd_seek( + fd: number, + offset: bigint, + whence: number, + ): [bigint | undefined, number] { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); - Atomics.store(func_sig_view_u32, 0, 24); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u64, 1, offset); - Atomics.store(func_sig_view_u8, 16, whence); + Atomics.store(func_sig_view_u32, 0, 24); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u64, 1, offset); + Atomics.store(func_sig_view_u8, 16, whence); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - if (error === wasi.ERRNO_BADF) { - this.release_fd(fd); - return [undefined, error]; - } + if (error === wasi.ERRNO_BADF) { + this.release_fd(fd); + return [undefined, error]; + } - const new_offset = Atomics.load(func_sig_view_u64, 0); + const new_offset = Atomics.load(func_sig_view_u64, 0); - this.release_fd(fd); + this.release_fd(fd); - return [new_offset, error]; - } + return [new_offset, error]; + } - fd_sync(fd: number): number { - this.lock_fd(fd); + fd_sync(fd: number): number { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - Atomics.store(func_sig_view_u32, 0, 25); - Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 0, 25); + Atomics.store(func_sig_view_u32, 1, fd); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return wasi.ERRNO_BADF; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return wasi.ERRNO_BADF; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - this.release_fd(fd); + this.release_fd(fd); - return error; - } + return error; + } - fd_tell(fd: number): [bigint | undefined, number] { - this.lock_fd(fd); + fd_tell(fd: number): [bigint | undefined, number] { + this.lock_fd(fd); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); - Atomics.store(func_sig_view_u32, 0, 26); - Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 0, 26); + Atomics.store(func_sig_view_u32, 1, fd); - if (!this.call_fd_func(fd)) { - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } + if (!this.call_fd_func(fd)) { + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - if (error === wasi.ERRNO_BADF) { - this.release_fd(fd); - return [undefined, error]; - } + if (error === wasi.ERRNO_BADF) { + this.release_fd(fd); + return [undefined, error]; + } - const offset = Atomics.load(func_sig_view_u64, 0); + const offset = Atomics.load(func_sig_view_u64, 0); - this.release_fd(fd); + this.release_fd(fd); - return [offset, error]; - } + return [offset, error]; + } - fd_write(fd: number, write_data: Uint8Array): [number | undefined, number] { - this.lock_fd(fd); + fd_write(fd: number, write_data: Uint8Array): [number | undefined, number] { + this.lock_fd(fd); - // console.log("fd_write: ref: write_data", new TextDecoder().decode(write_data)); + // console.log("fd_write: ref: write_data", new TextDecoder().decode(write_data)); - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - Atomics.store(func_sig_view_u32, 0, 27); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - write_data, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); + Atomics.store(func_sig_view_u32, 0, 27); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + write_data, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); - if (!this.call_fd_func(fd)) { - // console.log("fd_write: ref: error", "wasi.ERRNO_BADF"); + if (!this.call_fd_func(fd)) { + // console.log("fd_write: ref: error", "wasi.ERRNO_BADF"); - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } - const error = this.get_error(fd); + const error = this.get_error(fd); - // console.log("fd_write: ref: error", this.get_error(fd)); + // console.log("fd_write: ref: error", this.get_error(fd)); - // console.log("fd_write: ref: error", error); + // console.log("fd_write: ref: error", error); - if (error === wasi.ERRNO_BADF) { - this.release_fd(fd); - return [undefined, error]; - } + if (error === wasi.ERRNO_BADF) { + this.release_fd(fd); + return [undefined, error]; + } - const nwritten = Atomics.load(func_sig_view_u32, 0); + const nwritten = Atomics.load(func_sig_view_u32, 0); - this.release_fd(fd); + this.release_fd(fd); - return [nwritten, error]; - } + return [nwritten, error]; + } - path_create_directory(fd: number, path: Uint8Array): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 28); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - path_filestat_get( - fd: number, - flags: number, - path: Uint8Array, - ): [wasi.Filestat | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 29); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u32, 2, flags); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 3, - ); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - if (error !== wasi.ERRNO_SUCCESS) { - this.release_fd(fd); - return [undefined, error]; - } - - const fs_dev = Atomics.load(func_sig_view_u64, 0); - const fs_ino = Atomics.load(func_sig_view_u64, 1); - const fs_filetype = Atomics.load(func_sig_view_u8, 16); - const fs_nlink = Atomics.load(func_sig_view_u64, 3); - const fs_size = Atomics.load(func_sig_view_u64, 4); - const fs_atim = Atomics.load(func_sig_view_u64, 5); - const fs_mtim = Atomics.load(func_sig_view_u64, 6); - const fs_ctim = Atomics.load(func_sig_view_u64, 7); - - this.release_fd(fd); - - const file_stat = new wasi.Filestat(fs_filetype, fs_size); - file_stat.dev = fs_dev; - file_stat.ino = fs_ino; - file_stat.nlink = fs_nlink; - file_stat.atim = fs_atim; - file_stat.mtim = fs_mtim; - file_stat.ctim = fs_ctim; - - return [file_stat, error]; - } - - path_filestat_set_times( - fd: number, - flags: number, - path: Uint8Array, - st_atim: bigint, - st_mtim: bigint, - fst_flags: number, - ): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 30); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u32, 2, flags); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 3, - ); - Atomics.store(func_sig_view_u64, 3, st_atim); - Atomics.store(func_sig_view_u64, 4, st_mtim); - Atomics.store(func_sig_view_u16, 12, fst_flags); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - path_link( - old_fd: number, - old_flags: number, - old_path: Uint8Array, - new_fd: number, - new_path: Uint8Array, - ): number { - this.lock_double_fd(old_fd, new_fd); - - const bytes_offset = old_fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 31); - Atomics.store(func_sig_view_u32, 1, old_fd); - Atomics.store(func_sig_view_u32, 2, old_flags); - const [ptr1, len1] = this.allocator.block_write( - old_path, - this.fd_func_sig, - old_fd * fd_func_sig_u32_size + 3, - ); - Atomics.store(func_sig_view_u32, 5, new_fd); - const [ptr2, len2] = this.allocator.block_write( - new_path, - this.fd_func_sig, - old_fd * fd_func_sig_u32_size + 6, - ); - - if (!this.call_fd_func(old_fd)) { - this.allocator.free(ptr1, len1); - this.allocator.free(ptr2, len2); - this.release_double_fd(old_fd, new_fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(old_fd); - - this.release_double_fd(old_fd, new_fd); - - return error; - } - - path_open( - fd: number, - dirflags: number, - path: Uint8Array, - oflags: number, - fs_rights_base: bigint, - fs_rights_inheriting: bigint, - fs_flags: number, - ): [number | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - const func_sig_view_u64 = new BigUint64Array( - this.fd_func_sig, - bytes_offset, - ); - - Atomics.store(func_sig_view_u32, 0, 32); - Atomics.store(func_sig_view_u32, 1, fd); - Atomics.store(func_sig_view_u32, 2, dirflags); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 3, - ); - Atomics.store(func_sig_view_u32, 5, oflags); - Atomics.store(func_sig_view_u64, 3, fs_rights_base); - Atomics.store(func_sig_view_u64, 4, fs_rights_inheriting); - Atomics.store(func_sig_view_u16, 20, fs_flags); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - if (error === wasi.ERRNO_SUCCESS) { - const new_fd = Atomics.load(func_sig_view_u32, 0); - this.release_fd(fd); - return [new_fd, error]; - } - - this.release_fd(fd); - - return [undefined, error]; - } - - path_readlink( - fd: number, - path: Uint8Array, - buf_len: number, - ): [Uint8Array | undefined, number] { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 33); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - Atomics.store(func_sig_view_u32, 4, buf_len); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return [undefined, wasi.ERRNO_BADF]; - } - - const error = this.get_error(fd); - - const nread = Atomics.load(func_sig_view_u32, 0); - const ret_path_ptr = Atomics.load(func_sig_view_u32, 1); - const ret_path_len = Atomics.load(func_sig_view_u32, 2); - - this.release_fd(fd); - if (error !== wasi.ERRNO_SUCCESS && error !== wasi.ERRNO_NAMETOOLONG) { - this.allocator.free(ret_path_ptr, ret_path_len); - return [undefined, error]; - } - - const ret_path = new Uint8Array( - this.allocator.get_memory(ret_path_ptr, ret_path_len), - ); - const ret_path_slice = ret_path.slice(0, nread); - - return [ret_path_slice, error]; - } - - path_remove_directory(fd: number, path: Uint8Array): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 34); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - path_rename( - old_fd: number, - old_path: Uint8Array, - new_fd: number, - new_path: Uint8Array, - ): number { - this.lock_double_fd(old_fd, new_fd); - - const bytes_offset = old_fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 35); - Atomics.store(func_sig_view_u32, 1, old_fd); - const [ptr1, len1] = this.allocator.block_write( - old_path, - this.fd_func_sig, - old_fd * fd_func_sig_u32_size + 2, - ); - Atomics.store(func_sig_view_u32, 4, new_fd); - const [ptr2, len2] = this.allocator.block_write( - new_path, - this.fd_func_sig, - old_fd * fd_func_sig_u32_size + 5, - ); - - if (!this.call_fd_func(old_fd)) { - this.allocator.free(ptr1, len1); - this.allocator.free(ptr2, len2); - this.release_double_fd(old_fd, new_fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(old_fd); - - this.release_double_fd(old_fd, new_fd); - - return error; - } - - path_symlink(old_path: Uint8Array, fd: number, new_path: Uint8Array): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 36); - const [ptr1, len1] = this.allocator.block_write( - old_path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 1, - ); - Atomics.store(func_sig_view_u32, 3, fd); - const [ptr2, len2] = this.allocator.block_write( - new_path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 4, - ); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr1, len1); - this.allocator.free(ptr2, len2); - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } - - path_unlink_file(fd: number, path: Uint8Array): number { - this.lock_fd(fd); - - const bytes_offset = fd * fd_func_sig_bytes; - const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); - - Atomics.store(func_sig_view_u32, 0, 37); - Atomics.store(func_sig_view_u32, 1, fd); - const [ptr, len] = this.allocator.block_write( - path, - this.fd_func_sig, - fd * fd_func_sig_u32_size + 2, - ); - - if (!this.call_fd_func(fd)) { - this.allocator.free(ptr, len); - this.release_fd(fd); - return wasi.ERRNO_BADF; - } - - const error = this.get_error(fd); - - this.release_fd(fd); - - return error; - } + path_create_directory(fd: number, path: Uint8Array): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 28); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + path_filestat_get( + fd: number, + flags: number, + path: Uint8Array, + ): [wasi.Filestat | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 29); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 2, flags); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 3, + ); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + if (error !== wasi.ERRNO_SUCCESS) { + this.release_fd(fd); + return [undefined, error]; + } + + const fs_dev = Atomics.load(func_sig_view_u64, 0); + const fs_ino = Atomics.load(func_sig_view_u64, 1); + const fs_filetype = Atomics.load(func_sig_view_u8, 16); + const fs_nlink = Atomics.load(func_sig_view_u64, 3); + const fs_size = Atomics.load(func_sig_view_u64, 4); + const fs_atim = Atomics.load(func_sig_view_u64, 5); + const fs_mtim = Atomics.load(func_sig_view_u64, 6); + const fs_ctim = Atomics.load(func_sig_view_u64, 7); + + this.release_fd(fd); + + const file_stat = new wasi.Filestat(fs_filetype, fs_size); + file_stat.dev = fs_dev; + file_stat.ino = fs_ino; + file_stat.nlink = fs_nlink; + file_stat.atim = fs_atim; + file_stat.mtim = fs_mtim; + file_stat.ctim = fs_ctim; + + return [file_stat, error]; + } + + path_filestat_set_times( + fd: number, + flags: number, + path: Uint8Array, + st_atim: bigint, + st_mtim: bigint, + fst_flags: number, + ): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 30); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 2, flags); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 3, + ); + Atomics.store(func_sig_view_u64, 3, st_atim); + Atomics.store(func_sig_view_u64, 4, st_mtim); + Atomics.store(func_sig_view_u16, 12, fst_flags); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + path_link( + old_fd: number, + old_flags: number, + old_path: Uint8Array, + new_fd: number, + new_path: Uint8Array, + ): number { + this.lock_double_fd(old_fd, new_fd); + + const bytes_offset = old_fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 31); + Atomics.store(func_sig_view_u32, 1, old_fd); + Atomics.store(func_sig_view_u32, 2, old_flags); + const [ptr1, len1] = this.allocator.block_write( + old_path, + this.fd_func_sig, + old_fd * fd_func_sig_u32_size + 3, + ); + Atomics.store(func_sig_view_u32, 5, new_fd); + const [ptr2, len2] = this.allocator.block_write( + new_path, + this.fd_func_sig, + old_fd * fd_func_sig_u32_size + 6, + ); + + if (!this.call_fd_func(old_fd)) { + this.allocator.free(ptr1, len1); + this.allocator.free(ptr2, len2); + this.release_double_fd(old_fd, new_fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(old_fd); + + this.release_double_fd(old_fd, new_fd); + + return error; + } + + path_open( + fd: number, + dirflags: number, + path: Uint8Array, + oflags: number, + fs_rights_base: bigint, + fs_rights_inheriting: bigint, + fs_flags: number, + ): [number | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + const func_sig_view_u64 = new BigUint64Array( + this.fd_func_sig, + bytes_offset, + ); + + Atomics.store(func_sig_view_u32, 0, 32); + Atomics.store(func_sig_view_u32, 1, fd); + Atomics.store(func_sig_view_u32, 2, dirflags); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 3, + ); + Atomics.store(func_sig_view_u32, 5, oflags); + Atomics.store(func_sig_view_u64, 3, fs_rights_base); + Atomics.store(func_sig_view_u64, 4, fs_rights_inheriting); + Atomics.store(func_sig_view_u16, 20, fs_flags); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + if (error === wasi.ERRNO_SUCCESS) { + const new_fd = Atomics.load(func_sig_view_u32, 0); + this.release_fd(fd); + return [new_fd, error]; + } + + this.release_fd(fd); + + return [undefined, error]; + } + + path_readlink( + fd: number, + path: Uint8Array, + buf_len: number, + ): [Uint8Array | undefined, number] { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 33); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + Atomics.store(func_sig_view_u32, 4, buf_len); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return [undefined, wasi.ERRNO_BADF]; + } + + const error = this.get_error(fd); + + const nread = Atomics.load(func_sig_view_u32, 0); + const ret_path_ptr = Atomics.load(func_sig_view_u32, 1); + const ret_path_len = Atomics.load(func_sig_view_u32, 2); + + this.release_fd(fd); + if (error !== wasi.ERRNO_SUCCESS && error !== wasi.ERRNO_NAMETOOLONG) { + this.allocator.free(ret_path_ptr, ret_path_len); + return [undefined, error]; + } + + const ret_path = new Uint8Array( + this.allocator.get_memory(ret_path_ptr, ret_path_len), + ); + const ret_path_slice = ret_path.slice(0, nread); + + return [ret_path_slice, error]; + } + + path_remove_directory(fd: number, path: Uint8Array): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 34); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + path_rename( + old_fd: number, + old_path: Uint8Array, + new_fd: number, + new_path: Uint8Array, + ): number { + this.lock_double_fd(old_fd, new_fd); + + const bytes_offset = old_fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 35); + Atomics.store(func_sig_view_u32, 1, old_fd); + const [ptr1, len1] = this.allocator.block_write( + old_path, + this.fd_func_sig, + old_fd * fd_func_sig_u32_size + 2, + ); + Atomics.store(func_sig_view_u32, 4, new_fd); + const [ptr2, len2] = this.allocator.block_write( + new_path, + this.fd_func_sig, + old_fd * fd_func_sig_u32_size + 5, + ); + + if (!this.call_fd_func(old_fd)) { + this.allocator.free(ptr1, len1); + this.allocator.free(ptr2, len2); + this.release_double_fd(old_fd, new_fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(old_fd); + + this.release_double_fd(old_fd, new_fd); + + return error; + } + + path_symlink(old_path: Uint8Array, fd: number, new_path: Uint8Array): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 36); + const [ptr1, len1] = this.allocator.block_write( + old_path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 1, + ); + Atomics.store(func_sig_view_u32, 3, fd); + const [ptr2, len2] = this.allocator.block_write( + new_path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 4, + ); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr1, len1); + this.allocator.free(ptr2, len2); + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } + + path_unlink_file(fd: number, path: Uint8Array): number { + this.lock_fd(fd); + + const bytes_offset = fd * fd_func_sig_bytes; + const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset); + + Atomics.store(func_sig_view_u32, 0, 37); + Atomics.store(func_sig_view_u32, 1, fd); + const [ptr, len] = this.allocator.block_write( + path, + this.fd_func_sig, + fd * fd_func_sig_u32_size + 2, + ); + + if (!this.call_fd_func(fd)) { + this.allocator.free(ptr, len); + this.release_fd(fd); + return wasi.ERRNO_BADF; + } + + const error = this.get_error(fd); + + this.release_fd(fd); + + return error; + } } diff --git a/src/wasi_farm/shared_array_buffer/sender.ts b/src/wasi_farm/shared_array_buffer/sender.ts index 46db0c9..252e36b 100644 --- a/src/wasi_farm/shared_array_buffer/sender.ts +++ b/src/wasi_farm/shared_array_buffer/sender.ts @@ -1,225 +1,221 @@ export type ToRefSenderUseArrayBufferObject = { - data_size: number; - share_arrays_memory?: SharedArrayBuffer; + data_size: number; + share_arrays_memory?: SharedArrayBuffer; }; // To ref sender abstract class export abstract class ToRefSenderUseArrayBuffer { - // The structure is similar to an allocator, but the mechanism is different - - // Example of fd management - // This needs to be handled - // 1. Start of path_open - // 2. Removed by fd_close - // 2.1 Sent by ToRefSender - // 3. Reassigned by path_open - // < Closed by ToRefSender - // 3.1 The person who opened it can use it - // < Closed by ToRefSender — this alone will cause a bug - // Structurally, this shouldn't happen in the farm - - // In the end, when receiving from this function, it should be done on the first call of each function - - // The first 4 bytes are for lock value: i32 - // The next 4 bytes are the current number of data: m: i32 - // The next 4 bytes are the length of the area used by share_arrays_memory: n: i32 - // Data header - // 4 bytes: remaining target count - // 4 bytes: target count (n) - // n * 4 bytes: target allocation numbers - // Data - // data_size bytes: data - private share_arrays_memory: SharedArrayBuffer; - - // The size of the data - private data_size: number; - - constructor( - // data is Uint32Array - // and data_size is data.length - data_size: number, - max_share_arrays_memory: number = 100 * 1024, - share_arrays_memory?: SharedArrayBuffer, - ) { - this.data_size = data_size; - if (share_arrays_memory) { - this.share_arrays_memory = share_arrays_memory; - } else { - this.share_arrays_memory = new SharedArrayBuffer(max_share_arrays_memory); - } - const view = new Int32Array(this.share_arrays_memory); - Atomics.store(view, 0, 0); - Atomics.store(view, 1, 0); - Atomics.store(view, 2, 12); - } - - protected static init_self_inner(sl: ToRefSenderUseArrayBufferObject): { - data_size: number; - max_share_arrays_memory: number; - share_arrays_memory: SharedArrayBuffer; - } { - return { - data_size: sl.data_size, - max_share_arrays_memory: sl.share_arrays_memory.byteLength, - share_arrays_memory: sl.share_arrays_memory, - }; - } - - private async async_lock(): Promise { - const view = new Int32Array(this.share_arrays_memory); - // eslint-disable-next-line no-constant-condition - while (true) { - let lock: "not-equal" | "timed-out" | "ok"; - const { value } = Atomics.waitAsync(view, 0, 1); - if (value instanceof Promise) { - lock = await value; - } else { - lock = value; - } - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old !== 0) { - continue; - } - break; - } - } - - private block_lock(): void { - // eslint-disable-next-line no-constant-condition - while (true) { - const view = new Int32Array(this.share_arrays_memory); - const lock = Atomics.wait(view, 0, 1); - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old !== 0) { - continue; - } - break; - } - } - - private release_lock(): void { - const view = new Int32Array(this.share_arrays_memory); - Atomics.store(view, 0, 0); - Atomics.notify(view, 0, 1); - } - - protected async async_send( - targets: Array, - data: Uint32Array, - ): Promise { - await this.async_lock(); - - const view = new Int32Array(this.share_arrays_memory); - const used_len = Atomics.load(view, 2); - const data_len = data.byteLength; - if (data_len !== this.data_size) { - throw new Error( - `invalid data size: ${data_len} !== ${this.data_size}`, - ); - } - const new_used_len = used_len + data_len + 8 + targets.length * 4; - if (new_used_len > this.share_arrays_memory.byteLength) { - throw new Error("over memory"); - } - - Atomics.store(view, 2, new_used_len); - - const header = new Int32Array(this.share_arrays_memory, used_len); - header[0] = targets.length; - header[1] = targets.length; - header.set(targets, 2); - - const data_view = new Uint32Array( - this.share_arrays_memory, - used_len + 8 + targets.length * 4, - ); - data_view.set(data); - - // console.log("async_send send", targets, data); - - Atomics.add(view, 1, 1); - - this.release_lock(); - } - - protected get_data(id: number): Array | undefined { - const view = new Int32Array(this.share_arrays_memory); - const data_num_tmp = Atomics.load(view, 1); - if (data_num_tmp === 0) { - return undefined; - } - - this.block_lock(); - - const data_num = Atomics.load(view, 1); - - const return_data: Array = []; - - let offset = 12; - // console.log("data_num", data_num); - for (let i = 0; i < data_num; i++) { - // console.log("this.share_arrays_memory", this.share_arrays_memory); - const header = new Int32Array(this.share_arrays_memory, offset); - const target_num = header[1]; - const targets = new Int32Array( - this.share_arrays_memory, - offset + 8, - target_num, - ); - const data_len = this.data_size; - if (targets.includes(id)) { - const data = new Uint32Array( - this.share_arrays_memory, - offset + 8 + target_num * 4, - data_len / 4, - ); - - // なぜかわからないが、上では正常に動作せず、以下のようにすると動作する - // return_data.push(new Uint32Array(data)); - return_data.push(new Uint32Array([...data])); - - const target_index = targets.indexOf(id); - Atomics.store(targets, target_index, -1); - const old_left_targets_num = Atomics.sub(header, 0, 1); - if (old_left_targets_num === 1) { - // rm data - Atomics.sub(view, 1, 1); - const used_len = Atomics.load(view, 2); - const new_used_len = used_len - data_len - 8 - target_num * 4; - Atomics.store(view, 2, new_used_len); - const next_data_offset = offset + data_len + 8 + target_num * 4; - const next_tail = new Int32Array( - this.share_arrays_memory, - next_data_offset, - ); - const now_tail = new Int32Array(this.share_arrays_memory, offset); - now_tail.set(next_tail); - // console.log("new_used_len", new_used_len); - } else { - offset += data_len + 8 + target_num * 4; - } - } else { - offset += data_len + 8 + target_num * 4; - } - // console.log("offset", offset); - } - - if (offset !== Atomics.load(view, 2)) { - throw new Error( - `invalid offset: ${offset} !== ${Atomics.load(view, 2)}`, - ); - } - - this.release_lock(); - - // console.log("get_data get: return_data", return_data); - - return return_data; - } + // The structure is similar to an allocator, but the mechanism is different + + // Example of fd management + // This needs to be handled + // 1. Start of path_open + // 2. Removed by fd_close + // 2.1 Sent by ToRefSender + // 3. Reassigned by path_open + // < Closed by ToRefSender + // 3.1 The person who opened it can use it + // < Closed by ToRefSender — this alone will cause a bug + // Structurally, this shouldn't happen in the farm + + // In the end, when receiving from this function, it should be done on the first call of each function + + // The first 4 bytes are for lock value: i32 + // The next 4 bytes are the current number of data: m: i32 + // The next 4 bytes are the length of the area used by share_arrays_memory: n: i32 + // Data header + // 4 bytes: remaining target count + // 4 bytes: target count (n) + // n * 4 bytes: target allocation numbers + // Data + // data_size bytes: data + private share_arrays_memory: SharedArrayBuffer; + + // The size of the data + private data_size: number; + + constructor( + // data is Uint32Array + // and data_size is data.length + data_size: number, + max_share_arrays_memory: number = 100 * 1024, + share_arrays_memory?: SharedArrayBuffer, + ) { + this.data_size = data_size; + if (share_arrays_memory) { + this.share_arrays_memory = share_arrays_memory; + } else { + this.share_arrays_memory = new SharedArrayBuffer(max_share_arrays_memory); + } + const view = new Int32Array(this.share_arrays_memory); + Atomics.store(view, 0, 0); + Atomics.store(view, 1, 0); + Atomics.store(view, 2, 12); + } + + protected static init_self_inner(sl: ToRefSenderUseArrayBufferObject): { + data_size: number; + max_share_arrays_memory: number; + share_arrays_memory: SharedArrayBuffer; + } { + return { + data_size: sl.data_size, + max_share_arrays_memory: sl.share_arrays_memory.byteLength, + share_arrays_memory: sl.share_arrays_memory, + }; + } + + private async async_lock(): Promise { + const view = new Int32Array(this.share_arrays_memory); + // eslint-disable-next-line no-constant-condition + while (true) { + let lock: "not-equal" | "timed-out" | "ok"; + const { value } = Atomics.waitAsync(view, 0, 1); + if (value instanceof Promise) { + lock = await value; + } else { + lock = value; + } + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old !== 0) { + continue; + } + break; + } + } + + private block_lock(): void { + // eslint-disable-next-line no-constant-condition + while (true) { + const view = new Int32Array(this.share_arrays_memory); + const lock = Atomics.wait(view, 0, 1); + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old !== 0) { + continue; + } + break; + } + } + + private release_lock(): void { + const view = new Int32Array(this.share_arrays_memory); + Atomics.store(view, 0, 0); + Atomics.notify(view, 0, 1); + } + + protected async async_send( + targets: Array, + data: Uint32Array, + ): Promise { + await this.async_lock(); + + const view = new Int32Array(this.share_arrays_memory); + const used_len = Atomics.load(view, 2); + const data_len = data.byteLength; + if (data_len !== this.data_size) { + throw new Error(`invalid data size: ${data_len} !== ${this.data_size}`); + } + const new_used_len = used_len + data_len + 8 + targets.length * 4; + if (new_used_len > this.share_arrays_memory.byteLength) { + throw new Error("over memory"); + } + + Atomics.store(view, 2, new_used_len); + + const header = new Int32Array(this.share_arrays_memory, used_len); + header[0] = targets.length; + header[1] = targets.length; + header.set(targets, 2); + + const data_view = new Uint32Array( + this.share_arrays_memory, + used_len + 8 + targets.length * 4, + ); + data_view.set(data); + + // console.log("async_send send", targets, data); + + Atomics.add(view, 1, 1); + + this.release_lock(); + } + + protected get_data(id: number): Array | undefined { + const view = new Int32Array(this.share_arrays_memory); + const data_num_tmp = Atomics.load(view, 1); + if (data_num_tmp === 0) { + return undefined; + } + + this.block_lock(); + + const data_num = Atomics.load(view, 1); + + const return_data: Array = []; + + let offset = 12; + // console.log("data_num", data_num); + for (let i = 0; i < data_num; i++) { + // console.log("this.share_arrays_memory", this.share_arrays_memory); + const header = new Int32Array(this.share_arrays_memory, offset); + const target_num = header[1]; + const targets = new Int32Array( + this.share_arrays_memory, + offset + 8, + target_num, + ); + const data_len = this.data_size; + if (targets.includes(id)) { + const data = new Uint32Array( + this.share_arrays_memory, + offset + 8 + target_num * 4, + data_len / 4, + ); + + // なぜかわからないが、上では正常に動作せず、以下のようにすると動作する + // return_data.push(new Uint32Array(data)); + return_data.push(new Uint32Array([...data])); + + const target_index = targets.indexOf(id); + Atomics.store(targets, target_index, -1); + const old_left_targets_num = Atomics.sub(header, 0, 1); + if (old_left_targets_num === 1) { + // rm data + Atomics.sub(view, 1, 1); + const used_len = Atomics.load(view, 2); + const new_used_len = used_len - data_len - 8 - target_num * 4; + Atomics.store(view, 2, new_used_len); + const next_data_offset = offset + data_len + 8 + target_num * 4; + const next_tail = new Int32Array( + this.share_arrays_memory, + next_data_offset, + ); + const now_tail = new Int32Array(this.share_arrays_memory, offset); + now_tail.set(next_tail); + // console.log("new_used_len", new_used_len); + } else { + offset += data_len + 8 + target_num * 4; + } + } else { + offset += data_len + 8 + target_num * 4; + } + // console.log("offset", offset); + } + + if (offset !== Atomics.load(view, 2)) { + throw new Error(`invalid offset: ${offset} !== ${Atomics.load(view, 2)}`); + } + + this.release_lock(); + + // console.log("get_data get: return_data", return_data); + + return return_data; + } } diff --git a/src/wasi_farm/shared_array_buffer/thread_spawn.ts b/src/wasi_farm/shared_array_buffer/thread_spawn.ts index cb6d2cb..5260fad 100644 --- a/src/wasi_farm/shared_array_buffer/thread_spawn.ts +++ b/src/wasi_farm/shared_array_buffer/thread_spawn.ts @@ -18,248 +18,248 @@ import { WASIFarmAnimal } from "../animals.js"; import type { WASIFarmRefObject } from "../ref.js"; import type { WorkerBackgroundRefObject } from "./worker_background/index.js"; import { - WorkerBackgroundRef, - worker_background_worker_url, + WorkerBackgroundRef, + worker_background_worker_url, } from "./worker_background/index.js"; type ThreadSpawnerObject = { - share_memory: WebAssembly.Memory; - wasi_farm_refs_object: Array; - worker_url: string; - worker_background_ref_object: WorkerBackgroundRefObject; + share_memory: WebAssembly.Memory; + wasi_farm_refs_object: Array; + worker_url: string; + worker_background_ref_object: WorkerBackgroundRefObject; }; export class ThreadSpawner { - private share_memory: WebAssembly.Memory; - private wasi_farm_refs_object: Array; - private worker_url: string; - private worker_background_ref: WorkerBackgroundRef; - private worker_background_ref_object: WorkerBackgroundRefObject; + private share_memory: WebAssembly.Memory; + private wasi_farm_refs_object: Array; + private worker_url: string; + private worker_background_ref: WorkerBackgroundRef; + private worker_background_ref_object: WorkerBackgroundRefObject; - // hold the worker to prevent GC. - private worker_background_worker?: Worker; - private worker_background_worker_promise?: Promise; + // hold the worker to prevent GC. + private worker_background_worker?: Worker; + private worker_background_worker_promise?: Promise; - // https://github.com/rustwasm/wasm-pack/issues/479 + // https://github.com/rustwasm/wasm-pack/issues/479 - constructor( - worker_url: string, - wasi_farm_refs_object: Array, - share_memory?: WebAssembly.Memory, - // 16MB for the time being. - // https://users.rust-lang.org/t/what-is-the-size-limit-of-threads-stack-in-rust/11867/3 - MIN_STACK = 16777216, - worker_background_ref_object?: WorkerBackgroundRefObject, - thread_spawn_wasm?: WebAssembly.Module, - ) { - this.worker_url = worker_url; - this.wasi_farm_refs_object = wasi_farm_refs_object; + constructor( + worker_url: string, + wasi_farm_refs_object: Array, + share_memory?: WebAssembly.Memory, + // 16MB for the time being. + // https://users.rust-lang.org/t/what-is-the-size-limit-of-threads-stack-in-rust/11867/3 + MIN_STACK = 16777216, + worker_background_ref_object?: WorkerBackgroundRefObject, + thread_spawn_wasm?: WebAssembly.Module, + ) { + this.worker_url = worker_url; + this.wasi_farm_refs_object = wasi_farm_refs_object; - const min_initial_size = 1048576 / 65536; // Rust's default stack size is 1MB. - const initial_size = MIN_STACK / 65536; - if (initial_size < min_initial_size) { - throw new Error( - `The stack size must be at least ${min_initial_size} bytes.`, - ); - } - const max_memory = 1073741824 / 65536; // Rust's default maximum memory size is 1GB. + const min_initial_size = 1048576 / 65536; // Rust's default stack size is 1MB. + const initial_size = MIN_STACK / 65536; + if (initial_size < min_initial_size) { + throw new Error( + `The stack size must be at least ${min_initial_size} bytes.`, + ); + } + const max_memory = 1073741824 / 65536; // Rust's default maximum memory size is 1GB. - this.share_memory = - share_memory || - // WebAssembly.Memory's 1 page is 65536 bytes. - new WebAssembly.Memory({ - initial: initial_size, - maximum: max_memory, - shared: true, - }); + this.share_memory = + share_memory || + // WebAssembly.Memory's 1 page is 65536 bytes. + new WebAssembly.Memory({ + initial: initial_size, + maximum: max_memory, + shared: true, + }); - if (worker_background_ref_object === undefined) { - const worker_background_worker_url__ = worker_background_worker_url(); - this.worker_background_worker = new Worker( - worker_background_worker_url__, - { type: "module" }, - ); - URL.revokeObjectURL(worker_background_worker_url__); - const { promise, resolve } = Promise.withResolvers(); - this.worker_background_worker_promise = promise; - this.worker_background_worker.onmessage = (e) => { - this.worker_background_ref_object = e.data; - this.worker_background_ref = WorkerBackgroundRef.init_self( - this.worker_background_ref_object, - ); - resolve(); - }; - this.worker_background_worker.postMessage({ - override_object: { - sl_object: this.get_object(), - thread_spawn_wasm, - }, - }); - } else { - this.worker_background_ref_object = worker_background_ref_object; - this.worker_background_ref = WorkerBackgroundRef.init_self( - this.worker_background_ref_object, - ); - } - } + if (worker_background_ref_object === undefined) { + const worker_background_worker_url__ = worker_background_worker_url(); + this.worker_background_worker = new Worker( + worker_background_worker_url__, + { type: "module" }, + ); + URL.revokeObjectURL(worker_background_worker_url__); + const { promise, resolve } = Promise.withResolvers(); + this.worker_background_worker_promise = promise; + this.worker_background_worker.onmessage = (e) => { + this.worker_background_ref_object = e.data; + this.worker_background_ref = WorkerBackgroundRef.init_self( + this.worker_background_ref_object, + ); + resolve(); + }; + this.worker_background_worker.postMessage({ + override_object: { + sl_object: this.get_object(), + thread_spawn_wasm, + }, + }); + } else { + this.worker_background_ref_object = worker_background_ref_object; + this.worker_background_ref = WorkerBackgroundRef.init_self( + this.worker_background_ref_object, + ); + } + } - wait_worker_background_worker(): Promise { - if (this.worker_background_worker_promise) { - return this.worker_background_worker_promise; - } - return Promise.resolve(); - } + wait_worker_background_worker(): Promise { + if (this.worker_background_worker_promise) { + return this.worker_background_worker_promise; + } + return Promise.resolve(); + } - thread_spawn( - start_arg: number, - args: Array, - env: Array, - fd_map: Array<[number, number]>, - ): number { - if (!self.Worker.toString().includes("[native code]")) { - if (self.Worker.toString().includes("function")) { - console.warn("SubWorker(new Worker on Worker) is polyfilled maybe."); - } else { - throw new Error("SubWorker(new Worker on Worker) is not supported."); - } - } + thread_spawn( + start_arg: number, + args: Array, + env: Array, + fd_map: Array<[number, number]>, + ): number { + if (!self.Worker.toString().includes("[native code]")) { + if (self.Worker.toString().includes("function")) { + console.warn("SubWorker(new Worker on Worker) is polyfilled maybe."); + } else { + throw new Error("SubWorker(new Worker on Worker) is not supported."); + } + } - const worker = this.worker_background_ref.new_worker( - this.worker_url, - { type: "module" }, - { - this_is_thread_spawn: true, - start_arg, - args, - env, - fd_map, - }, - ); + const worker = this.worker_background_ref.new_worker( + this.worker_url, + { type: "module" }, + { + this_is_thread_spawn: true, + start_arg, + args, + env, + fd_map, + }, + ); - const thread_id = worker.get_id(); + const thread_id = worker.get_id(); - return thread_id; - } + return thread_id; + } - static init_self(sl: ThreadSpawnerObject): ThreadSpawner { - const thread_spawner = new ThreadSpawner( - sl.worker_url, - sl.wasi_farm_refs_object, - sl.share_memory, - undefined, - sl.worker_background_ref_object, - ); - return thread_spawner; - } + static init_self(sl: ThreadSpawnerObject): ThreadSpawner { + const thread_spawner = new ThreadSpawner( + sl.worker_url, + sl.wasi_farm_refs_object, + sl.share_memory, + undefined, + sl.worker_background_ref_object, + ); + return thread_spawner; + } - static init_self_with_worker_background_ref( - sl: ThreadSpawnerObject, - worker_background_ref_object: WorkerBackgroundRefObject, - ): ThreadSpawner { - const thread_spawner = new ThreadSpawner( - sl.worker_url, - sl.wasi_farm_refs_object, - sl.share_memory, - undefined, - worker_background_ref_object, - ); - return thread_spawner; - } + static init_self_with_worker_background_ref( + sl: ThreadSpawnerObject, + worker_background_ref_object: WorkerBackgroundRefObject, + ): ThreadSpawner { + const thread_spawner = new ThreadSpawner( + sl.worker_url, + sl.wasi_farm_refs_object, + sl.share_memory, + undefined, + worker_background_ref_object, + ); + return thread_spawner; + } - get_share_memory(): WebAssembly.Memory { - return this.share_memory; - } + get_share_memory(): WebAssembly.Memory { + return this.share_memory; + } - get_object(): ThreadSpawnerObject { - return { - share_memory: this.share_memory, - wasi_farm_refs_object: this.wasi_farm_refs_object, - worker_url: this.worker_url, - worker_background_ref_object: this.worker_background_ref_object, - }; - } + get_object(): ThreadSpawnerObject { + return { + share_memory: this.share_memory, + wasi_farm_refs_object: this.wasi_farm_refs_object, + worker_url: this.worker_url, + worker_background_ref_object: this.worker_background_ref_object, + }; + } } // send fd_map is not implemented yet. // issue: the fd passed to the child process is different from the parent process. export const thread_spawn_on_worker = async (msg: { - this_is_thread_spawn: boolean; - worker_id: number; - start_arg: number; - worker_background_ref: WorkerBackgroundRefObject; - sl_object: ThreadSpawnerObject; - thread_spawn_wasm: WebAssembly.Module; - args: Array; - env: Array; - fd_map: Array; + this_is_thread_spawn: boolean; + worker_id: number; + start_arg: number; + worker_background_ref: WorkerBackgroundRefObject; + sl_object: ThreadSpawnerObject; + thread_spawn_wasm: WebAssembly.Module; + args: Array; + env: Array; + fd_map: Array; }): Promise => { - if (msg.this_is_thread_spawn) { - const { - worker_id: thread_id, - start_arg, - args, - env, - sl_object, - thread_spawn_wasm, - } = msg; + if (msg.this_is_thread_spawn) { + const { + worker_id: thread_id, + start_arg, + args, + env, + sl_object, + thread_spawn_wasm, + } = msg; - console.log(`thread_spawn worker ${thread_id} start`); + console.log(`thread_spawn worker ${thread_id} start`); - const thread_spawner = ThreadSpawner.init_self_with_worker_background_ref( - sl_object, - msg.worker_background_ref, - ); + const thread_spawner = ThreadSpawner.init_self_with_worker_background_ref( + sl_object, + msg.worker_background_ref, + ); - const override_fd_map: Array = new Array( - sl_object.wasi_farm_refs_object.length, - ); + const override_fd_map: Array = new Array( + sl_object.wasi_farm_refs_object.length, + ); - for (const [fd, wasi_ref_n] of msg.fd_map) { - if (override_fd_map[wasi_ref_n] === undefined) { - override_fd_map[wasi_ref_n] = []; - } - override_fd_map[wasi_ref_n].push(fd); - } + for (const [fd, wasi_ref_n] of msg.fd_map) { + if (override_fd_map[wasi_ref_n] === undefined) { + override_fd_map[wasi_ref_n] = []; + } + override_fd_map[wasi_ref_n].push(fd); + } - const wasi = new WASIFarmAnimal( - sl_object.wasi_farm_refs_object, - args, - env, - { - can_thread_spawn: true, - thread_spawn_worker_url: sl_object.worker_url, - }, - override_fd_map, - thread_spawner, - ); + const wasi = new WASIFarmAnimal( + sl_object.wasi_farm_refs_object, + args, + env, + { + can_thread_spawn: true, + thread_spawn_worker_url: sl_object.worker_url, + }, + override_fd_map, + thread_spawner, + ); - const inst = await WebAssembly.instantiate(thread_spawn_wasm, { - env: { - memory: wasi.get_share_memory(), - }, - wasi: wasi.wasiThreadImport, - wasi_snapshot_preview1: wasi.wasiImport, - }); + const inst = await WebAssembly.instantiate(thread_spawn_wasm, { + env: { + memory: wasi.get_share_memory(), + }, + wasi: wasi.wasiThreadImport, + wasi_snapshot_preview1: wasi.wasiImport, + }); - globalThis.postMessage({ - msg: "ready", - }); + globalThis.postMessage({ + msg: "ready", + }); - wasi.wasi_thread_start( - inst as unknown as { - exports: { - memory: WebAssembly.Memory; - wasi_thread_start: (thread_id: number, start_arg: number) => void; - }; - }, - thread_id, - start_arg, - ); + wasi.wasi_thread_start( + inst as unknown as { + exports: { + memory: WebAssembly.Memory; + wasi_thread_start: (thread_id: number, start_arg: number) => void; + }; + }, + thread_id, + start_arg, + ); - globalThis.postMessage({ - msg: "done", - }); + globalThis.postMessage({ + msg: "done", + }); - return wasi; - } + return wasi; + } }; diff --git a/src/wasi_farm/shared_array_buffer/util.ts b/src/wasi_farm/shared_array_buffer/util.ts index 0c41594..4ed230f 100644 --- a/src/wasi_farm/shared_array_buffer/util.ts +++ b/src/wasi_farm/shared_array_buffer/util.ts @@ -1,68 +1,68 @@ export const get_func_name_from_number = (num: number): string => { - switch (num) { - case 7: - return "fd_advise"; - case 8: - return "fd_allocate"; - case 9: - return "fd_close"; - case 10: - return "fd_datasync"; - case 11: - return "fd_fdstat_get"; - case 12: - return "fd_fdstat_set_flags"; - case 13: - return "fd_fdstat_set_rights"; - case 14: - return "fd_filestat_get"; - case 15: - return "fd_filestat_set_size"; - case 16: - return "fd_filestat_set_times"; - case 17: - return "fd_pread"; - case 18: - return "fd_prestat_get"; - case 19: - return "fd_prestat_dir_name"; - case 20: - return "fd_pwrite"; - case 21: - return "fd_read"; - case 22: - return "fd_readdir"; - case 23: - return "fd_renumber"; - case 24: - return "fd_seek"; - case 25: - return "fd_sync"; - case 26: - return "fd_tell"; - case 27: - return "fd_write"; - case 28: - return "path_create_directory"; - case 29: - return "path_filestat_get"; - case 30: - return "path_filestat_set_times"; - case 31: - return "path_link"; - case 32: - return "path_open"; - case 33: - return "path_readlink"; - case 34: - return "path_remove_directory"; - case 35: - return "path_rename"; - case 36: - return "path_symlink"; - case 37: - return "path_unlink_file"; - default: - return "unknown"; - } + switch (num) { + case 7: + return "fd_advise"; + case 8: + return "fd_allocate"; + case 9: + return "fd_close"; + case 10: + return "fd_datasync"; + case 11: + return "fd_fdstat_get"; + case 12: + return "fd_fdstat_set_flags"; + case 13: + return "fd_fdstat_set_rights"; + case 14: + return "fd_filestat_get"; + case 15: + return "fd_filestat_set_size"; + case 16: + return "fd_filestat_set_times"; + case 17: + return "fd_pread"; + case 18: + return "fd_prestat_get"; + case 19: + return "fd_prestat_dir_name"; + case 20: + return "fd_pwrite"; + case 21: + return "fd_read"; + case 22: + return "fd_readdir"; + case 23: + return "fd_renumber"; + case 24: + return "fd_seek"; + case 25: + return "fd_sync"; + case 26: + return "fd_tell"; + case 27: + return "fd_write"; + case 28: + return "path_create_directory"; + case 29: + return "path_filestat_get"; + case 30: + return "path_filestat_set_times"; + case 31: + return "path_link"; + case 32: + return "path_open"; + case 33: + return "path_readlink"; + case 34: + return "path_remove_directory"; + case 35: + return "path_rename"; + case 36: + return "path_symlink"; + case 37: + return "path_unlink_file"; + default: + return "unknown"; + } }; diff --git a/src/wasi_farm/shared_array_buffer/worker_background/index.ts b/src/wasi_farm/shared_array_buffer/worker_background/index.ts index ec6835d..40c6805 100644 --- a/src/wasi_farm/shared_array_buffer/worker_background/index.ts +++ b/src/wasi_farm/shared_array_buffer/worker_background/index.ts @@ -3,8 +3,8 @@ import { WorkerBackgroundRef, WorkerRef } from "./worker_background_ref.js"; import { url as worker_background_worker_url } from "./worker_blob.js"; export { - WorkerBackgroundRef, - WorkerRef, - type WorkerBackgroundRefObject, - worker_background_worker_url, + WorkerBackgroundRef, + WorkerRef, + type WorkerBackgroundRefObject, + worker_background_worker_url, }; diff --git a/src/wasi_farm/shared_array_buffer/worker_background/minify.js b/src/wasi_farm/shared_array_buffer/worker_background/minify.js index 69d8c31..eecb571 100644 --- a/src/wasi_farm/shared_array_buffer/worker_background/minify.js +++ b/src/wasi_farm/shared_array_buffer/worker_background/minify.js @@ -3,26 +3,26 @@ import swc from "@swc/core"; import { readFileSync, writeFileSync } from "node:fs"; const old_code = readFileSync( - "./dist/workers/worker_background_worker.js", - "utf8", + "./dist/workers/worker_background_worker.js", + "utf8", ); const { code } = await swc.minify(old_code, { - compress: { - reduce_funcs: true, - arguments: true, - booleans_as_integers: true, - hoist_funs: false, - keep_classnames: false, - unsafe: true, - }, - mangle: true, + compress: { + reduce_funcs: true, + arguments: true, + booleans_as_integers: true, + hoist_funs: false, + keep_classnames: false, + unsafe: true, + }, + mangle: true, }); writeFileSync( - "./dist/workers/worker_background_worker_minify.js", - code, - "utf8", + "./dist/workers/worker_background_worker_minify.js", + code, + "utf8", ); // \n -> \\n @@ -40,7 +40,7 @@ const wrapper_code = `export const url = () => { `; writeFileSync( - "./src/wasi_farm/shared_array_buffer/worker_background/worker_blob.ts", - wrapper_code, - "utf8", + "./src/wasi_farm/shared_array_buffer/worker_background/worker_blob.ts", + wrapper_code, + "utf8", ); diff --git a/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs b/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs index fa1a9a9..2b498de 100644 --- a/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs +++ b/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs @@ -5,11 +5,11 @@ const { config } = require("@swc/core/spack"); console.log(__dirname); module.exports = config({ - entry: { - web: `${__dirname}/worker.ts`, - }, - output: { - path: `${__dirname}/../../../../dist/workers/`, - name: "worker_background_worker.js", - }, + entry: { + web: `${__dirname}/worker.ts`, + }, + output: { + path: `${__dirname}/../../../../dist/workers/`, + name: "worker_background_worker.js", + }, }); diff --git a/src/wasi_farm/shared_array_buffer/worker_background/worker.ts b/src/wasi_farm/shared_array_buffer/worker_background/worker.ts index 932c23e..6f11e00 100644 --- a/src/wasi_farm/shared_array_buffer/worker_background/worker.ts +++ b/src/wasi_farm/shared_array_buffer/worker_background/worker.ts @@ -5,8 +5,8 @@ // The request is made using BroadcastChannel. import { - AllocatorUseArrayBuffer, - type AllocatorUseArrayBufferObject, + AllocatorUseArrayBuffer, + type AllocatorUseArrayBufferObject, } from "../allocator.js"; // Note that postMessage, etc. @@ -14,155 +14,155 @@ import { // (at least as far as I have tried) export type WorkerBackgroundRefObject = { - allocator: AllocatorUseArrayBufferObject; - lock: SharedArrayBuffer; - signature_input: SharedArrayBuffer; + allocator: AllocatorUseArrayBufferObject; + lock: SharedArrayBuffer; + signature_input: SharedArrayBuffer; }; class WorkerBackground { - private override_object: T; - private allocator: AllocatorUseArrayBuffer; - private lock: SharedArrayBuffer; - private signature_input: SharedArrayBuffer; - - private workers: Array = []; - - private listen_holder: Promise; - - constructor(override_object: T) { - this.override_object = override_object; - this.lock = new SharedArrayBuffer(8); - this.allocator = new AllocatorUseArrayBuffer( - new SharedArrayBuffer(10 * 1024), - ); - this.signature_input = new SharedArrayBuffer(24); - this.listen_holder = this.listen(); - } - - assign_worker_id(): number { - for (let i = 0; i < this.workers.length; i++) { - if (this.workers[i] === undefined) { - return i; - } - } - this.workers.push(undefined); - return this.workers.length; - } - - ref(): WorkerBackgroundRefObject { - return { - allocator: this.allocator.get_object(), - lock: this.lock, - signature_input: this.signature_input, - }; - } - - async listen(): Promise { - const lock_view = new Int32Array(this.lock); - Atomics.store(lock_view, 0, 0); - Atomics.store(lock_view, 1, 0); - - const signature_input_view = new Int32Array(this.signature_input); - - // eslint-disable-next-line no-constant-condition - while (true) { - try { - let lock: "not-equal" | "timed-out" | "ok"; - - const { value } = Atomics.waitAsync(lock_view, 1, 0); - if (value instanceof Promise) { - lock = await value; - } else { - lock = value; - } - if (lock === "timed-out") { - throw new Error("timed-out"); - } - - const locked_value = Atomics.load(lock_view, 1); - if (locked_value !== 1) { - throw new Error("locked"); - } - - const signature_input = Atomics.load(signature_input_view, 0); - switch (signature_input) { - // create new worker - case 1: { - const url_ptr = Atomics.load(signature_input_view, 1); - const url_len = Atomics.load(signature_input_view, 2); - const url_buff = this.allocator.get_memory(url_ptr, url_len); - const url = new TextDecoder().decode(url_buff); - const is_module = Atomics.load(signature_input_view, 3) === 1; - const worker = new Worker(url, { - type: is_module ? "module" : "classic", - }); - const json_ptr = Atomics.load(signature_input_view, 4); - const json_len = Atomics.load(signature_input_view, 5); - const json_buff = this.allocator.get_memory(json_ptr, json_len); - const json = new TextDecoder().decode(json_buff); - const obj = JSON.parse(json); - - const worker_id = this.assign_worker_id(); - - this.workers[worker_id] = worker; - - const { promise, resolve } = Promise.withResolvers(); - - worker.onmessage = (e) => { - const { msg } = e.data; - - if (msg === "ready") { - resolve(); - } - - if (msg === "done") { - this.workers[worker_id].terminate(); - this.workers[worker_id] = undefined; - - console.log(`worker ${worker_id} done so terminate`); - } - }; - - worker.postMessage({ - ...this.override_object, - ...obj, - worker_id, - worker_background_ref: this.ref(), - }); - - await promise; - - Atomics.store(signature_input_view, 0, worker_id); - - break; - } - } - - const old_call_lock = Atomics.exchange(lock_view, 1, 0); - if (old_call_lock !== 1) { - throw new Error("Lock is already set"); - } - const num = Atomics.notify(lock_view, 1, 1); - if (num !== 1) { - if (num === 0) { - console.warn("notify failed, waiter is late"); - continue; - } - throw new Error(`notify failed: ${num}`); - } - } catch (e) { - console.error(e); - } - } - } + private override_object: T; + private allocator: AllocatorUseArrayBuffer; + private lock: SharedArrayBuffer; + private signature_input: SharedArrayBuffer; + + private workers: Array = []; + + private listen_holder: Promise; + + constructor(override_object: T) { + this.override_object = override_object; + this.lock = new SharedArrayBuffer(8); + this.allocator = new AllocatorUseArrayBuffer( + new SharedArrayBuffer(10 * 1024), + ); + this.signature_input = new SharedArrayBuffer(24); + this.listen_holder = this.listen(); + } + + assign_worker_id(): number { + for (let i = 0; i < this.workers.length; i++) { + if (this.workers[i] === undefined) { + return i; + } + } + this.workers.push(undefined); + return this.workers.length; + } + + ref(): WorkerBackgroundRefObject { + return { + allocator: this.allocator.get_object(), + lock: this.lock, + signature_input: this.signature_input, + }; + } + + async listen(): Promise { + const lock_view = new Int32Array(this.lock); + Atomics.store(lock_view, 0, 0); + Atomics.store(lock_view, 1, 0); + + const signature_input_view = new Int32Array(this.signature_input); + + // eslint-disable-next-line no-constant-condition + while (true) { + try { + let lock: "not-equal" | "timed-out" | "ok"; + + const { value } = Atomics.waitAsync(lock_view, 1, 0); + if (value instanceof Promise) { + lock = await value; + } else { + lock = value; + } + if (lock === "timed-out") { + throw new Error("timed-out"); + } + + const locked_value = Atomics.load(lock_view, 1); + if (locked_value !== 1) { + throw new Error("locked"); + } + + const signature_input = Atomics.load(signature_input_view, 0); + switch (signature_input) { + // create new worker + case 1: { + const url_ptr = Atomics.load(signature_input_view, 1); + const url_len = Atomics.load(signature_input_view, 2); + const url_buff = this.allocator.get_memory(url_ptr, url_len); + const url = new TextDecoder().decode(url_buff); + const is_module = Atomics.load(signature_input_view, 3) === 1; + const worker = new Worker(url, { + type: is_module ? "module" : "classic", + }); + const json_ptr = Atomics.load(signature_input_view, 4); + const json_len = Atomics.load(signature_input_view, 5); + const json_buff = this.allocator.get_memory(json_ptr, json_len); + const json = new TextDecoder().decode(json_buff); + const obj = JSON.parse(json); + + const worker_id = this.assign_worker_id(); + + this.workers[worker_id] = worker; + + const { promise, resolve } = Promise.withResolvers(); + + worker.onmessage = (e) => { + const { msg } = e.data; + + if (msg === "ready") { + resolve(); + } + + if (msg === "done") { + this.workers[worker_id].terminate(); + this.workers[worker_id] = undefined; + + console.log(`worker ${worker_id} done so terminate`); + } + }; + + worker.postMessage({ + ...this.override_object, + ...obj, + worker_id, + worker_background_ref: this.ref(), + }); + + await promise; + + Atomics.store(signature_input_view, 0, worker_id); + + break; + } + } + + const old_call_lock = Atomics.exchange(lock_view, 1, 0); + if (old_call_lock !== 1) { + throw new Error("Lock is already set"); + } + const num = Atomics.notify(lock_view, 1, 1); + if (num !== 1) { + if (num === 0) { + console.warn("notify failed, waiter is late"); + continue; + } + throw new Error(`notify failed: ${num}`); + } + } catch (e) { + console.error(e); + } + } + } } let worker_background: WorkerBackground; globalThis.onmessage = (e: MessageEvent) => { - const { override_object } = e.data; - worker_background = new WorkerBackground(override_object); - postMessage(worker_background.ref()); + const { override_object } = e.data; + worker_background = new WorkerBackground(override_object); + postMessage(worker_background.ref()); - console.log("worker_background ready"); + console.log("worker_background ready"); }; diff --git a/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts b/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts index ceac13e..db47f9f 100644 --- a/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts +++ b/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts @@ -2,102 +2,102 @@ import { AllocatorUseArrayBuffer } from "../allocator.js"; import type { WorkerBackgroundRefObject } from "./worker.js"; export class WorkerBackgroundRef { - private allocator: AllocatorUseArrayBuffer; - private lock: SharedArrayBuffer; - private signature_input: SharedArrayBuffer; + private allocator: AllocatorUseArrayBuffer; + private lock: SharedArrayBuffer; + private signature_input: SharedArrayBuffer; - constructor( - allocator: AllocatorUseArrayBuffer, - lock: SharedArrayBuffer, - signature_input: SharedArrayBuffer, - ) { - this.allocator = allocator; - this.lock = lock; - this.signature_input = signature_input; - } + constructor( + allocator: AllocatorUseArrayBuffer, + lock: SharedArrayBuffer, + signature_input: SharedArrayBuffer, + ) { + this.allocator = allocator; + this.lock = lock; + this.signature_input = signature_input; + } - private lock_base_func(): void { - const view = new Int32Array(this.lock); - // eslint-disable-next-line no-constant-condition - while (true) { - const lock = Atomics.wait(view, 0, 1); - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - const old = Atomics.compareExchange(view, 0, 0, 1); - if (old !== 0) { - continue; - } - break; - } - } + private lock_base_func(): void { + const view = new Int32Array(this.lock); + // eslint-disable-next-line no-constant-condition + while (true) { + const lock = Atomics.wait(view, 0, 1); + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + const old = Atomics.compareExchange(view, 0, 0, 1); + if (old !== 0) { + continue; + } + break; + } + } - private call_base_func(): void { - const view = new Int32Array(this.lock); - const old = Atomics.exchange(view, 1, 1); - if (old !== 0) { - console.error("what happened?"); - } - Atomics.notify(view, 1, 1); - } + private call_base_func(): void { + const view = new Int32Array(this.lock); + const old = Atomics.exchange(view, 1, 1); + if (old !== 0) { + console.error("what happened?"); + } + Atomics.notify(view, 1, 1); + } - // wait base_func - private wait_base_func(): void { - const view = new Int32Array(this.lock); - const lock = Atomics.wait(view, 1, 1); - if (lock === "timed-out") { - throw new Error("timed-out lock"); - } - } + // wait base_func + private wait_base_func(): void { + const view = new Int32Array(this.lock); + const lock = Atomics.wait(view, 1, 1); + if (lock === "timed-out") { + throw new Error("timed-out lock"); + } + } - // release base_func - private release_base_func(): void { - const view = new Int32Array(this.lock); - Atomics.store(view, 0, 0); - Atomics.notify(view, 0, 1); - } + // release base_func + private release_base_func(): void { + const view = new Int32Array(this.lock); + Atomics.store(view, 0, 0); + Atomics.notify(view, 0, 1); + } - new_worker( - url: string, - options?: WorkerOptions, - post_obj?: unknown, - ): WorkerRef { - this.lock_base_func(); - const view = new Int32Array(this.signature_input); - Atomics.store(view, 0, 1); - const url_buffer = new TextEncoder().encode(url); - this.allocator.block_write(url_buffer, this.signature_input, 1); - Atomics.store(view, 3, options.type === "module" ? 1 : 0); - const obj_json = JSON.stringify(post_obj); - const obj_buffer = new TextEncoder().encode(obj_json); - this.allocator.block_write(obj_buffer, this.signature_input, 4); - this.call_base_func(); - this.wait_base_func(); + new_worker( + url: string, + options?: WorkerOptions, + post_obj?: unknown, + ): WorkerRef { + this.lock_base_func(); + const view = new Int32Array(this.signature_input); + Atomics.store(view, 0, 1); + const url_buffer = new TextEncoder().encode(url); + this.allocator.block_write(url_buffer, this.signature_input, 1); + Atomics.store(view, 3, options.type === "module" ? 1 : 0); + const obj_json = JSON.stringify(post_obj); + const obj_buffer = new TextEncoder().encode(obj_json); + this.allocator.block_write(obj_buffer, this.signature_input, 4); + this.call_base_func(); + this.wait_base_func(); - const id = Atomics.load(view, 0); + const id = Atomics.load(view, 0); - this.release_base_func(); + this.release_base_func(); - return new WorkerRef(id); - } + return new WorkerRef(id); + } - static init_self(sl: WorkerBackgroundRefObject): WorkerBackgroundRef { - return new WorkerBackgroundRef( - AllocatorUseArrayBuffer.init_self(sl.allocator), - sl.lock, - sl.signature_input, - ); - } + static init_self(sl: WorkerBackgroundRefObject): WorkerBackgroundRef { + return new WorkerBackgroundRef( + AllocatorUseArrayBuffer.init_self(sl.allocator), + sl.lock, + sl.signature_input, + ); + } } export class WorkerRef { - private id: number; + private id: number; - constructor(id: number) { - this.id = id; - } + constructor(id: number) { + this.id = id; + } - get_id(): number { - return this.id; - } + get_id(): number { + return this.id; + } }