Let me describe how Keykos works in this area.
We did not find any patterns that we could not support.
Design decisions such as these determine what patterns are efficient, but hopefully does not exclude patterns.
For instance we unified mailbox and domain.
Most other systems separate these two and an actor (domain in our case) asks it there is mail in some mailbox, or waits for there to be some.
When your pattern requires asking a mailbox whether there is mail, you can devote a Keykos domain to serve as that mailbox.
This is an example of a difference only in performance, and then not a large difference.
Quite literally a domain consists of:
- a reference to a segment which serves as its address space,
- a meter reference via which CPU cycles are acquired,
- a C-list of capabilities (“cap”s here), whose meaning is determined solely by the program (in the address segment) that the domain obeys, perhaps parameterized by the caps in its C-list.
- a set of values for the machine registers, including program counter, which is an integral part of what it means to obey code,
- a keeper cap to be invoked when the domain cannot execute an instruction such as divide by zero, or invalid op code.
This typically leads to a domain executing a program called the “domain keeper”.
Upon invocation the domain keeper gets a domain cap to the domain which suffices tos intervene in the execution of the faulting program.
- other parameters useful in controlling the hardware facilities useful in debugging user mode code.
Segments are composed recursively of pages or other segments.
Two ‘instances’ (in the C++ sense) will have the method defining code in a subsegment, and the instance variables in another mutable segment.
Segments can be equipped with keepers which are programs that run when some currently undefined portion of the segment is touched.
The keeper can then define it.
There are three valid domain states:
- Available, in which anyone with a start cap to said domain can send a message and the domain will immediately begin to run with access to that message.
- Running, in which the domain is waiting only for a CPU or a page to come in from disk, or is actually executing instructions.
- Waiting, in which the domain has called another domain and will not run again until the return cap produced by that call, is used by someone who in due course came to hold that return cap and invokes it to return a message to the waiting domain.
Some literature calls our ‘available’ state an “open wait” for it it is ready to take on some hew task.
The PC of such a domain points to code that will dispatch on an integer parameter that chooses which method for the current call.
That literature uses “closed wait” to describe we call a waiting domain that insists on getting an answer to some question before the subject is changed.
In Keykos it may be restarted only by invoking the return cap that was produced when it was called
The PC of such a domain points to just after a cap call site.
Note that there is no explicit stack known to the kernel.
The distribution of return caps, which the kernel does not consider, is the manifestation of stack.
There are three variants to cap invocation:
- Call, which makes a new return cap which the calling domain waits for.
The calling domain begins then to wait.
- Return, which sends a message typically to a waiting domain.
The returning domain becomes available.
- Fork, which sends a message, as in call, but continues to run.
Here is a more complete definition of segment.