[−][src]Module sunrise_kernel::ipc
IPC primitives
Mostly lifted from the Nintendo Switch. http://switchbrew.org/index.php?title=IPC_Marshalling contains documentation for how it works on the official hardware. I'll try my best to explain the ideas here.
The switch IPC mechanism is separated with two main types, Ports and Sessions, both having a client and a server side. A port is used to establish a Session.
Ports
A Port represents an endpoint which can be connected to, in order to
establish a Session. It is split in two different part: ServerPort and
ClientPort. The ClientPort has a connect operation, while a ServerPort has
an accept operation.
Those work as a rendez-vous, meaning both operations wait for each-other:
The connect operation blocks until a ServerPort calls accept. Similarly,
the accept operation waits until a ClientPort connects. Once the two
operation meet, a Session is created. The accept operation will return a
ServerSession, while the connect operation returns a ClientSession.
Additionally, a ServerPort implements the Waitable trait, allowing it to be
used with the event::wait function. This will wait until the associated
ClientPort had its connect operation called. TODO: The ClientPort should also
implement Waitable, I believe. In Horizon/NX, it implements KSynchronization.
let (server, client) = Port::new(); let client_sess = client.connect(); // In a separate thread let server_sess = server.accept();
Session
A Session represents an established connection. It is split in two different
part: ServerSession and ClientSession. The ClientSession has a send_request
operation (with various variants), while a ClientSession has a reply and a
receive operation (again, with various variants).
ServerSession implements the Waitable trait, allowing it to be used with the
event::wait function. TODO: The ClientSession should also implement Waitable.
use kernel::ipc::session; let (server, client) = session::new();
Managed Ports
Sessions and Ports are cool, but we're lacking some kind of entrypoint: In order to do IPC, we need a handle to another service's ClientPort. But we have no such handle when starting a process!
To fix this, the kernel has a global registry of ports. Such ports are called "Managed Ports". In a normal userland, only one service (the Service Manager) would register themselves as a Managed Port, but the kernel allows any number of those to be registered at any given time, so long as each has a unique name.
Managed Ports aren't very special, the only difference is the syscalls used to interact with them: You can register a managed port, which returns a ServerPort handle, and you can connect to a managed port, which returns a ClientSession handle.
use kernel::ipc; let serverport = ipc::create_named_port(b"test\0\0\0\0\0\0\0\0")?; loop { let serversess = serverport.accept()?; } // In another thread let clientsess = ipc::connect_to_named_port(b"test\0\0\0\0\0\0\0\0\0\0\0\0")?;
Re-exports
pub use self::session::ClientSession; |
pub use self::session::ServerSession; |
pub use self::port::ClientPort; |
pub use self::port::ServerPort; |
Modules
| port | IPC Port |
| session | IPC Sessions |
Structs
| NAMED_PORTS |
Functions
| connect_to_named_port | Connects to a named port. |
| create_named_port | Creates a named port. |