[][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.