unixpickle / alux

A lightweight C++ kernel designed to run a JavaScript or Dart VM
BSD 2-Clause "Simplified" License
22 stars 5 forks source link

Inter-process communication #6

Open unixpickle opened 9 years ago

unixpickle commented 9 years ago

I am in the process of figuring out how my microkernel should implement inter-process communication. Here are the two types of IPC I want to consider:

Since basic IPC should allow very limited memory usage, I'm considering a simple "write & signal" approach. In this approach, a basic IPC connection has a 32-byte buffer associated with it that can be read/written with a system call. A task may wakeup the remote end of a basic IPC connection to notify it of a data change. A task can also poll one or more basic IPC connections at once to await data. Multiple threads on a task cannot poll on the same basic IPC connection at the same time.

This IPC technique would serve best if it was primarily used underneath shared memory IPC. For example, task A would connect to task B and the tasks would perform a basic handshake over basic IPC. Then, both task A and task B would use their connection to the memory daemon to negotiate a shared memory region. From there, task A and task B would communicate as follows: one task would write a relatively large piece of data to the shared memory region and use its basic IPC connection to signal the other task of the data change.

Essentially, the basic IPC connection would be used as a signaling mechanism for the larger shared memory region.

Thread-Local IPC

An IPC connection can only be polled or signaled by one thread at a time. My first instinct is to decide that only the main Dart Isolate or VM thread can access the IPC mechanism. However, this is unreasonable because multithreaded VMs will probably need to access the memory daemon from multiple threads at once.

To deal with this issue, I came up with the idea of "thread-local IPC". When you open a connection to another task, you will specify whether you want to connect with a full-task connection, or with a thread-local connection. Thread-local file descriptors will be negative and will be specific to a given thread. Thread-local connections are closed when a thread is terminated, similarly to how full-task connections are closed when the task exits.

When you run a PollAll() system call, that will only poll full-task connections. I have not yet decided if PollAll() should poll thread-local connections on the thread that made the call.

unixpickle commented 9 years ago

Things I am still flaky about:

unixpickle commented 9 years ago

Additionally, I'd like to have some form of sockets for privileged tasks to communicate with the kernel. For example, I'd want a type of connection that would transmit page faults to the memory daemon. Additionally, I want a way that the kernel's arch-specific code could talk to user-space to send it things like hardware interrupts.

unixpickle commented 9 years ago

I have recently decided that all IPC will be thread local. A task will serve other tasks by allocating its own ports and passing them to some sort of PushToListenQueue() method. I will prevent DOS in the future by creating a permissions bitmap so that a task can block or unblock any given user ID from connecting.