Add process manager

This commit is contained in:
2025-11-23 18:52:51 +01:00
parent 6f303bf656
commit 1775af99b0
19 changed files with 428 additions and 23 deletions

View File

@@ -146,6 +146,22 @@ duk_ret_t native_word_out(duk_context *ctx)
// Global context for IRQ handlers
duk_context *global_ctx = NULL;
// Pending heaps to destroy
duk_context *pending_heaps[16];
int pending_heaps_count = 0;
void process_pending_heaps()
{
for (int i = 0; i < pending_heaps_count; i++)
{
if (pending_heaps[i] != NULL)
{
duk_destroy_heap(pending_heaps[i]);
}
}
pending_heaps_count = 0;
}
// JavaScript IRQ wrapper
void js_irq_callback(registers_t *r)
{
@@ -187,6 +203,9 @@ void js_irq_callback(registers_t *r)
}
duk_pop(global_ctx); // Pop stash
// Process any pending heaps
process_pending_heaps();
}
// Native function to register IRQ from JavaScript
@@ -616,10 +635,29 @@ duk_ret_t native_isolated_exec(duk_context *ctx)
// duk_destroy_heap(isolated_ctx);
// Return success/failure
duk_push_boolean(ctx, success);
// Return the heap pointer as a number (uint32_t)
duk_push_uint(ctx, (duk_uint_t)isolated_ctx);
return 1;
}
// Native function to destroy an isolated heap
duk_ret_t native_destroy_isolated_heap(duk_context *ctx)
{
// Get the heap pointer
duk_uint_t heap_ptr = duk_require_uint(ctx, 0);
duk_context *isolated_ctx = (duk_context *)heap_ptr;
if (isolated_ctx != NULL)
{
if (pending_heaps_count < 16)
{
pending_heaps[pending_heaps_count++] = isolated_ctx;
}
}
return 0;
}
void kmain()
{
// Initialize IDT and ISRs
@@ -674,6 +712,10 @@ void kmain()
duk_push_c_function(ctx, native_isolated_exec, 1);
duk_put_global_string(ctx, "$isolatedExec");
// Register native isolated heap destruction function
duk_push_c_function(ctx, native_destroy_isolated_heap, 1);
duk_put_global_string(ctx, "$destroyIsolatedHeap");
// Enable interrupts before JavaScript execution
__asm__ volatile("sti");

View File

@@ -35,6 +35,9 @@ export function devfs_driver(): KFilesystemDriver {
stat(path: string): KFilesystemStat | null {
return devfs_statEntity(path);
},
rm(path: string): void {
throw new Error("Cannot remove objects in devfs.")
}
};
}

View File

@@ -75,6 +75,9 @@ export function fat32_driver(driver: any, data: any): KFilesystemDriver {
directRead(path: string, count: number, offset: number) {
return fat32_directRead(state, path, count, offset);
},
rm(path: string): void {
throw new Error("Cannot remove objects in fat32.");
},
};
}

View File

