This is a sketch of a capability system which utilised data and operations in kernel mode.
There are 2 kernel objects used to support the capability system, Vat and Call. Cap is a global identifier of a capability consisting of a Vat reference and a vat defined number.
enum Message {
Call(Call, Cap, Vec<u8>, Vec<Cap>),
Reply(Call, Vec<u8>),
Resolve(Call, Cap),
Provide(Vat, Cap),
}Vats contains a queue of messages and a map of vats to sets of capability ids. The map represents which other vats have access and the set which capabilites each vat can access.
struct Vat {
inbox: Vec<Message>,
connections: Map<Vat, Set<Cap>>,
}User-mode can block on a message from a Vat. However Provide messages will not be returned as there nothing for user-mode to do with them.
The call object is created for each remote call. It contains either a queue of messages or a cap which was returned from the call. It also has a set of vats which indicated if each vat has access to it as a future. During a RPC, the caller will gain access to it as a future and the callee will gain access to it as a promise.
struct Call {
state: CallState,
caller: Vat,
callee: Vat,
futures: Set<Vat>,
}
enum CallState {
Unresolved(Vec<Message>),
Resolved(Cap),
}Vats with future access can queue messages which will be sent when the call is complete.
The callee can reply to the Call object causing it to send all it's queued messages and then send a Resolve message to each of vats with future access. It will also then send a Reply message with the result to the caller.
When we are sending a Call cap in a payload, we add access to the receiver in either the promises or the futures field of Call depending what the cap gives access to.
When we are sending a cap belonging to the current vat, we add the cap in the set associated with the receiver in the connections map.
When we are sending a cap belonging to another vat to a third vat we send a Provide message to the owner which will grant access to the third vat.