mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
working using seperate threads
This commit is contained in:
@ -1,11 +1,11 @@
|
|||||||
import { importObject, zjs } from "./imports";
|
import { importObject, setFiles, setStdin, setWasmModule, zjs } from "./imports";
|
||||||
import { old } from "./old";
|
import { old } from "./old";
|
||||||
|
|
||||||
const url = new URL("ghostty-wasm.wasm", import.meta.url);
|
const url = new URL("ghostty-wasm.wasm", import.meta.url);
|
||||||
fetch(url.href)
|
fetch(url.href)
|
||||||
.then((response) => response.arrayBuffer())
|
.then((response) => response.arrayBuffer())
|
||||||
.then((bytes) => WebAssembly.instantiate(bytes, importObject))
|
.then((bytes) => WebAssembly.instantiate(bytes, importObject))
|
||||||
.then((results) => {
|
.then(async (results) => {
|
||||||
const memory = importObject.env.memory;
|
const memory = importObject.env.memory;
|
||||||
const {
|
const {
|
||||||
atlas_clear,
|
atlas_clear,
|
||||||
@ -39,6 +39,7 @@ fetch(url.href)
|
|||||||
shared_grid_index_for_codepoint,
|
shared_grid_index_for_codepoint,
|
||||||
shared_grid_render_glyph,
|
shared_grid_render_glyph,
|
||||||
run,
|
run,
|
||||||
|
draw,
|
||||||
} = results.instance.exports;
|
} = results.instance.exports;
|
||||||
|
|
||||||
// Give us access to the zjs value for debugging.
|
// Give us access to the zjs value for debugging.
|
||||||
@ -59,5 +60,42 @@ fetch(url.href)
|
|||||||
// Create our config
|
// Create our config
|
||||||
const config_str = makeStr("font-family = monospace\nfont-size = 32\n");
|
const config_str = makeStr("font-family = monospace\nfont-size = 32\n");
|
||||||
old(results);
|
old(results);
|
||||||
|
setWasmModule(results.module);
|
||||||
|
const stdin = new SharedArrayBuffer(1024);
|
||||||
|
const files = {
|
||||||
|
nextFd: new SharedArrayBuffer(4),
|
||||||
|
polling: new SharedArrayBuffer(4),
|
||||||
|
has: new SharedArrayBuffer(1024),
|
||||||
|
}
|
||||||
|
new Int32Array(files.nextFd)[0] = 4;
|
||||||
|
setFiles(files);
|
||||||
|
setStdin(stdin);
|
||||||
run(config_str.ptr, config_str.len);
|
run(config_str.ptr, config_str.len);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||||
|
const io = new Uint8ClampedArray(stdin, 4);
|
||||||
|
const text = new TextEncoder().encode("hello world\n\r");
|
||||||
|
io.set(text);
|
||||||
|
const n = new Int32Array(stdin);
|
||||||
|
console.error("storing");
|
||||||
|
Atomics.store(n, 0, text.length)
|
||||||
|
Atomics.notify(n, 0);
|
||||||
|
console.error("done storing");
|
||||||
|
function drawing() {
|
||||||
|
setTimeout(() => {
|
||||||
|
draw();
|
||||||
|
drawing();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
drawing()
|
||||||
|
setTimeout(() => {
|
||||||
|
const io = new Uint8ClampedArray(stdin, 4);
|
||||||
|
const text = new TextEncoder().encode("🐏\n\r👍🏽\n\rM_ghostty\033[2;2H\033[48;2;240;40;40m\033[38;2;23;255;80mhello");
|
||||||
|
io.set(text);
|
||||||
|
const n = new Int32Array(stdin);
|
||||||
|
console.error("storing");
|
||||||
|
Atomics.store(n, 0, text.length)
|
||||||
|
Atomics.notify(n, 0);
|
||||||
|
console.error("done storing");
|
||||||
|
}, 5000)
|
||||||
})
|
})
|
||||||
|
@ -1,13 +1,142 @@
|
|||||||
import { ZigJS } from "zig-js/src/index.ts";
|
import { ZigJS } from "zig-js/src/index.ts";
|
||||||
|
import {
|
||||||
|
WASI_ESUCCESS,
|
||||||
|
WASI_EBADF,
|
||||||
|
WASI_EINVAL,
|
||||||
|
WASI_ENOSYS,
|
||||||
|
WASI_EPERM,
|
||||||
|
//WASI_ENOTCAPABLE,
|
||||||
|
WASI_FILETYPE_UNKNOWN,
|
||||||
|
WASI_FILETYPE_BLOCK_DEVICE,
|
||||||
|
WASI_FILETYPE_CHARACTER_DEVICE,
|
||||||
|
WASI_FILETYPE_DIRECTORY,
|
||||||
|
WASI_FILETYPE_REGULAR_FILE,
|
||||||
|
WASI_FILETYPE_SOCKET_STREAM,
|
||||||
|
WASI_FILETYPE_SYMBOLIC_LINK,
|
||||||
|
WASI_FILETYPE,
|
||||||
|
WASI_FDFLAG_APPEND,
|
||||||
|
WASI_FDFLAG_DSYNC,
|
||||||
|
WASI_FDFLAG_NONBLOCK,
|
||||||
|
WASI_FDFLAG_RSYNC,
|
||||||
|
WASI_FDFLAG_SYNC,
|
||||||
|
WASI_RIGHT_FD_DATASYNC,
|
||||||
|
WASI_RIGHT_FD_READ,
|
||||||
|
WASI_RIGHT_FD_SEEK,
|
||||||
|
WASI_RIGHT_FD_FDSTAT_SET_FLAGS,
|
||||||
|
WASI_RIGHT_FD_SYNC,
|
||||||
|
WASI_RIGHT_FD_TELL,
|
||||||
|
WASI_RIGHT_FD_WRITE,
|
||||||
|
WASI_RIGHT_FD_ADVISE,
|
||||||
|
WASI_RIGHT_FD_ALLOCATE,
|
||||||
|
WASI_RIGHT_PATH_CREATE_DIRECTORY,
|
||||||
|
WASI_RIGHT_PATH_CREATE_FILE,
|
||||||
|
WASI_RIGHT_PATH_LINK_SOURCE,
|
||||||
|
WASI_RIGHT_PATH_LINK_TARGET,
|
||||||
|
WASI_RIGHT_PATH_OPEN,
|
||||||
|
WASI_RIGHT_FD_READDIR,
|
||||||
|
WASI_RIGHT_PATH_READLINK,
|
||||||
|
WASI_RIGHT_PATH_RENAME_SOURCE,
|
||||||
|
WASI_RIGHT_PATH_RENAME_TARGET,
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_GET,
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_SET_SIZE,
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_SET_TIMES,
|
||||||
|
WASI_RIGHT_FD_FILESTAT_GET,
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_SIZE,
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_TIMES,
|
||||||
|
WASI_RIGHT_PATH_SYMLINK,
|
||||||
|
WASI_RIGHT_PATH_REMOVE_DIRECTORY,
|
||||||
|
WASI_RIGHT_POLL_FD_READWRITE,
|
||||||
|
WASI_RIGHT_PATH_UNLINK_FILE,
|
||||||
|
RIGHTS_BLOCK_DEVICE_BASE,
|
||||||
|
RIGHTS_BLOCK_DEVICE_INHERITING,
|
||||||
|
RIGHTS_CHARACTER_DEVICE_BASE,
|
||||||
|
RIGHTS_CHARACTER_DEVICE_INHERITING,
|
||||||
|
RIGHTS_REGULAR_FILE_BASE,
|
||||||
|
RIGHTS_REGULAR_FILE_INHERITING,
|
||||||
|
RIGHTS_DIRECTORY_BASE,
|
||||||
|
RIGHTS_DIRECTORY_INHERITING,
|
||||||
|
RIGHTS_SOCKET_BASE,
|
||||||
|
RIGHTS_SOCKET_INHERITING,
|
||||||
|
RIGHTS_TTY_BASE,
|
||||||
|
RIGHTS_TTY_INHERITING,
|
||||||
|
WASI_CLOCK_MONOTONIC,
|
||||||
|
WASI_CLOCK_PROCESS_CPUTIME_ID,
|
||||||
|
WASI_CLOCK_REALTIME,
|
||||||
|
WASI_CLOCK_THREAD_CPUTIME_ID,
|
||||||
|
WASI_EVENTTYPE_CLOCK,
|
||||||
|
WASI_EVENTTYPE_FD_READ,
|
||||||
|
WASI_EVENTTYPE_FD_WRITE,
|
||||||
|
WASI_FILESTAT_SET_ATIM,
|
||||||
|
WASI_FILESTAT_SET_ATIM_NOW,
|
||||||
|
WASI_FILESTAT_SET_MTIM,
|
||||||
|
WASI_FILESTAT_SET_MTIM_NOW,
|
||||||
|
WASI_O_CREAT,
|
||||||
|
WASI_O_DIRECTORY,
|
||||||
|
WASI_O_EXCL,
|
||||||
|
WASI_O_TRUNC,
|
||||||
|
WASI_PREOPENTYPE_DIR,
|
||||||
|
WASI_STDIN_FILENO,
|
||||||
|
WASI_STDOUT_FILENO,
|
||||||
|
WASI_STDERR_FILENO,
|
||||||
|
ERROR_MAP,
|
||||||
|
SIGNAL_MAP,
|
||||||
|
WASI_WHENCE_CUR,
|
||||||
|
WASI_WHENCE_END,
|
||||||
|
WASI_WHENCE_SET,
|
||||||
|
} from "./wasi";
|
||||||
const textDecoder = new TextDecoder("utf-8");
|
const textDecoder = new TextDecoder("utf-8");
|
||||||
|
let stdin = new SharedArrayBuffer(1024);
|
||||||
|
export function setStdin(buf: SharedArrayBuffer) {
|
||||||
|
stdin = buf;
|
||||||
|
}
|
||||||
|
let bytes: null | Uint8ClampedArray = null
|
||||||
|
function perfNow() {
|
||||||
|
return performance.now() + performance.timeOrigin;
|
||||||
|
}
|
||||||
|
function readStdin() {
|
||||||
|
const len = new Int32Array(stdin);
|
||||||
|
if (len[0] == 0) {
|
||||||
|
Atomics.wait(len, 0, 0, 1000);
|
||||||
|
}
|
||||||
|
const length = len[0];
|
||||||
|
console.error("stdin", length);
|
||||||
|
if (length === 0) {
|
||||||
|
bytes = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bytes = new Uint8ClampedArray(stdin, 4, length).slice();
|
||||||
|
console.log(textDecoder.decode(bytes));
|
||||||
|
Atomics.store(len, 0, 0);
|
||||||
|
Atomics.notify(len, 0);
|
||||||
|
}
|
||||||
|
function sleep(ms: number) {
|
||||||
|
const buf = new SharedArrayBuffer(4);
|
||||||
|
const view = new Int32Array(buf);
|
||||||
|
view[0] = 1;
|
||||||
|
Atomics.wait(view, 0, 1, ms);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
let wasmModule;
|
||||||
|
export function setWasmModule(mod) {
|
||||||
|
wasmModule = mod;
|
||||||
|
}
|
||||||
|
let mainThread = true;
|
||||||
|
export function setMainThread(isMain) {
|
||||||
|
mainThread = isMain;
|
||||||
|
}
|
||||||
let gl: WebGL2RenderingContext;
|
let gl: WebGL2RenderingContext;
|
||||||
export function setGl(l) {
|
export function setGl(l) {
|
||||||
gl = l;
|
gl = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const zjs = new ZigJS();
|
export const zjs = new ZigJS();
|
||||||
|
globalThis.fontCanvas = new OffscreenCanvas(0, 0);
|
||||||
|
// window.fontContext = () => {
|
||||||
|
// const ctx = fontCanvas.getContext("2d");
|
||||||
|
// ctx.willReadFrequently = true;
|
||||||
|
// return ctx;
|
||||||
|
// }
|
||||||
try {
|
try {
|
||||||
const $webgl = document.getElementById("main-canvas");
|
const $webgl = document.getElementById("main-canvas");
|
||||||
let webgl2Supported = typeof WebGL2RenderingContext !== "undefined";
|
let webgl2Supported = typeof WebGL2RenderingContext !== "undefined";
|
||||||
@ -28,7 +157,7 @@ try {
|
|||||||
throw new Error("The browser supports WebGL2, but initialization failed.");
|
throw new Error("The browser supports WebGL2, but initialization failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e){console.error(e) }
|
} catch (e) { console.error(e) }
|
||||||
|
|
||||||
// OpenGL operates on numeric IDs while WebGL on objects. The following is a
|
// OpenGL operates on numeric IDs while WebGL on objects. The following is a
|
||||||
// hack made to allow keeping current API on the native side while resolving IDs
|
// hack made to allow keeping current API on the native side while resolving IDs
|
||||||
@ -230,7 +359,7 @@ const glBufferData = (type, count, pointer, drawType) => {
|
|||||||
// The Float32Array multiplies by size of float which is 4, and the call to
|
// The Float32Array multiplies by size of float which is 4, and the call to
|
||||||
// this method, due to OpenGL compatibility, also receives already
|
// this method, due to OpenGL compatibility, also receives already
|
||||||
// pre-multiplied value.
|
// pre-multiplied value.
|
||||||
gl.bufferData(type, zjs.memory.buffer.slice(pointer, pointer+count), drawType);
|
gl.bufferData(type, zjs.memory.buffer.slice(pointer, pointer + count), drawType);
|
||||||
};
|
};
|
||||||
|
|
||||||
const glBufferSubData = (target, offset, size, data) => {
|
const glBufferSubData = (target, offset, size, data) => {
|
||||||
@ -506,6 +635,39 @@ const webgl = {
|
|||||||
glDrawElementsInstanced,
|
glDrawElementsInstanced,
|
||||||
glBindBufferBase,
|
glBindBufferBase,
|
||||||
}
|
}
|
||||||
|
const nsToMs = (ns: number | bigint) => {
|
||||||
|
if (typeof ns === "number") {
|
||||||
|
ns = Math.trunc(ns);
|
||||||
|
}
|
||||||
|
const nsInt = BigInt(ns);
|
||||||
|
return Number(nsInt / BigInt(1000000));
|
||||||
|
};
|
||||||
|
const msToNs = (ms: number) => {
|
||||||
|
const msInt = Math.trunc(ms);
|
||||||
|
const decimal = BigInt(Math.round((ms - msInt) * 1000000));
|
||||||
|
const ns = BigInt(msInt) * BigInt(1000000);
|
||||||
|
return ns + decimal;
|
||||||
|
};
|
||||||
|
const CPUTIME_START = msToNs(perfNow());
|
||||||
|
const now = (clockId?: number) => {
|
||||||
|
switch (clockId) {
|
||||||
|
case WASI_CLOCK_MONOTONIC:
|
||||||
|
return msToNs(perfNow());
|
||||||
|
case WASI_CLOCK_REALTIME:
|
||||||
|
return msToNs(Date.now());
|
||||||
|
case WASI_CLOCK_PROCESS_CPUTIME_ID:
|
||||||
|
case WASI_CLOCK_THREAD_CPUTIME_ID: // TODO -- this assumes 1 thread
|
||||||
|
return msToNs(perfNow()) - CPUTIME_START;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let files: { polling: SharedArrayBuffer, nextFd: SharedArrayBuffer, has: SharedArrayBuffer };
|
||||||
|
export function setFiles(file) {
|
||||||
|
files = file;
|
||||||
|
}
|
||||||
|
const fdStart = 4;
|
||||||
|
|
||||||
export const importObject = {
|
export const importObject = {
|
||||||
module: {},
|
module: {},
|
||||||
env: {
|
env: {
|
||||||
@ -521,6 +683,11 @@ export const importObject = {
|
|||||||
const str = textDecoder.decode(data);
|
const str = textDecoder.decode(data);
|
||||||
console.error(str);
|
console.error(str);
|
||||||
},
|
},
|
||||||
|
eventFd() {
|
||||||
|
const next = new Int32Array(files.nextFd);
|
||||||
|
return Atomics.add(next, 0, 1);
|
||||||
|
|
||||||
|
},
|
||||||
fork: (...params) => {
|
fork: (...params) => {
|
||||||
console.error("fork", params);
|
console.error("fork", params);
|
||||||
},
|
},
|
||||||
@ -555,17 +722,32 @@ export const importObject = {
|
|||||||
},
|
},
|
||||||
wasi_snapshot_preview1: {
|
wasi_snapshot_preview1: {
|
||||||
fd_write: (fd, iovs, iovs_len, nwritten_ptr) => {
|
fd_write: (fd, iovs, iovs_len, nwritten_ptr) => {
|
||||||
const memory = new DataView(zjs.memory.buffer);
|
if (fd >= fdStart) {
|
||||||
let buf = "";
|
const memory = new DataView(zjs.memory.buffer);
|
||||||
let nwritten = 0;
|
let nwritten = 0;
|
||||||
for (let offset = iovs; offset < iovs + iovs_len * 8; offset += 8) {
|
for (let offset = iovs; offset < iovs + iovs_len * 8; offset += 8) {
|
||||||
const iov_base = memory.getUint32(offset, true);
|
const iov_len = memory.getUint32(offset + 4, true);
|
||||||
const iov_len = memory.getUint32(offset + 4, true);
|
nwritten += iov_len;
|
||||||
buf += textDecoder.decode(new Uint8ClampedArray(memory.buffer.slice(iov_base, iov_base + iov_len)).slice());
|
}
|
||||||
nwritten += iov_len;
|
const has = new Int32Array(files.has);
|
||||||
|
Atomics.store(has, fd - fdStart, 1);
|
||||||
|
Atomics.notify(has, fd - fdStart);
|
||||||
|
console.error("notify", fd);
|
||||||
|
memory.setUint32(nwritten_ptr, nwritten, true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const memory = new DataView(zjs.memory.buffer);
|
||||||
|
let buf = "";
|
||||||
|
let nwritten = 0;
|
||||||
|
for (let offset = iovs; offset < iovs + iovs_len * 8; offset += 8) {
|
||||||
|
const iov_base = memory.getUint32(offset, true);
|
||||||
|
const iov_len = memory.getUint32(offset + 4, true);
|
||||||
|
buf += textDecoder.decode(new Uint8ClampedArray(memory.buffer.slice(iov_base, iov_base + iov_len)).slice());
|
||||||
|
nwritten += iov_len;
|
||||||
|
}
|
||||||
|
memory.setUint32(nwritten_ptr, nwritten, true);
|
||||||
|
console.error(buf);
|
||||||
}
|
}
|
||||||
memory.setUint32(nwritten_ptr, nwritten, true);
|
|
||||||
console.error(buf);
|
|
||||||
},
|
},
|
||||||
fd_close: (...params) => {
|
fd_close: (...params) => {
|
||||||
console.error("fd_close", params);
|
console.error("fd_close", params);
|
||||||
@ -591,8 +773,38 @@ export const importObject = {
|
|||||||
fd_pwrite: (...params) => {
|
fd_pwrite: (...params) => {
|
||||||
console.error("fd_pwrite", params);
|
console.error("fd_pwrite", params);
|
||||||
},
|
},
|
||||||
fd_read: (...params) => {
|
fd_read(fd, iovs, iovsLen, nreadPtr) {
|
||||||
console.error("fd_read", params);
|
if (fd >= fdStart) {
|
||||||
|
const memory = new DataView(zjs.memory.buffer);
|
||||||
|
let nwritten = 0;
|
||||||
|
for (let offset = iovs; offset < iovs + iovsLen * 8; offset += 8) {
|
||||||
|
const iov_base = memory.getUint32(offset, true);
|
||||||
|
const iov_len = memory.getUint32(offset + 4, true);
|
||||||
|
// new Uint8ClampedArray(memory.buffer.slice(iov_base, iov_base + iov_len)).fill(1);
|
||||||
|
nwritten += iov_len;
|
||||||
|
memory.setUint32(nreadPtr, nwritten, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const memory = new DataView(zjs.memory.buffer);
|
||||||
|
let nwritten = 0;
|
||||||
|
for (let offset = iovs; offset < iovs + iovsLen * 8; offset += 8) {
|
||||||
|
if (bytes == null) readStdin();
|
||||||
|
if (bytes == null) break;
|
||||||
|
const iov_base = memory.getUint32(offset, true);
|
||||||
|
const iov_len = memory.getUint32(offset + 4, true);
|
||||||
|
const read = Math.min(iov_len, bytes.length);
|
||||||
|
const io = new Uint8ClampedArray(zjs.memory.buffer, iov_base, iov_len);
|
||||||
|
io.set(bytes.slice(0, read));
|
||||||
|
bytes = bytes.slice(read);
|
||||||
|
if (bytes.length === 0) bytes = null;
|
||||||
|
nwritten += read;
|
||||||
|
if (read !== iov_len) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory.setUint32(nreadPtr, nwritten, true);
|
||||||
|
if (nwritten > 0)
|
||||||
|
console.error("fd_read", nwritten);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fd_seek: (...params) => {
|
fd_seek: (...params) => {
|
||||||
console.error("fd_seek", params);
|
console.error("fd_seek", params);
|
||||||
@ -606,7 +818,207 @@ export const importObject = {
|
|||||||
path_unlink_file: (...params) => {
|
path_unlink_file: (...params) => {
|
||||||
console.error("path_unlink_file", params);
|
console.error("path_unlink_file", params);
|
||||||
},
|
},
|
||||||
poll_oneoff: (...params) => {
|
poll_oneoff(
|
||||||
|
sin: number,
|
||||||
|
sout: number,
|
||||||
|
nsubscriptions: number,
|
||||||
|
neventsPtr: number
|
||||||
|
) {
|
||||||
|
|
||||||
|
let nevents = 0;
|
||||||
|
let name = "";
|
||||||
|
|
||||||
|
// May have to wait this long (this gets computed below in the WASI_EVENTTYPE_CLOCK case).
|
||||||
|
|
||||||
|
let waitTimeNs = BigInt(0);
|
||||||
|
|
||||||
|
let fd = -1;
|
||||||
|
let fd_type: "read" | "write" = "read";
|
||||||
|
let fd_timeout_ms = 0;
|
||||||
|
|
||||||
|
const startNs = BigInt(msToNs(perfNow()));
|
||||||
|
let view = new DataView(zjs.memory.buffer);
|
||||||
|
let last_sin = sin;
|
||||||
|
for (let i = 0; i < nsubscriptions; i += 1) {
|
||||||
|
const userdata = view.getBigUint64(sin, true);
|
||||||
|
sin += 8;
|
||||||
|
const type = view.getUint8(sin);
|
||||||
|
sin += 1;
|
||||||
|
sin += 7; // padding
|
||||||
|
if (type == WASI_EVENTTYPE_CLOCK) {
|
||||||
|
name = "poll_oneoff (type=WASI_EVENTTYPE_CLOCK): ";
|
||||||
|
} else if (type == WASI_EVENTTYPE_FD_READ) {
|
||||||
|
name = "poll_oneoff (type=WASI_EVENTTYPE_FD_READ): ";
|
||||||
|
} else {
|
||||||
|
name = "poll_oneoff (type=WASI_EVENTTYPE_FD_WRITE): ";
|
||||||
|
}
|
||||||
|
console.log(name);
|
||||||
|
switch (type) {
|
||||||
|
case WASI_EVENTTYPE_CLOCK: {
|
||||||
|
// see packages/zig/dist/lib/libc/include/wasm-wasi-musl/wasi/api.h
|
||||||
|
// for exactly how these values are encoded. I carefully looked
|
||||||
|
// at that header and **this is definitely right**. Same with the fd
|
||||||
|
// in the other case below.
|
||||||
|
const clockid = view.getUint32(sin, true);
|
||||||
|
sin += 4;
|
||||||
|
sin += 4; // padding
|
||||||
|
let timeout = view.getBigUint64(sin, true);
|
||||||
|
console.log(timeout);
|
||||||
|
sin += 8;
|
||||||
|
// const precision = view.getBigUint64(sin, true);
|
||||||
|
sin += 8;
|
||||||
|
const subclockflags = view.getUint16(sin, true);
|
||||||
|
sin += 2;
|
||||||
|
sin += 6; // padding
|
||||||
|
|
||||||
|
const absolute = subclockflags === 1;
|
||||||
|
console.log(name, { clockid, timeout, absolute });
|
||||||
|
if (!absolute) {
|
||||||
|
fd_timeout_ms = Number(timeout / BigInt(1000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = WASI_ESUCCESS;
|
||||||
|
const t = now(clockid);
|
||||||
|
// logToFile(t, clockid, timeout, subclockflags, absolute);
|
||||||
|
if (t == null) {
|
||||||
|
e = WASI_EINVAL;
|
||||||
|
} else {
|
||||||
|
const end = absolute ? timeout : t + timeout;
|
||||||
|
const waitNs = end - t;
|
||||||
|
if (waitNs > waitTimeNs) {
|
||||||
|
waitTimeNs = waitNs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view = new DataView(zjs.memory.buffer);
|
||||||
|
view.setBigUint64(sout, userdata, true);
|
||||||
|
sout += 8;
|
||||||
|
view.setUint16(sout, e, true); // error
|
||||||
|
sout += 8; // pad offset 2
|
||||||
|
view.setUint8(sout, WASI_EVENTTYPE_CLOCK);
|
||||||
|
sout += 8; // pad offset 1
|
||||||
|
sout += 8; // padding to 8
|
||||||
|
|
||||||
|
nevents += 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WASI_EVENTTYPE_FD_READ:
|
||||||
|
case WASI_EVENTTYPE_FD_WRITE: {
|
||||||
|
/*
|
||||||
|
Look at
|
||||||
|
lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/sys/select/pselect.c
|
||||||
|
to see how poll_oneoff is actually used by wasi to implement pselect.
|
||||||
|
It's also used in
|
||||||
|
lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/poll/poll.c
|
||||||
|
|
||||||
|
"If none of the selected descriptors are ready for the
|
||||||
|
requested operation, the pselect() or select() function shall
|
||||||
|
block until at least one of the requested operations becomes
|
||||||
|
ready, until the timeout occurs, or until interrupted by a signal."
|
||||||
|
Thus what is supposed to happen below is supposed
|
||||||
|
to block until the fd is ready to read from or write
|
||||||
|
to, etc.
|
||||||
|
|
||||||
|
For now at least if reading from stdin then we block for a short amount
|
||||||
|
of time if getStdin defined; otherwise, we at least *pause* for a moment
|
||||||
|
(to avoid cpu burn) if this.sleep is available.
|
||||||
|
*/
|
||||||
|
fd = view.getUint32(sin, true);
|
||||||
|
fd_type = type == WASI_EVENTTYPE_FD_READ ? "read" : "write";
|
||||||
|
sin += 4;
|
||||||
|
console.log(name, "fd =", fd);
|
||||||
|
sin += 28;
|
||||||
|
let notify = true;
|
||||||
|
if (fd >= fdStart) {
|
||||||
|
const has = new Int32Array(files.has);
|
||||||
|
Atomics.wait(has, fd - fdStart, 0, 500);
|
||||||
|
if (has[fd - fdStart] == 0) {
|
||||||
|
console.warn("not notify");
|
||||||
|
notify = false;
|
||||||
|
} else {
|
||||||
|
console.warn("notify");
|
||||||
|
notify = true;
|
||||||
|
Atomics.store(has, fd - fdStart, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify) {
|
||||||
|
view = new DataView(zjs.memory.buffer);
|
||||||
|
view.setBigUint64(sout, userdata, true);
|
||||||
|
sout += 8;
|
||||||
|
view.setUint16(sout, WASI_ENOSYS, true); // error
|
||||||
|
sout += 8; // pad offset 2
|
||||||
|
view.setUint8(sout, type);
|
||||||
|
sout += 8; // pad offset 3
|
||||||
|
sout += 8; // padding to 8
|
||||||
|
|
||||||
|
nevents += 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
TODO: for now for stdin we are just doing a dumb hack.
|
||||||
|
|
||||||
|
We just do something really naive, which is "pause for a little while".
|
||||||
|
It seems to work for every application I have so far, from Python to
|
||||||
|
to ncurses, etc. This also makes it easy to have non-blocking sleep
|
||||||
|
in node.js at the terminal without a worker thread, which is very nice!
|
||||||
|
|
||||||
|
Before I had it block here via getStdin when available, but that does not work
|
||||||
|
in general; in particular, it breaks ncurses completely. In
|
||||||
|
ncurses/tty/tty_update.c
|
||||||
|
the following call is assumed not to block, and if it does, then ncurses
|
||||||
|
interaction becomes totally broken:
|
||||||
|
|
||||||
|
select(SP_PARM->_checkfd + 1, &fdset, NULL, NULL, &ktimeout)
|
||||||
|
|
||||||
|
*/
|
||||||
|
if (fd == WASI_STDIN_FILENO && WASI_EVENTTYPE_FD_READ == type) {
|
||||||
|
sleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return WASI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consistency check that we consumed exactly the right amount
|
||||||
|
// of the __wasi_subscription_t. See zig/lib/libc/include/wasm-wasi-musl/wasi/api.h
|
||||||
|
if (sin - last_sin != 48) {
|
||||||
|
console.warn("*** BUG in wasi-js in poll_oneoff ", {
|
||||||
|
i,
|
||||||
|
sin,
|
||||||
|
last_sin,
|
||||||
|
diff: sin - last_sin,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
last_sin = sin;
|
||||||
|
}
|
||||||
|
|
||||||
|
view = new DataView(zjs.memory.buffer);
|
||||||
|
view.setUint32(neventsPtr, nevents, true);
|
||||||
|
|
||||||
|
// if (nevents == 2 && fd >= 0) {
|
||||||
|
// const r = this.wasiImport.sock_pollSocket(fd, fd_type, fd_timeout_ms);
|
||||||
|
// if (r != WASI_ENOSYS) {
|
||||||
|
// // special implementation from outside
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
// // fall back to below
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Account for the time it took to do everything above, which
|
||||||
|
// can be arbitrarily long:
|
||||||
|
if (waitTimeNs > 0) {
|
||||||
|
waitTimeNs -= msToNs(perfNow()) - startNs;
|
||||||
|
// logToFile("waitTimeNs", waitTimeNs);
|
||||||
|
if (waitTimeNs >= 1000000) {
|
||||||
|
const ms = nsToMs(waitTimeNs);
|
||||||
|
sleep(ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WASI_ESUCCESS;
|
||||||
},
|
},
|
||||||
proc_exit: (...params) => {
|
proc_exit: (...params) => {
|
||||||
console.error("proc_exit", params);
|
console.error("proc_exit", params);
|
||||||
@ -632,7 +1044,7 @@ export const importObject = {
|
|||||||
},
|
},
|
||||||
clock_time_get: (_clock, _precision, ptr) => {
|
clock_time_get: (_clock, _precision, ptr) => {
|
||||||
const data = new DataView(zjs.memory.buffer);
|
const data = new DataView(zjs.memory.buffer);
|
||||||
data.setBigUint64(ptr, BigInt(Date.now()) * 1000000n, true)
|
data.setBigUint64(ptr, msToNs(perfNow()), true)
|
||||||
},
|
},
|
||||||
environ_sizes_get: (...params) => {
|
environ_sizes_get: (...params) => {
|
||||||
console.error("environ_sizes_get", params);
|
console.error("environ_sizes_get", params);
|
||||||
@ -640,11 +1052,22 @@ export const importObject = {
|
|||||||
},
|
},
|
||||||
wasi: {
|
wasi: {
|
||||||
"thread-spawn": (instance) => {
|
"thread-spawn": (instance) => {
|
||||||
const worker = new Worker(new URL("worker.ts", import.meta.url), { type: "module" });
|
if (mainThread) {
|
||||||
worker.postMessage([zjs.memory, instance]);
|
spawnWorker(instance)
|
||||||
|
} else {
|
||||||
|
postMessage([instance])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
...zjs.importObject(),
|
...zjs.importObject(),
|
||||||
};
|
};
|
||||||
|
function spawnWorker(instance) {
|
||||||
|
const worker = new Worker(new URL("worker.ts", import.meta.url), { type: "module" });
|
||||||
|
worker.postMessage([zjs.memory, instance, stdin, wasmModule, files]);
|
||||||
|
worker.onmessage = (event) => {
|
||||||
|
const [instance] = event.data;
|
||||||
|
spawnWorker(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
431
example/wasi.ts
Normal file
431
example/wasi.ts
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This project is based from the Node implementation made by Gus Caplan
|
||||||
|
https://github.com/devsnek/node-wasi
|
||||||
|
However, JavaScript WASI is focused on:
|
||||||
|
* Bringing WASI to the Browsers
|
||||||
|
* Make easy to plug different filesystems
|
||||||
|
* Provide a type-safe api using Typescript
|
||||||
|
|
||||||
|
|
||||||
|
Copyright 2019 Gus Caplan
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
deal in the Software without restriction, including without limitation the
|
||||||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const WASI_ESUCCESS = 0;
|
||||||
|
export const WASI_E2BIG = 1;
|
||||||
|
export const WASI_EACCES = 2;
|
||||||
|
export const WASI_EADDRINUSE = 3;
|
||||||
|
export const WASI_EADDRNOTAVAIL = 4;
|
||||||
|
export const WASI_EAFNOSUPPORT = 5;
|
||||||
|
export const WASI_EAGAIN = 6;
|
||||||
|
export const WASI_EALREADY = 7;
|
||||||
|
export const WASI_EBADF = 8;
|
||||||
|
export const WASI_EBADMSG = 9;
|
||||||
|
export const WASI_EBUSY = 10;
|
||||||
|
export const WASI_ECANCELED = 11;
|
||||||
|
export const WASI_ECHILD = 12;
|
||||||
|
export const WASI_ECONNABORTED = 13;
|
||||||
|
export const WASI_ECONNREFUSED = 14;
|
||||||
|
export const WASI_ECONNRESET = 15;
|
||||||
|
export const WASI_EDEADLK = 16;
|
||||||
|
export const WASI_EDESTADDRREQ = 17;
|
||||||
|
export const WASI_EDOM = 18;
|
||||||
|
export const WASI_EDQUOT = 19;
|
||||||
|
export const WASI_EEXIST = 20;
|
||||||
|
export const WASI_EFAULT = 21;
|
||||||
|
export const WASI_EFBIG = 22;
|
||||||
|
export const WASI_EHOSTUNREACH = 23;
|
||||||
|
export const WASI_EIDRM = 24;
|
||||||
|
export const WASI_EILSEQ = 25;
|
||||||
|
export const WASI_EINPROGRESS = 26;
|
||||||
|
export const WASI_EINTR = 27;
|
||||||
|
export const WASI_EINVAL = 28;
|
||||||
|
export const WASI_EIO = 29;
|
||||||
|
export const WASI_EISCONN = 30;
|
||||||
|
export const WASI_EISDIR = 31;
|
||||||
|
export const WASI_ELOOP = 32;
|
||||||
|
export const WASI_EMFILE = 33;
|
||||||
|
export const WASI_EMLINK = 34;
|
||||||
|
export const WASI_EMSGSIZE = 35;
|
||||||
|
export const WASI_EMULTIHOP = 36;
|
||||||
|
export const WASI_ENAMETOOLONG = 37;
|
||||||
|
export const WASI_ENETDOWN = 38;
|
||||||
|
export const WASI_ENETRESET = 39;
|
||||||
|
export const WASI_ENETUNREACH = 40;
|
||||||
|
export const WASI_ENFILE = 41;
|
||||||
|
export const WASI_ENOBUFS = 42;
|
||||||
|
export const WASI_ENODEV = 43;
|
||||||
|
export const WASI_ENOENT = 44;
|
||||||
|
export const WASI_ENOEXEC = 45;
|
||||||
|
export const WASI_ENOLCK = 46;
|
||||||
|
export const WASI_ENOLINK = 47;
|
||||||
|
export const WASI_ENOMEM = 48;
|
||||||
|
export const WASI_ENOMSG = 49;
|
||||||
|
export const WASI_ENOPROTOOPT = 50;
|
||||||
|
export const WASI_ENOSPC = 51;
|
||||||
|
export const WASI_ENOSYS = 52;
|
||||||
|
export const WASI_ENOTCONN = 53;
|
||||||
|
export const WASI_ENOTDIR = 54;
|
||||||
|
export const WASI_ENOTEMPTY = 55;
|
||||||
|
export const WASI_ENOTRECOVERABLE = 56;
|
||||||
|
export const WASI_ENOTSOCK = 57;
|
||||||
|
export const WASI_ENOTSUP = 58;
|
||||||
|
export const WASI_ENOTTY = 59;
|
||||||
|
export const WASI_ENXIO = 60;
|
||||||
|
export const WASI_EOVERFLOW = 61;
|
||||||
|
export const WASI_EOWNERDEAD = 62;
|
||||||
|
export const WASI_EPERM = 63;
|
||||||
|
export const WASI_EPIPE = 64;
|
||||||
|
export const WASI_EPROTO = 65;
|
||||||
|
export const WASI_EPROTONOSUPPORT = 66;
|
||||||
|
export const WASI_EPROTOTYPE = 67;
|
||||||
|
export const WASI_ERANGE = 68;
|
||||||
|
export const WASI_EROFS = 69;
|
||||||
|
export const WASI_ESPIPE = 70;
|
||||||
|
export const WASI_ESRCH = 71;
|
||||||
|
export const WASI_ESTALE = 72;
|
||||||
|
export const WASI_ETIMEDOUT = 73;
|
||||||
|
export const WASI_ETXTBSY = 74;
|
||||||
|
export const WASI_EXDEV = 75;
|
||||||
|
export const WASI_ENOTCAPABLE = 76;
|
||||||
|
|
||||||
|
export const WASI_SIGABRT = 0;
|
||||||
|
export const WASI_SIGALRM = 1;
|
||||||
|
export const WASI_SIGBUS = 2;
|
||||||
|
export const WASI_SIGCHLD = 3;
|
||||||
|
export const WASI_SIGCONT = 4;
|
||||||
|
export const WASI_SIGFPE = 5;
|
||||||
|
export const WASI_SIGHUP = 6;
|
||||||
|
export const WASI_SIGILL = 7;
|
||||||
|
export const WASI_SIGINT = 8;
|
||||||
|
export const WASI_SIGKILL = 9;
|
||||||
|
export const WASI_SIGPIPE = 10;
|
||||||
|
export const WASI_SIGQUIT = 11;
|
||||||
|
export const WASI_SIGSEGV = 12;
|
||||||
|
export const WASI_SIGSTOP = 13;
|
||||||
|
export const WASI_SIGTERM = 14;
|
||||||
|
export const WASI_SIGTRAP = 15;
|
||||||
|
export const WASI_SIGTSTP = 16;
|
||||||
|
export const WASI_SIGTTIN = 17;
|
||||||
|
export const WASI_SIGTTOU = 18;
|
||||||
|
export const WASI_SIGURG = 19;
|
||||||
|
export const WASI_SIGUSR1 = 20;
|
||||||
|
export const WASI_SIGUSR2 = 21;
|
||||||
|
export const WASI_SIGVTALRM = 22;
|
||||||
|
export const WASI_SIGXCPU = 23;
|
||||||
|
export const WASI_SIGXFSZ = 24;
|
||||||
|
|
||||||
|
export const WASI_FILETYPE_UNKNOWN = 0;
|
||||||
|
export const WASI_FILETYPE_BLOCK_DEVICE = 1;
|
||||||
|
export const WASI_FILETYPE_CHARACTER_DEVICE = 2;
|
||||||
|
export const WASI_FILETYPE_DIRECTORY = 3;
|
||||||
|
export const WASI_FILETYPE_REGULAR_FILE = 4;
|
||||||
|
export const WASI_FILETYPE_SOCKET_DGRAM = 5;
|
||||||
|
export const WASI_FILETYPE_SOCKET_STREAM = 6;
|
||||||
|
export const WASI_FILETYPE_SYMBOLIC_LINK = 7;
|
||||||
|
|
||||||
|
export type WASI_FILETYPE =
|
||||||
|
| typeof WASI_FILETYPE_UNKNOWN
|
||||||
|
| typeof WASI_FILETYPE_BLOCK_DEVICE
|
||||||
|
| typeof WASI_FILETYPE_CHARACTER_DEVICE
|
||||||
|
| typeof WASI_FILETYPE_DIRECTORY
|
||||||
|
| typeof WASI_FILETYPE_REGULAR_FILE
|
||||||
|
| typeof WASI_FILETYPE_SOCKET_DGRAM
|
||||||
|
| typeof WASI_FILETYPE_SOCKET_STREAM
|
||||||
|
| typeof WASI_FILETYPE_SYMBOLIC_LINK;
|
||||||
|
|
||||||
|
export const WASI_FDFLAG_APPEND = 0x0001;
|
||||||
|
export const WASI_FDFLAG_DSYNC = 0x0002;
|
||||||
|
export const WASI_FDFLAG_NONBLOCK = 0x0004;
|
||||||
|
export const WASI_FDFLAG_RSYNC = 0x0008;
|
||||||
|
export const WASI_FDFLAG_SYNC = 0x0010;
|
||||||
|
|
||||||
|
export const WASI_RIGHT_FD_DATASYNC = BigInt(0x0000000000000001);
|
||||||
|
export const WASI_RIGHT_FD_READ = BigInt(0x0000000000000002);
|
||||||
|
export const WASI_RIGHT_FD_SEEK = BigInt(0x0000000000000004);
|
||||||
|
export const WASI_RIGHT_FD_FDSTAT_SET_FLAGS = BigInt(0x0000000000000008);
|
||||||
|
export const WASI_RIGHT_FD_SYNC = BigInt(0x0000000000000010);
|
||||||
|
export const WASI_RIGHT_FD_TELL = BigInt(0x0000000000000020);
|
||||||
|
export const WASI_RIGHT_FD_WRITE = BigInt(0x0000000000000040);
|
||||||
|
export const WASI_RIGHT_FD_ADVISE = BigInt(0x0000000000000080);
|
||||||
|
export const WASI_RIGHT_FD_ALLOCATE = BigInt(0x0000000000000100);
|
||||||
|
export const WASI_RIGHT_PATH_CREATE_DIRECTORY = BigInt(0x0000000000000200);
|
||||||
|
export const WASI_RIGHT_PATH_CREATE_FILE = BigInt(0x0000000000000400);
|
||||||
|
export const WASI_RIGHT_PATH_LINK_SOURCE = BigInt(0x0000000000000800);
|
||||||
|
export const WASI_RIGHT_PATH_LINK_TARGET = BigInt(0x0000000000001000);
|
||||||
|
export const WASI_RIGHT_PATH_OPEN = BigInt(0x0000000000002000);
|
||||||
|
export const WASI_RIGHT_FD_READDIR = BigInt(0x0000000000004000);
|
||||||
|
export const WASI_RIGHT_PATH_READLINK = BigInt(0x0000000000008000);
|
||||||
|
export const WASI_RIGHT_PATH_RENAME_SOURCE = BigInt(0x0000000000010000);
|
||||||
|
export const WASI_RIGHT_PATH_RENAME_TARGET = BigInt(0x0000000000020000);
|
||||||
|
export const WASI_RIGHT_PATH_FILESTAT_GET = BigInt(0x0000000000040000);
|
||||||
|
export const WASI_RIGHT_PATH_FILESTAT_SET_SIZE = BigInt(0x0000000000080000);
|
||||||
|
export const WASI_RIGHT_PATH_FILESTAT_SET_TIMES = BigInt(0x0000000000100000);
|
||||||
|
export const WASI_RIGHT_FD_FILESTAT_GET = BigInt(0x0000000000200000);
|
||||||
|
export const WASI_RIGHT_FD_FILESTAT_SET_SIZE = BigInt(0x0000000000400000);
|
||||||
|
export const WASI_RIGHT_FD_FILESTAT_SET_TIMES = BigInt(0x0000000000800000);
|
||||||
|
export const WASI_RIGHT_PATH_SYMLINK = BigInt(0x0000000001000000);
|
||||||
|
export const WASI_RIGHT_PATH_REMOVE_DIRECTORY = BigInt(0x0000000002000000);
|
||||||
|
export const WASI_RIGHT_PATH_UNLINK_FILE = BigInt(0x0000000004000000);
|
||||||
|
export const WASI_RIGHT_POLL_FD_READWRITE = BigInt(0x0000000008000000);
|
||||||
|
export const WASI_RIGHT_SOCK_SHUTDOWN = BigInt(0x0000000010000000);
|
||||||
|
|
||||||
|
export const RIGHTS_ALL =
|
||||||
|
WASI_RIGHT_FD_DATASYNC |
|
||||||
|
WASI_RIGHT_FD_READ |
|
||||||
|
WASI_RIGHT_FD_SEEK |
|
||||||
|
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||||
|
WASI_RIGHT_FD_SYNC |
|
||||||
|
WASI_RIGHT_FD_TELL |
|
||||||
|
WASI_RIGHT_FD_WRITE |
|
||||||
|
WASI_RIGHT_FD_ADVISE |
|
||||||
|
WASI_RIGHT_FD_ALLOCATE |
|
||||||
|
WASI_RIGHT_PATH_CREATE_DIRECTORY |
|
||||||
|
WASI_RIGHT_PATH_CREATE_FILE |
|
||||||
|
WASI_RIGHT_PATH_LINK_SOURCE |
|
||||||
|
WASI_RIGHT_PATH_LINK_TARGET |
|
||||||
|
WASI_RIGHT_PATH_OPEN |
|
||||||
|
WASI_RIGHT_FD_READDIR |
|
||||||
|
WASI_RIGHT_PATH_READLINK |
|
||||||
|
WASI_RIGHT_PATH_RENAME_SOURCE |
|
||||||
|
WASI_RIGHT_PATH_RENAME_TARGET |
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_TIMES |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_SIZE |
|
||||||
|
WASI_RIGHT_PATH_SYMLINK |
|
||||||
|
WASI_RIGHT_PATH_UNLINK_FILE |
|
||||||
|
WASI_RIGHT_PATH_REMOVE_DIRECTORY |
|
||||||
|
WASI_RIGHT_POLL_FD_READWRITE |
|
||||||
|
WASI_RIGHT_SOCK_SHUTDOWN;
|
||||||
|
|
||||||
|
export const RIGHTS_BLOCK_DEVICE_BASE = RIGHTS_ALL;
|
||||||
|
export const RIGHTS_BLOCK_DEVICE_INHERITING = RIGHTS_ALL;
|
||||||
|
|
||||||
|
export const RIGHTS_CHARACTER_DEVICE_BASE = RIGHTS_ALL;
|
||||||
|
export const RIGHTS_CHARACTER_DEVICE_INHERITING = RIGHTS_ALL;
|
||||||
|
|
||||||
|
export const RIGHTS_REGULAR_FILE_BASE =
|
||||||
|
WASI_RIGHT_FD_DATASYNC |
|
||||||
|
WASI_RIGHT_FD_READ |
|
||||||
|
WASI_RIGHT_FD_SEEK |
|
||||||
|
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||||
|
WASI_RIGHT_FD_SYNC |
|
||||||
|
WASI_RIGHT_FD_TELL |
|
||||||
|
WASI_RIGHT_FD_WRITE |
|
||||||
|
WASI_RIGHT_FD_ADVISE |
|
||||||
|
WASI_RIGHT_FD_ALLOCATE |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_SIZE |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_TIMES |
|
||||||
|
WASI_RIGHT_POLL_FD_READWRITE;
|
||||||
|
export const RIGHTS_REGULAR_FILE_INHERITING = BigInt(0);
|
||||||
|
|
||||||
|
export const RIGHTS_DIRECTORY_BASE =
|
||||||
|
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||||
|
WASI_RIGHT_FD_SYNC |
|
||||||
|
WASI_RIGHT_FD_ADVISE |
|
||||||
|
WASI_RIGHT_PATH_CREATE_DIRECTORY |
|
||||||
|
WASI_RIGHT_PATH_CREATE_FILE |
|
||||||
|
WASI_RIGHT_PATH_LINK_SOURCE |
|
||||||
|
WASI_RIGHT_PATH_LINK_TARGET |
|
||||||
|
WASI_RIGHT_PATH_OPEN |
|
||||||
|
WASI_RIGHT_FD_READDIR |
|
||||||
|
WASI_RIGHT_PATH_READLINK |
|
||||||
|
WASI_RIGHT_PATH_RENAME_SOURCE |
|
||||||
|
WASI_RIGHT_PATH_RENAME_TARGET |
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||||
|
WASI_RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_SET_TIMES |
|
||||||
|
WASI_RIGHT_PATH_SYMLINK |
|
||||||
|
WASI_RIGHT_PATH_UNLINK_FILE |
|
||||||
|
WASI_RIGHT_PATH_REMOVE_DIRECTORY |
|
||||||
|
WASI_RIGHT_POLL_FD_READWRITE;
|
||||||
|
export const RIGHTS_DIRECTORY_INHERITING =
|
||||||
|
RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE;
|
||||||
|
|
||||||
|
export const RIGHTS_SOCKET_BASE =
|
||||||
|
WASI_RIGHT_FD_READ |
|
||||||
|
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||||
|
WASI_RIGHT_FD_WRITE |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_POLL_FD_READWRITE |
|
||||||
|
WASI_RIGHT_SOCK_SHUTDOWN;
|
||||||
|
export const RIGHTS_SOCKET_INHERITING = RIGHTS_ALL;
|
||||||
|
|
||||||
|
export const RIGHTS_TTY_BASE =
|
||||||
|
WASI_RIGHT_FD_READ |
|
||||||
|
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||||
|
WASI_RIGHT_FD_WRITE |
|
||||||
|
WASI_RIGHT_FD_FILESTAT_GET |
|
||||||
|
WASI_RIGHT_POLL_FD_READWRITE;
|
||||||
|
export const RIGHTS_TTY_INHERITING = BigInt(0);
|
||||||
|
|
||||||
|
export const WASI_CLOCK_REALTIME = 0;
|
||||||
|
export const WASI_CLOCK_MONOTONIC = 1;
|
||||||
|
export const WASI_CLOCK_PROCESS_CPUTIME_ID = 2;
|
||||||
|
export const WASI_CLOCK_THREAD_CPUTIME_ID = 3;
|
||||||
|
|
||||||
|
export const WASI_EVENTTYPE_CLOCK = 0;
|
||||||
|
export const WASI_EVENTTYPE_FD_READ = 1;
|
||||||
|
export const WASI_EVENTTYPE_FD_WRITE = 2;
|
||||||
|
|
||||||
|
export const WASI_FILESTAT_SET_ATIM = 1 << 0;
|
||||||
|
export const WASI_FILESTAT_SET_ATIM_NOW = 1 << 1;
|
||||||
|
export const WASI_FILESTAT_SET_MTIM = 1 << 2;
|
||||||
|
export const WASI_FILESTAT_SET_MTIM_NOW = 1 << 3;
|
||||||
|
|
||||||
|
export const WASI_O_CREAT = 1 << 0;
|
||||||
|
export const WASI_O_DIRECTORY = 1 << 1;
|
||||||
|
export const WASI_O_EXCL = 1 << 2;
|
||||||
|
export const WASI_O_TRUNC = 1 << 3;
|
||||||
|
|
||||||
|
export const WASI_PREOPENTYPE_DIR = 0;
|
||||||
|
|
||||||
|
export const WASI_DIRCOOKIE_START = 0;
|
||||||
|
|
||||||
|
export const WASI_STDIN_FILENO = 0;
|
||||||
|
export const WASI_STDOUT_FILENO = 1;
|
||||||
|
export const WASI_STDERR_FILENO = 2;
|
||||||
|
|
||||||
|
export const WASI_WHENCE_SET = 0;
|
||||||
|
export const WASI_WHENCE_CUR = 1;
|
||||||
|
export const WASI_WHENCE_END = 2;
|
||||||
|
|
||||||
|
// http://man7.org/linux/man-pages/man3/errno.3.html
|
||||||
|
export const ERROR_MAP: { [key: string]: number } = {
|
||||||
|
E2BIG: WASI_E2BIG,
|
||||||
|
EACCES: WASI_EACCES,
|
||||||
|
EADDRINUSE: WASI_EADDRINUSE,
|
||||||
|
EADDRNOTAVAIL: WASI_EADDRNOTAVAIL,
|
||||||
|
EAFNOSUPPORT: WASI_EAFNOSUPPORT,
|
||||||
|
EALREADY: WASI_EALREADY,
|
||||||
|
EAGAIN: WASI_EAGAIN,
|
||||||
|
// EBADE: WASI_EBADE,
|
||||||
|
EBADF: WASI_EBADF,
|
||||||
|
// EBADFD: WASI_EBADFD,
|
||||||
|
EBADMSG: WASI_EBADMSG,
|
||||||
|
// EBADR: WASI_EBADR,
|
||||||
|
// EBADRQC: WASI_EBADRQC,
|
||||||
|
// EBADSLT: WASI_EBADSLT,
|
||||||
|
EBUSY: WASI_EBUSY,
|
||||||
|
ECANCELED: WASI_ECANCELED,
|
||||||
|
ECHILD: WASI_ECHILD,
|
||||||
|
// ECHRNG: WASI_ECHRNG,
|
||||||
|
// ECOMM: WASI_ECOMM,
|
||||||
|
ECONNABORTED: WASI_ECONNABORTED,
|
||||||
|
ECONNREFUSED: WASI_ECONNREFUSED,
|
||||||
|
ECONNRESET: WASI_ECONNRESET,
|
||||||
|
EDEADLOCK: WASI_EDEADLK,
|
||||||
|
EDESTADDRREQ: WASI_EDESTADDRREQ,
|
||||||
|
EDOM: WASI_EDOM,
|
||||||
|
EDQUOT: WASI_EDQUOT,
|
||||||
|
EEXIST: WASI_EEXIST,
|
||||||
|
EFAULT: WASI_EFAULT,
|
||||||
|
EFBIG: WASI_EFBIG,
|
||||||
|
EHOSTDOWN: WASI_EHOSTUNREACH,
|
||||||
|
EHOSTUNREACH: WASI_EHOSTUNREACH,
|
||||||
|
// EHWPOISON: WASI_EHWPOISON,
|
||||||
|
EIDRM: WASI_EIDRM,
|
||||||
|
EILSEQ: WASI_EILSEQ,
|
||||||
|
EINPROGRESS: WASI_EINPROGRESS,
|
||||||
|
EINTR: WASI_EINTR,
|
||||||
|
EINVAL: WASI_EINVAL,
|
||||||
|
EIO: WASI_EIO,
|
||||||
|
EISCONN: WASI_EISCONN,
|
||||||
|
EISDIR: WASI_EISDIR,
|
||||||
|
ELOOP: WASI_ELOOP,
|
||||||
|
EMFILE: WASI_EMFILE,
|
||||||
|
EMLINK: WASI_EMLINK,
|
||||||
|
EMSGSIZE: WASI_EMSGSIZE,
|
||||||
|
EMULTIHOP: WASI_EMULTIHOP,
|
||||||
|
ENAMETOOLONG: WASI_ENAMETOOLONG,
|
||||||
|
ENETDOWN: WASI_ENETDOWN,
|
||||||
|
ENETRESET: WASI_ENETRESET,
|
||||||
|
ENETUNREACH: WASI_ENETUNREACH,
|
||||||
|
ENFILE: WASI_ENFILE,
|
||||||
|
ENOBUFS: WASI_ENOBUFS,
|
||||||
|
ENODEV: WASI_ENODEV,
|
||||||
|
ENOENT: WASI_ENOENT,
|
||||||
|
ENOEXEC: WASI_ENOEXEC,
|
||||||
|
ENOLCK: WASI_ENOLCK,
|
||||||
|
ENOLINK: WASI_ENOLINK,
|
||||||
|
ENOMEM: WASI_ENOMEM,
|
||||||
|
ENOMSG: WASI_ENOMSG,
|
||||||
|
ENOPROTOOPT: WASI_ENOPROTOOPT,
|
||||||
|
ENOSPC: WASI_ENOSPC,
|
||||||
|
ENOSYS: WASI_ENOSYS,
|
||||||
|
ENOTCONN: WASI_ENOTCONN,
|
||||||
|
ENOTDIR: WASI_ENOTDIR,
|
||||||
|
ENOTEMPTY: WASI_ENOTEMPTY,
|
||||||
|
ENOTRECOVERABLE: WASI_ENOTRECOVERABLE,
|
||||||
|
ENOTSOCK: WASI_ENOTSOCK,
|
||||||
|
ENOTTY: WASI_ENOTTY,
|
||||||
|
ENXIO: WASI_ENXIO,
|
||||||
|
EOVERFLOW: WASI_EOVERFLOW,
|
||||||
|
EOWNERDEAD: WASI_EOWNERDEAD,
|
||||||
|
EPERM: WASI_EPERM,
|
||||||
|
EPIPE: WASI_EPIPE,
|
||||||
|
EPROTO: WASI_EPROTO,
|
||||||
|
EPROTONOSUPPORT: WASI_EPROTONOSUPPORT,
|
||||||
|
EPROTOTYPE: WASI_EPROTOTYPE,
|
||||||
|
ERANGE: WASI_ERANGE,
|
||||||
|
EROFS: WASI_EROFS,
|
||||||
|
ESPIPE: WASI_ESPIPE,
|
||||||
|
ESRCH: WASI_ESRCH,
|
||||||
|
ESTALE: WASI_ESTALE,
|
||||||
|
ETIMEDOUT: WASI_ETIMEDOUT,
|
||||||
|
ETXTBSY: WASI_ETXTBSY,
|
||||||
|
EXDEV: WASI_EXDEV
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SIGNAL_MAP: { [key: string]: string } = {
|
||||||
|
[WASI_SIGHUP]: "SIGHUP",
|
||||||
|
[WASI_SIGINT]: "SIGINT",
|
||||||
|
[WASI_SIGQUIT]: "SIGQUIT",
|
||||||
|
[WASI_SIGILL]: "SIGILL",
|
||||||
|
[WASI_SIGTRAP]: "SIGTRAP",
|
||||||
|
[WASI_SIGABRT]: "SIGABRT",
|
||||||
|
[WASI_SIGBUS]: "SIGBUS",
|
||||||
|
[WASI_SIGFPE]: "SIGFPE",
|
||||||
|
[WASI_SIGKILL]: "SIGKILL",
|
||||||
|
[WASI_SIGUSR1]: "SIGUSR1",
|
||||||
|
[WASI_SIGSEGV]: "SIGSEGV",
|
||||||
|
[WASI_SIGUSR2]: "SIGUSR2",
|
||||||
|
[WASI_SIGPIPE]: "SIGPIPE",
|
||||||
|
[WASI_SIGALRM]: "SIGALRM",
|
||||||
|
[WASI_SIGTERM]: "SIGTERM",
|
||||||
|
[WASI_SIGCHLD]: "SIGCHLD",
|
||||||
|
[WASI_SIGCONT]: "SIGCONT",
|
||||||
|
[WASI_SIGSTOP]: "SIGSTOP",
|
||||||
|
[WASI_SIGTSTP]: "SIGTSTP",
|
||||||
|
[WASI_SIGTTIN]: "SIGTTIN",
|
||||||
|
[WASI_SIGTTOU]: "SIGTTOU",
|
||||||
|
[WASI_SIGURG]: "SIGURG",
|
||||||
|
[WASI_SIGXCPU]: "SIGXCPU",
|
||||||
|
[WASI_SIGXFSZ]: "SIGXFSZ",
|
||||||
|
[WASI_SIGVTALRM]: "SIGVTALRM"
|
||||||
|
};
|
@ -1,11 +1,14 @@
|
|||||||
import { importObject, zjs } from "./imports";
|
import { importObject, setFiles, setMainThread, setStdin, zjs } from "./imports";
|
||||||
|
|
||||||
onmessage = async (e) => {
|
onmessage = async (e) => {
|
||||||
console.log("module received from main thread");
|
console.log("module received from main thread");
|
||||||
const [memory, instance] = e.data;
|
const [memory, instance, stdin, wasmModule, files] = e.data;
|
||||||
|
console.log(wasmModule)
|
||||||
|
setStdin(stdin);
|
||||||
|
setMainThread(false);
|
||||||
|
setFiles(files);
|
||||||
importObject.env.memory = memory;
|
importObject.env.memory = memory;
|
||||||
const url = new URL("ghostty-wasm.wasm", import.meta.url);
|
const results = await WebAssembly.instantiate(wasmModule, importObject);
|
||||||
const results = await WebAssembly.instantiateStreaming(fetch(url), importObject)
|
|
||||||
zjs.memory = memory;
|
zjs.memory = memory;
|
||||||
results.instance.exports.wasi_thread_start(100, instance);
|
results.exports.wasi_thread_start(100, instance);
|
||||||
};
|
};
|
||||||
|
@ -203,48 +203,9 @@ fn startWasi(self: *Command, arena: Allocator) !void {
|
|||||||
else
|
else
|
||||||
@compileError("missing env vars");
|
@compileError("missing env vars");
|
||||||
|
|
||||||
// Fork. If we have a cgroup specified on Linxu then we use clone
|
self.pid = 100;
|
||||||
const pid: posix.pid_t = switch (builtin.os.tag) {
|
|
||||||
.linux => if (self.linux_cgroup) |cgroup|
|
|
||||||
try internal_os.cgroup.cloneInto(cgroup)
|
|
||||||
else
|
|
||||||
try posix.fork(),
|
|
||||||
|
|
||||||
else => try posix.fork(),
|
std.log.err("need to fork {s} {*}", .{ pathZ, envp });
|
||||||
};
|
|
||||||
|
|
||||||
if (pid != 0) {
|
|
||||||
// Parent, return immediately.
|
|
||||||
self.pid = @intCast(pid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are the child.
|
|
||||||
|
|
||||||
// Setup our file descriptors for std streams.
|
|
||||||
if (self.stdin) |f| setupFd(f.handle, posix.STDIN_FILENO) catch
|
|
||||||
return error.ExecFailedInChild;
|
|
||||||
if (self.stdout) |f| setupFd(f.handle, posix.STDOUT_FILENO) catch
|
|
||||||
return error.ExecFailedInChild;
|
|
||||||
if (self.stderr) |f| setupFd(f.handle, posix.STDERR_FILENO) catch
|
|
||||||
return error.ExecFailedInChild;
|
|
||||||
|
|
||||||
// Setup our working directory
|
|
||||||
if (self.cwd) |cwd| posix.chdir(cwd) catch {
|
|
||||||
// This can fail if we don't have permission to go to
|
|
||||||
// this directory or if due to race conditions it doesn't
|
|
||||||
// exist or any various other reasons. We don't want to
|
|
||||||
// crash the entire process if this fails so we ignore it.
|
|
||||||
// We don't log because that'll show up in the output.
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the user requested a pre exec callback, call it now.
|
|
||||||
if (self.pre_exec) |f| f(self);
|
|
||||||
std.log.err("{s} {*}", .{ pathZ, envp });
|
|
||||||
|
|
||||||
// If we are executing this code, the exec failed. In that scenario,
|
|
||||||
// we return a very specific error that can be detected to determine
|
|
||||||
// we're in the child.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +29,6 @@ pub const Face = struct {
|
|||||||
/// Metrics for this font face. These are useful for renderers.
|
/// Metrics for this font face. These are useful for renderers.
|
||||||
metrics: font.face.Metrics,
|
metrics: font.face.Metrics,
|
||||||
|
|
||||||
/// The canvas element that we will reuse to render glyphs
|
|
||||||
canvas: js.Object,
|
|
||||||
|
|
||||||
/// The map to store multi-codepoint grapheme clusters that are rendered.
|
/// The map to store multi-codepoint grapheme clusters that are rendered.
|
||||||
/// We use 1 above the maximum unicode codepoint up to the max 32-bit
|
/// We use 1 above the maximum unicode codepoint up to the max 32-bit
|
||||||
/// unsigned integer to store the "glyph index" for graphemes.
|
/// unsigned integer to store the "glyph index" for graphemes.
|
||||||
@ -58,20 +55,12 @@ pub const Face = struct {
|
|||||||
const font_str = try alloc.dupe(u8, raw);
|
const font_str = try alloc.dupe(u8, raw);
|
||||||
errdefer alloc.free(font_str);
|
errdefer alloc.free(font_str);
|
||||||
|
|
||||||
// Create our canvasxx that we're going to continue to reuse.
|
|
||||||
const OffscreenCanvas = try js.global.get(js.Object, "OffscreenCanvas");
|
|
||||||
defer OffscreenCanvas.deinit();
|
|
||||||
const canvas = try OffscreenCanvas.new(.{ 0, 0 });
|
|
||||||
errdefer canvas.deinit();
|
|
||||||
|
|
||||||
var result = Face{
|
var result = Face{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.font_str = font_str,
|
.font_str = font_str,
|
||||||
.size = size,
|
.size = size,
|
||||||
.presentation = presentation,
|
.presentation = presentation,
|
||||||
|
|
||||||
.canvas = canvas,
|
|
||||||
|
|
||||||
// We're going to calculate these right after initialization.
|
// We're going to calculate these right after initialization.
|
||||||
.metrics = undefined,
|
.metrics = undefined,
|
||||||
};
|
};
|
||||||
@ -89,7 +78,6 @@ pub const Face = struct {
|
|||||||
while (it.next()) |value| self.alloc.free(value.*);
|
while (it.next()) |value| self.alloc.free(value.*);
|
||||||
self.glyph_to_grapheme.deinit(self.alloc);
|
self.glyph_to_grapheme.deinit(self.alloc);
|
||||||
}
|
}
|
||||||
self.canvas.deinit();
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,13 +279,15 @@ pub const Face = struct {
|
|||||||
fn context(self: Face) !js.Object {
|
fn context(self: Face) !js.Object {
|
||||||
// This will return the same context on subsequent calls so it
|
// This will return the same context on subsequent calls so it
|
||||||
// is important to reset it.
|
// is important to reset it.
|
||||||
const ctx = try self.canvas.call(js.Object, "getContext", .{js.string("2d")});
|
const canvas = try js.global.get(js.Object, "fontCanvas");
|
||||||
|
defer canvas.deinit();
|
||||||
|
const ctx = try canvas.call(js.Object, "getContext", .{js.string("2d")});
|
||||||
errdefer ctx.deinit();
|
errdefer ctx.deinit();
|
||||||
|
|
||||||
// Clear the canvas
|
// Clear the canvas
|
||||||
{
|
{
|
||||||
const width = try self.canvas.get(f64, "width");
|
const width = try canvas.get(f64, "width");
|
||||||
const height = try self.canvas.get(f64, "height");
|
const height = try canvas.get(f64, "height");
|
||||||
try ctx.call(void, "clearRect", .{ 0, 0, width, height });
|
try ctx.call(void, "clearRect", .{ 0, 0, width, height });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,8 +418,10 @@ pub const Face = struct {
|
|||||||
|
|
||||||
// Resize canvas to match the glyph size exactly
|
// Resize canvas to match the glyph size exactly
|
||||||
{
|
{
|
||||||
try self.canvas.set("width", width);
|
const canvas = try js.global.get(js.Object, "fontCanvas");
|
||||||
try self.canvas.set("height", height);
|
defer canvas.deinit();
|
||||||
|
try canvas.set("width", width);
|
||||||
|
try canvas.set("height", height);
|
||||||
|
|
||||||
// const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{width});
|
// const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{width});
|
||||||
// defer alloc.free(width_str);
|
// defer alloc.free(width_str);
|
||||||
@ -562,25 +554,25 @@ pub const Wasm = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn face_debug_canvas(face: *Face) void {
|
// export fn face_debug_canvas(face: *Face) void {
|
||||||
face_debug_canvas_(face) catch |err| {
|
// face_debug_canvas_(face) catch |err| {
|
||||||
log.warn("error adding debug canvas err={}", .{err});
|
// log.warn("error adding debug canvas err={}", .{err});
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn face_debug_canvas_(face: *Face) !void {
|
// fn face_debug_canvas_(face: *Face) !void {
|
||||||
const doc = try js.global.get(js.Object, "document");
|
// const doc = try js.global.get(js.Object, "document");
|
||||||
defer doc.deinit();
|
// defer doc.deinit();
|
||||||
|
|
||||||
const elem = try doc.call(
|
// const elem = try doc.call(
|
||||||
?js.Object,
|
// ?js.Object,
|
||||||
"getElementById",
|
// "getElementById",
|
||||||
.{js.string("face-canvas")},
|
// .{js.string("face-canvas")},
|
||||||
) orelse return error.CanvasContainerNotFound;
|
// ) orelse return error.CanvasContainerNotFound;
|
||||||
defer elem.deinit();
|
// defer elem.deinit();
|
||||||
|
|
||||||
try elem.call(void, "append", .{face.canvas});
|
// try elem.call(void, "append", .{face.canvas});
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn face_render_glyph_(face: *Face, atlas: *font.Atlas, codepoint: u32) !*font.Glyph {
|
fn face_render_glyph_(face: *Face, atlas: *font.Atlas, codepoint: u32) !*font.Glyph {
|
||||||
const glyph = try face.renderGlyph(alloc, atlas, codepoint, .{});
|
const glyph = try face.renderGlyph(alloc, atlas, codepoint, .{});
|
||||||
|
@ -26,6 +26,14 @@ export fn run(str: [*]const u8, len: usize) void {
|
|||||||
std.log.err("err: {?}", .{err});
|
std.log.err("err: {?}", .{err});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var surf: ?*Surface = null;
|
||||||
|
export fn draw() void {
|
||||||
|
surf.?.renderer.drawFrame(surf.?.rt_surface) catch |err| {
|
||||||
|
std.log.err("err: {?}", .{err});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn run_(str: []const u8) !void {
|
fn run_(str: []const u8) !void {
|
||||||
var config = try Config.default(alloc);
|
var config = try Config.default(alloc);
|
||||||
var fbs = std.io.fixedBufferStream(str);
|
var fbs = std.io.fixedBufferStream(str);
|
||||||
@ -41,28 +49,29 @@ fn run_(str: []const u8) !void {
|
|||||||
try surface.init(alloc, &config, app, &app_runtime, apprt_surface);
|
try surface.init(alloc, &config, app, &app_runtime, apprt_surface);
|
||||||
std.log.err("{}", .{surface.size});
|
std.log.err("{}", .{surface.size});
|
||||||
try surface.renderer.setScreenSize(surface.size);
|
try surface.renderer.setScreenSize(surface.size);
|
||||||
const esc = "\x1b[";
|
surf = surface;
|
||||||
surface.io.processOutput("M_yhelloaaaaaaaaa\n\r🐏\n\r👍🏽\n\rM_ghostty" ++ esc ++ "2;2H" ++ esc ++ "48;2;240;40;40m" ++ esc ++ "38;2;23;255;80mhello");
|
// const esc = "\x1b[";
|
||||||
// try surface.renderer_state.terminal.printString("M_yhelloaaaaaaaaa\n🐏\n👍🏽\nM_ghostty");
|
// surface.io.processOutput("M_yhelloaaaaaaaaa\n\r🐏\n\r👍🏽\n\rM_ghostty" ++ esc ++ "2;2H" ++ esc ++ "48;2;240;40;40m" ++ esc ++ "38;2;23;255;80mhello");
|
||||||
// surface.renderer_state.terminal.setCursorPos(4, 2);
|
// // try surface.renderer_state.terminal.printString("M_yhelloaaaaaaaaa\n🐏\n👍🏽\nM_ghostty");
|
||||||
// try surface.renderer_state.terminal.setAttribute(.{ .direct_color_bg = .{
|
// // surface.renderer_state.terminal.setCursorPos(4, 2);
|
||||||
// .r = 240,
|
// // try surface.renderer_state.terminal.setAttribute(.{ .direct_color_bg = .{
|
||||||
// .g = 40,
|
// // .r = 240,
|
||||||
// .b = 40,
|
// // .g = 40,
|
||||||
// } });
|
// // .b = 40,
|
||||||
// try surface.renderer_state.terminal.setAttribute(.{ .direct_color_fg = .{
|
// // } });
|
||||||
// .r = 255,
|
// // try surface.renderer_state.terminal.setAttribute(.{ .direct_color_fg = .{
|
||||||
// .g = 255,
|
// // .r = 255,
|
||||||
// .b = 255,
|
// // .g = 255,
|
||||||
// } });
|
// // .b = 255,
|
||||||
// try surface.renderer_state.terminal.printString("hello");
|
// // } });
|
||||||
try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false);
|
// // try surface.renderer_state.terminal.printString("hello");
|
||||||
try surface.renderer.drawFrame(apprt_surface);
|
// try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false);
|
||||||
try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false);
|
// try surface.renderer.drawFrame(apprt_surface);
|
||||||
try surface.renderer.drawFrame(apprt_surface);
|
// try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false);
|
||||||
|
// try surface.renderer.drawFrame(apprt_surface);
|
||||||
|
|
||||||
// const webgl = try renderer.OpenGL.init(alloc, .{ .config = try renderer.OpenGL.DerivedConfig.init(alloc, &config) });
|
// // const webgl = try renderer.OpenGL.init(alloc, .{ .config = try renderer.OpenGL.DerivedConfig.init(alloc, &config) });
|
||||||
// _ = webgl;
|
// // _ = webgl;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
pub const std_options: std.Options = .{
|
||||||
|
@ -683,6 +683,7 @@ pub fn updateFrame(
|
|||||||
) !void {
|
) !void {
|
||||||
_ = surface;
|
_ = surface;
|
||||||
|
|
||||||
|
std.log.err("update frame", .{});
|
||||||
// Data we extract out of the critical area.
|
// Data we extract out of the critical area.
|
||||||
const Critical = struct {
|
const Critical = struct {
|
||||||
full_rebuild: bool,
|
full_rebuild: bool,
|
||||||
@ -701,6 +702,7 @@ pub fn updateFrame(
|
|||||||
|
|
||||||
state.mutex.lock();
|
state.mutex.lock();
|
||||||
defer state.mutex.unlock();
|
defer state.mutex.unlock();
|
||||||
|
std.log.err("critical", .{});
|
||||||
|
|
||||||
// If we're in a synchronized output state, we pause all rendering.
|
// If we're in a synchronized output state, we pause all rendering.
|
||||||
if (state.terminal.modes.get(.synchronized_output)) {
|
if (state.terminal.modes.get(.synchronized_output)) {
|
||||||
@ -2229,8 +2231,9 @@ fn flushAtlasSingle(
|
|||||||
/// the cells.
|
/// the cells.
|
||||||
pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void {
|
pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void {
|
||||||
// If we're in single-threaded more we grab a lock since we use shared data.
|
// If we're in single-threaded more we grab a lock since we use shared data.
|
||||||
if (single_threaded_draw) self.draw_mutex.lock();
|
// wasm can't use a mutex on the main thread because it uses Atomic.wait
|
||||||
defer if (single_threaded_draw) self.draw_mutex.unlock();
|
if (single_threaded_draw and builtin.cpu.arch != .wasm32) self.draw_mutex.lock();
|
||||||
|
defer if (single_threaded_draw and builtin.cpu.arch != .wasm32) self.draw_mutex.unlock();
|
||||||
const gl_state: *GLState = if (self.gl_state) |*v| v else return;
|
const gl_state: *GLState = if (self.gl_state) |*v| v else return;
|
||||||
|
|
||||||
// Go through our images and see if we need to setup any textures.
|
// Go through our images and see if we need to setup any textures.
|
||||||
|
@ -232,7 +232,7 @@ fn threadMain_(self: *Thread) !void {
|
|||||||
self.startDrawTimer();
|
self.startDrawTimer();
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
log.debug("starting renderer thread", .{});
|
log.err("starting renderer thread", .{});
|
||||||
defer log.debug("starting renderer thread shutdown", .{});
|
defer log.debug("starting renderer thread shutdown", .{});
|
||||||
_ = try self.loop.run(.until_done);
|
_ = try self.loop.run(.until_done);
|
||||||
}
|
}
|
||||||
@ -437,6 +437,7 @@ fn wakeupCallback(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const t = self_.?;
|
const t = self_.?;
|
||||||
|
log.err("wakeup", .{});
|
||||||
|
|
||||||
// When we wake up, we check the mailbox. Mailbox producers should
|
// When we wake up, we check the mailbox. Mailbox producers should
|
||||||
// wake up our thread after publishing.
|
// wake up our thread after publishing.
|
||||||
|
@ -126,7 +126,7 @@ pub fn threadEnter(
|
|||||||
|
|
||||||
// Start our read thread
|
// Start our read thread
|
||||||
const read_thread = try std.Thread.spawn(
|
const read_thread = try std.Thread.spawn(
|
||||||
.{},
|
.{ .allocator = alloc },
|
||||||
if (builtin.os.tag == .windows) ReadThread.threadMainWindows else ReadThread.threadMainPosix,
|
if (builtin.os.tag == .windows) ReadThread.threadMainWindows else ReadThread.threadMainPosix,
|
||||||
.{ pty_fds.read, io, pipe[0] },
|
.{ pty_fds.read, io, pipe[0] },
|
||||||
);
|
);
|
||||||
@ -1424,6 +1424,7 @@ pub const ReadThread = struct {
|
|||||||
// child process dies. To be safe, we just break the loop
|
// child process dies. To be safe, we just break the loop
|
||||||
// and let our poll happen.
|
// and let our poll happen.
|
||||||
if (n == 0) break;
|
if (n == 0) break;
|
||||||
|
std.log.err("{} {} {}", .{ buf[0], n, @intFromPtr(&buf) });
|
||||||
|
|
||||||
// log.info("DATA: {d}", .{n});
|
// log.info("DATA: {d}", .{n});
|
||||||
@call(.always_inline, termio.Termio.processOutput, .{ io, buf[0..n] });
|
@call(.always_inline, termio.Termio.processOutput, .{ io, buf[0..n] });
|
||||||
|
@ -554,6 +554,7 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void {
|
|||||||
// use a timer under the covers
|
// use a timer under the covers
|
||||||
if (internal_os.Instant.now()) |now| cursor_reset: {
|
if (internal_os.Instant.now()) |now| cursor_reset: {
|
||||||
if (self.last_cursor_reset) |last| {
|
if (self.last_cursor_reset) |last| {
|
||||||
|
log.err("now: {} last: {}", .{ now, last });
|
||||||
if (now.since(last) <= (500 * std.time.ns_per_ms)) {
|
if (now.since(last) <= (500 * std.time.ns_per_ms)) {
|
||||||
break :cursor_reset;
|
break :cursor_reset;
|
||||||
}
|
}
|
||||||
@ -571,6 +572,7 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void {
|
|||||||
// process a byte at a time alternating between the inspector handler
|
// process a byte at a time alternating between the inspector handler
|
||||||
// and the termio handler. This is very slow compared to our optimizations
|
// and the termio handler. This is very slow compared to our optimizations
|
||||||
// below but at least users only pay for it if they're using the inspector.
|
// below but at least users only pay for it if they're using the inspector.
|
||||||
|
std.log.err("to print {s}", .{buf});
|
||||||
if (builtin.cpu.arch == .wasm32) {
|
if (builtin.cpu.arch == .wasm32) {
|
||||||
self.terminal_stream.nextSlice(buf) catch |err|
|
self.terminal_stream.nextSlice(buf) catch |err|
|
||||||
log.err("error processing terminal data: {}", .{err});
|
log.err("error processing terminal data: {}", .{err});
|
||||||
|
Reference in New Issue
Block a user