@@ -0,0 +1,168 @@
import { Logger } from "../../lib/libstd/logger/logger.kmod";
import { Path } from "../../lib/libstd/path";
import type {
KFilesystemDriver,
KFilesystemEntity,
KFilesystemMemdata,
KFilesystemStat,
} from "../../types/filesystem/fs";
const procfs_data: KFilesystemMemdata = [];
export function procfs_driver(): KFilesystemDriver {
return {
id: "procfs",
init: procfs_init,
listDir(path: string): KFilesystemEntity[] | null {
return procfs_listDir(path);
},
readFile(path: string): unknown {
return procfs_readFile(path);
},
writeFile(path: string, content: unknown): void {
throw new Error("Cannot write files in procfs.");
},
createFile(path: string, content: unknown): void {
throw new Error("Cannot create files in procfs.");
},
mkdir(path: string): void {
throw new Error("Cannot make directories in procfs.");
},
stat(path: string): KFilesystemStat | null {
return procfs_statEntity(path);
},
rm(path: string): void {
procfs_rm(path);
},
};
}
export function procfs_init(): void {
procfs_data.push({
name: "root",
path: "/",
type: "folder",
size: 0,
contents: null,
});
}
export function procfs_getEntity(path: string): KFilesystemEntity | null {
for (let i = 0; i < procfs_data.length; i++) {
const entity = procfs_data[i]!;
if (entity.path === path) return entity;
}
return null;
}
export function procfs_statEntity(path: string): KFilesystemStat | null {
const entity = procfs_getEntity(path);
if (!entity) return null;
return {
name: entity.name,
type: entity.type,
size: entity.size,
};
}
export function procfs_mkdir(path: string): void {
if (procfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!procfs_getEntity(parent)) return;
procfs_data.push({
name: Path.filename(path),
path,
type: "folder",
size: 0,
contents: null,
});
}
export function procfs_createFile(path: string, content: unknown): void {
if (procfs_getEntity(path)) return;
const parent = Path.dirname(path);
if (!procfs_getEntity(parent)) return;
const size = String(content).length;
procfs_data.push({
name: Path.filename(path),
path,
type: "file",
size,
contents: content,
});
}
export function procfs_writeFile(path: string, content: unknown): void {
const entity = procfs_getEntity(path);
if (!entity) return procfs_createFile(path, content);
if (entity.type !== "file") return;
entity.contents = content;
entity.size = String(content).length;
}
export function procfs_readFile(path: string): unknown {
const entity = procfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "file") return null;
return entity.contents;
}
export function procfs_listDir(path: string): KFilesystemEntity[] | null {
const entity = procfs_getEntity(path);
if (!entity) return null;
if (entity.type !== "folder") return null;
const contents: KFilesystemEntity[] = [];
for (let i = 0; i < procfs_data.length; i++) {
const e = procfs_data[i]!;
if (Path.dirname(e.path) === path) {
contents.push(e);
}
}
return contents;
}
export function procfs_rm(path: string): void {
const entity = procfs_getEntity(path);
if (!entity) return;
if (entity.type === "file") {
const index = procfs_data.indexOf(entity);
if (index !== -1) procfs_data.splice(index, 1);
} else if (entity.type === "folder") {
const entitiesToRemove: KFilesystemEntity[] = [];
const pathPrefix = path === "/" ? "/" : path + "/";
for (let i = 0; i < procfs_data.length; i++) {
const e = procfs_data[i]!;
if (e.path === path || e.path.startsWith(pathPrefix)) {
entitiesToRemove.push(e);
}
}
for (let i = 0; i < entitiesToRemove.length; i++) {
const toRemove = entitiesToRemove[i]!;
const index = procfs_data.indexOf(toRemove);
if (index !== -1) procfs_data.splice(index, 1);
}
}
}

View File

@@ -31,6 +31,9 @@ export function sysfs_driver(): KFilesystemDriver {
stat(path: string): KFilesystemStat | null {
return sysfs_statEntity(path);
},
rm(path: string): void {
throw new Error("Cannot remove objects in sysfs.");
},
};
}

View File

