runtimejs / runtime

[not maintained] Lightweight JavaScript library operating system for the cloud
http://runtimejs.org
Apache License 2.0
1.93k stars 128 forks source link

module and "process" loading bikeshed #14

Open groundwater opened 10 years ago

groundwater commented 10 years ago

I don't think we should be bound by the abstractions governing most *nix systems. Specifically the "everything is a file" abstraction, and the process abstraction.

isolates and contexts

Instead of a processes, we have isolates and contexts, since these already exist in v8. Each has features and constraints, and we should probably just embrace them as-is.

  1. isolates can run in parallel, but cannot share heap objects
  2. contexts (in the same isolate) can share heap objects, but cannot preempt one and other.

Sometimes I imagine you will want to boot a new context, and other times you will want a new isolate. It remains to be seen how isolates and contexts will be used to construct a system, but we definitely want both constructs as first-class runtimejs functionality.

modules

I think we should drop files as a first-class concept, rather "everything is a module".

By default, JavaScript code running in v8 has no external access. It cannot access the file system, the network, or make system calls. External access should be passed in via the ES6 module feature.

You gain access to external objects via the ES6 import syntax, e.g.

import {stdout, exit} from "process"

stdout.write("Hello World")
exit(0)

This is very similar to how an executable on linux links against libc headers during compilation, e.g.

#include <stdio.h>

int main(int argc, char** argv)
{
  printf("Hello World");

  return 0;
}

In most implementations, the actual IO code is not contained in the executable file on disk, but the shared library loaded at runtime.

We take this idea to its completion in runtime, where every parent process has full control over what gets passed into a child process. Each parent defines the moduel loader for its child. A parent can re-export its own imports, export a subset, or even provide a new API to its child.

let ctx = new Context()

ctx.load(source)
ctx.setLoader(custom_loader)
ctx.compile()
ctx.run()

Moule linking occurs during compile not run. If a child attempts to import a disallowed or missing module, it will receive an error during the compile step.

libraries

The first context that runs has its module loader defined by the kernel. At this point there is no file system, so the module loader cannot load files from disk, only memory.

The kernel should provide raw device and memory access.

import {mem, dev} from "kernel"

mem.cr3 = // setup the page table

dev.write(deviceAddress, data) // write to a raw device

User code does not want to deal with raw devices but files; kernel modules should import raw device access from the kernel, but export a file-system api.

// kernel module
import {dev} from "kernel"

class fs {
  ...
}

export fs

Children spawned by the kernel module will be handed a working file system implementation.

import {open} from "fs"

let file = open('/home/me/file.txt')
file.read(...)

user space

There is no longer just a kernel space and user space. Contexts run with imports defined by their parent context. A parent may decide to pass privileged functions to their children, provide proxies, or disallow the import altogether.

summary

At the core of runtime, we only need a module system. The kernel must provide the initial module loader, but from then on all subsequent loaders are defined by other modules.

iefserge commented 10 years ago

Sometimes I imagine you will want to boot a new context, and other times you will want a new isolate. It remains to be seen how isolates and contexts will be used to construct a system, but we definitely want both constructs as first-class runtimejs functionality.

Agreed. Isolates are useful if user wants to have separate heap and GC for some drivers/applications. I'm working on preemption problem though. Hopefully, I will be able to implement it for contexts on the same isolate.

I think we should drop files as a first-class concept, rather "everything is a module"

Ok. My proposal: I think we should not use module system for resource management. Instead we can use program arguments object to pass everything program needs.

This is the user program example https://github.com/runtimejs/runtime/blob/master/initrd/app/example.js

{
  "system" : <system resources>,
  "env" : <environment>,
  "data": <program data like command line etc>
}
args.system.process.spawn( path, options, data, env )

example (start /random.js using current process environment args.env)

args.system.process.spawn('/random.js', {}, {
  command: '-a -b -c=value'
}, args.env);

Thoughts?