[−][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 connect
s. 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. |