@@ -11,6 +11,7 @@ import {
} from "./drivers/etc/serial";
import { devfs_driver, devfs_getDevice } from "./filesystem/devfs";
import { fat32_driver } from "./filesystem/fat32";
import { procfs_driver } from "./filesystem/procfs";
import { sysfs_driver, sysfs_readFile } from "./filesystem/sysfs";
import { kmod_app_init, kmod_app_run } from "./modules/app/app.kmod";
import { kmod_disks_detectDisks } from "./modules/disks/disks.kmod";
@@ -48,6 +49,7 @@ export function kmain() {
kmod_filesystem_init();
kmod_filesystem_mount("/sys", sysfs_driver);
kmod_filesystem_mount("/dev", devfs_driver);
kmod_filesystem_mount("/proc", procfs_driver);
Logger.log("[Kernel] Initializing terminal module...");
kmod_terminal_input_init();
@@ -72,5 +74,5 @@ export function kmain() {
const shell = uiarrtostr(kmod_filesystem_readFile("/disk/ushellc")!);
kmod_app_run(shell);
kmod_app_run(shell, "");
}

View File

@@ -9,12 +9,21 @@ import {
} from "../filesystem/filesystem.kmod";
import { oskrnl_register } from "../../../oskrnl";
import { getPathEnv } from "../../../lib/sys/env";
import {
procfs_mkdir,
procfs_readFile,
procfs_rm,
procfs_writeFile,
} from "../../filesystem/procfs";
const exitListeners: { [pid: string]: (() => void)[] } = {};
const heapHandles: { [pid: string]: number } = {};
export function kmod_app_init() {
oskrnl_register();
}
export function kmod_app_run(path: string) {
export function kmod_app_run(path: string, args: string) {
const appPath = kmod_app_resolve(path);
if (!appPath) throw new Error("App not found");
@@ -27,7 +36,15 @@ export function kmod_app_run(path: string) {
const entrypoint = Path.join(appPath, meta["app:entrypoint"]);
const code = uiarrtostr(kmod_filesystem_readFile(entrypoint)!);
iexec(code);
const pid = kmod_app_proc_generateId().toString();
kmod_app_proc_init(pid, meta["app:name"]!, args);
kmod_app_proc_registerHandle(pid, "app");
const heapHandle = iexec("var __oskrnl_procd_pid = " + pid + ";\n" + code);
if (heapHandle) heapHandles[pid] = heapHandle;
kmod_app_proc_unregisterHandle(pid, "app");
return pid;
}
export function kmod_app_resolve(path: string): string | null {
@@ -43,3 +60,93 @@ export function kmod_app_resolve(path: string): string | null {
return null;
}
export function kmod_app_proc_generateId(): number {
return Math.floor(Math.random() * 0xffffffff);
}
export function kmod_app_proc_init(id: string, name: string, args: string) {
const root = "/" + id;
procfs_mkdir(root);
procfs_writeFile(Path.join(root, "name"), name);
procfs_writeFile(Path.join(root, "args"), args);
procfs_writeFile(Path.join(root, "pid"), id);
procfs_writeFile(Path.join(root, "handles"), "");
}
export function kmod_app_proc_getArgs(pid: string): string {
const res = procfs_readFile(Path.join("/" + pid, "args"));
return res as string;
}
export function kmod_app_proc_registerHandle(
pid: string,
handle: string
): string {
const handles = procfs_readFile(Path.join("/" + pid, "handles")) as string;
const handlesArr = handles == "" ? [] : handles.split(",");
handlesArr.push(handle);
procfs_writeFile(Path.join("/" + pid, "handles"), handlesArr.join(","));
return handle;
}
export function kmod_app_proc_unregisterHandle(
pid: string,
handle: string
): void {
const handles = procfs_readFile(Path.join("/" + pid, "handles")) as string;
if (handles == "") return;
const handlesArr = handles.split(",");
handlesArr.splice(handlesArr.indexOf(handle), 1);
procfs_writeFile(Path.join("/" + pid, "handles"), handlesArr.join(","));
if (handlesArr.length < 1) kmod_app_proc_handleExit(pid);
}
export function kmod_app_proc_generateHandle(): string {
return Math.floor(Math.random() * 0xffffffff).toString();
}
export function kmod_app_proc_handleExit(pid: string): void {
procfs_writeFile(Path.join("/", pid + "/handles"), "");
procfs_rm("/" + pid);
if (exitListeners[pid]) {
for (let i = 0; i < exitListeners[pid].length; i++) {
exitListeners[pid][i]!();
}
}
exitListeners[pid] = [];
delete exitListeners[pid];
if (heapHandles[pid]) {
$destroyIsolatedHeap(heapHandles[pid]!);
delete heapHandles[pid];
}
}
export function kmod_app_proc_running(pid: string): boolean {
const handles = procfs_readFile(Path.join("/" + pid, "handles")) as string;
if (handles === null || handles === undefined) return false;
return handles !== "";
}
export function kmod_app_proc_addExitListener(
pid: string,
listener: () => void
): void {
if (!exitListeners[pid]) exitListeners[pid] = [];
exitListeners[pid].push(listener);
}
export function kmod_app_proc_exit(pid: string): void {
kmod_app_proc_handleExit(pid);
}

View File

@@ -8,8 +8,15 @@ export function kmod_terminal_input_init(): void {}
export function kmod_terminal_input_onKeyboardInput(
handler: (keycode: keyof typeof Keycode) => void
) {
): () => void {
kmod_terminal_input_keyboardInputHandlers.push(handler);
return function () {
const index = kmod_terminal_input_keyboardInputHandlers.indexOf(handler);
if (index !== -1) {
kmod_terminal_input_keyboardInputHandlers.splice(index, 1);
}
};
}
export function kmod_terminal_input_handleKeyboardInput(

View File

@@ -1,3 +1,3 @@
export function iexec(code: string) {
$isolatedExec(code);
return $isolatedExec(code);
}

View File

@@ -1,8 +1,5 @@
import { kmod_app_run } from "../../kernel/modules/app/app.kmod";
export function oskrnl_app_launcher_run(path: string, args: string) {
if ((globalThis as any).__oskrnl) {
(globalThis as any).__oskrnl.app_args = args;
}
kmod_app_run(path);
return kmod_app_run(path, args);
}

View File

@@ -0,0 +1,25 @@
import {
kmod_app_proc_addExitListener,
kmod_app_proc_exit,
kmod_app_proc_getArgs,
kmod_app_proc_running,
} from "../../kernel/modules/app/app.kmod";
export function oskrnl_app_proc_getArgs(pid: string): string {
return kmod_app_proc_getArgs(pid);
}
export function oskrnl_app_proc_addExitListener(
pid: string,
listener: () => void
): void {
kmod_app_proc_addExitListener(pid, listener);
}
export function oskrnl_app_proc_exit(pid: string): void {
kmod_app_proc_exit(pid);
}
export function oskrnl_app_proc_running(pid: string): boolean {
return kmod_app_proc_running(pid);
}

View File

@@ -1,13 +1,22 @@
import { oskrnl_app_launcher_run } from "./app/launcher";
import {
oskrnl_app_proc_addExitListener,
oskrnl_app_proc_exit,
oskrnl_app_proc_getArgs,
oskrnl_app_proc_running,
} from "./app/proc";
import { oskrnl_console_log, oskrnl_console_update } from "./console/console";
import { oskrnl_input_onKeyPress } from "./input/input";
export function oskrnl_register() {
(globalThis as any).__oskrnl = {
app_args: null,
console_log: oskrnl_console_log,
console_update: oskrnl_console_update,
input_onKeyPress: oskrnl_input_onKeyPress,
app_launcher_run: oskrnl_app_launcher_run,
app_proc_getArgs: oskrnl_app_proc_getArgs,
app_proc_addExitListener: oskrnl_app_proc_addExitListener,
app_proc_exit: oskrnl_app_proc_exit,
app_proc_running: oskrnl_app_proc_running,
};
}

View File

@@ -1,5 +1,24 @@
import {
kmod_app_proc_generateHandle,
kmod_app_proc_registerHandle,
kmod_app_proc_running,
kmod_app_proc_addExitListener,
} from "../../kernel/modules/app/app.kmod";
import { kmod_terminal_input_onKeyboardInput } from "../../kernel/modules/terminal/input";
export function oskrnl_input_onKeyPress(handler: (key: string) => void) {
kmod_terminal_input_onKeyboardInput(handler);
export function oskrnl_input_onKeyPress(
pid: string,
handler: (key: string) => void
) {
kmod_app_proc_registerHandle(pid, kmod_app_proc_generateHandle());
const removeHandler = kmod_terminal_input_onKeyboardInput(function (
key: string
) {
const running = kmod_app_proc_running(pid);
if (!running) return;
handler(key);
});
kmod_app_proc_addExitListener(pid, removeHandler);
}

View File

@@ -11,5 +11,5 @@ declare const $irqregister: (
irq: number,
handler: (irqNum: number) => void
) => boolean;
declare function $isolatedExec(code: string): void;
declare function $isolatedExec(code: string): number;
declare function $destroyIsolatedHeap(handle: number): void;

View File

@@ -17,6 +17,7 @@ export type KFilesystemDriver = {
writeFile(path: string, content: unknown): void;
createFile(path: string, content: unknown): void;
mkdir(path: string): void;
rm(path: string): void;
stat(path: string): KFilesystemStat | null;
directRead?(
path: string,

View File

@@ -1 +1 @@
__oskrnl.console_log(__oskrnl.app_args);
__oskrnl.console_log(__oskrnl.app_proc_getArgs(__oskrnl_procd_pid));

View File

@@ -1,14 +1,13 @@
__oskrnl.console_log("> ");
var input = "";
var inputActive = true;
var pid = "";
__oskrnl.input_onKeyPress(function (key) {
if (!inputActive) return;
__oskrnl.input_onKeyPress(__oskrnl_procd_pid, function (key) {
if (pid != "" && __oskrnl.app_proc_running(pid)) return;
if (key == "Backspace") input = input.slice(0, -1);
else if (key == "Enter") {
inputActive = false;
process();
return;
} else input += key.toLowerCase();
@@ -19,5 +18,14 @@ __oskrnl.input_onKeyPress(function (key) {
function process() {
var app = input.split(" ")[0];
var args = input.split(" ").slice(1);
__oskrnl.app_launcher_run(app, args.join(" "));
pid = __oskrnl.app_launcher_run(app, args.join(" "));
__oskrnl.app_proc_addExitListener(pid, function () {
input = "";
__oskrnl.console_log("> ");
});
if (!__oskrnl.app_proc_running(pid)) {
input = "";
__oskrnl.console_log("> ");
}
}

View File

@@ -0,0 +1,6 @@
__oskrnl.input_onKeyPress(__oskrnl_procd_pid, function (key) {
if (key == __oskrnl.app_proc_getArgs(__oskrnl_procd_pid)[0].toUpperCase()) {
__oskrnl.app_proc_exit(__oskrnl_procd_pid);
return;
}
});

View File

@@ -0,0 +1,5 @@
{
"app:name": "wfkey",
"app:version": "1.0.0",
"app:entrypoint": "index.js"
}