Documentation Index Fetch the complete documentation index at: https://mintlify.com/serenityOS/serenity/llms.txt
Use this file to discover all available pages before exploring further.
SerenityOS uses a type-safe, high-level IPC (Inter-Process Communication) system called LibIPC for communication between processes. This system is fundamental to the microkernel-inspired architecture, enabling services and applications to interact efficiently.
IPC Overview
LibIPC provides:
Type-safe message passing between processes
Automatic serialization/deserialization
Request-response and one-way messaging
File descriptor passing
Code generation from interface definitions
Architecture
The IPC system consists of several components:
┌─────────────────────────────────────────────────┐
│ Application or Service (Client) │
├─────────────────────────────────────────────────┤
│ Generated Client Stub (ConnectionToServer) │
├─────────────────────────────────────────────────┤
│ LibIPC (Encoder/Decoder) │
├─────────────────────────────────────────────────┤
│ Unix Domain Socket │
├─────────────────────────────────────────────────┤
│ LibIPC (Encoder/Decoder) │
├─────────────────────────────────────────────────┤
│ Generated Server Stub (ConnectionFromClient) │
├─────────────────────────────────────────────────┤
│ Service Implementation │
└─────────────────────────────────────────────────┘
IPC Definition Language
IPC interfaces are defined in .ipc files using a simple DSL:
WindowServer Example
AudioServer Example
FileSystemAccessServer Example
endpoint WindowServer
{
// Request-response: client waits for response
CreateWindow(Gfx::IntRect rect, String title) => (i32 window_id)
// One-way message: no response expected
InvalidateRect(i32 window_id, Gfx::IntRect rect) =|
// Method with complex types
SetWindowBitmap(i32 window_id, [Bitmap] bitmap) => ()
// Get window properties
GetWindowRect(i32 window_id) => (Gfx::IntRect rect)
}
Message Types
Request-Response Messages
Use => syntax for synchronous request-response:
GetSomething(i32 id) => (String result)
Client sends request and blocks waiting for response
Server processes request and sends response
Return value delivered to client
One-Way Messages
Use =| syntax for asynchronous one-way messages:
NotifySomething(String data) =|
Client sends message and continues immediately
Server processes message when received
No response sent back to client
Code Generation
The IPC compiler (Meta/Lagom/Tools/CodeGenerators/IPCCompiler/) generates C++ code from .ipc files:
Client Stub
Server Stub
Message Structures
Generated ConnectionToServer class: // Auto-generated from WindowServer.ipc
class ConnectionToServer : public IPC :: ConnectionToServer <...> {
public:
// Synchronous call
IPC :: Messages :: WindowServer :: CreateWindowResponse create_window (
Gfx :: IntRect const& rect , String const& title )
{
return send_sync < Messages :: CreateWindow >(rect, title);
}
// Asynchronous call
void invalidate_rect ( i32 window_id , Gfx :: IntRect const& rect )
{
send < Messages :: InvalidateRect >(window_id, rect);
}
};
Generated ConnectionFromClient class: // Auto-generated from WindowServer.ipc
class ConnectionFromClient : public IPC :: ConnectionFromClient <...> {
protected:
// Pure virtual - must implement in derived class
virtual Messages :: WindowServer ::CreateWindowResponse
create_window ( Gfx :: IntRect const& rect , String const& title ) = 0 ;
virtual void invalidate_rect (
i32 window_id , Gfx :: IntRect const& rect ) = 0 ;
};
Generated message types: namespace Messages :: WindowServer {
struct CreateWindow {
Gfx ::IntRect rect;
String title;
};
struct CreateWindowResponse {
i32 window_id;
};
struct InvalidateRect {
i32 window_id;
Gfx ::IntRect rect;
};
}
Serialization
LibIPC automatically serializes and deserializes messages:
Supported Types
bool: Boolean
i8, i16, i32, i64: Signed integers
u8, u16, u32, u64: Unsigned integers
float, double: Floating point
String: UTF-8 string
ByteString: Byte string
StringView: Non-owning view (serialize as String)
Vector<T>: Dynamic array
HashMap<K, V>: Hash map
Optional<T>: Maybe type
Any type with IPC encoding support
Gfx types (IntRect, IntPoint, Color, etc.)
File descriptors via IPC::File
Bitmaps via special [Bitmap] syntax
Custom Type Encoding
To make a custom type IPC-serializable:
// In YourType.h
struct YourType {
i32 field1;
String field2;
};
// Add encoder/decoder
namespace IPC {
template <>
ErrorOr < void > encode ( Encoder & encoder , YourType const& value )
{
TRY ( encoder . encode ( value . field1 ));
TRY ( encoder . encode ( value . field2 ));
return {};
}
template <>
ErrorOr < YourType > decode ( Decoder & decoder )
{
auto field1 = TRY ( decoder . decode < i32 > ());
auto field2 = TRY ( decoder . decode < String > ());
return YourType { field1, move (field2) };
}
}
File Descriptor Passing
IPC supports passing file descriptors between processes:
endpoint ImageDecoder
{
// Pass file descriptor for shared memory
DecodeImage([File] image_file) => ([Bitmap] decoded_bitmap)
}
The [File] and [Bitmap] syntax indicates file descriptor transfer:
[File]: Transfers a file descriptor
[Bitmap]: Transfers a shared memory region containing a bitmap
Connection Lifecycle
Client Side
Create Connection
auto connection = TRY ( WindowServer :: ConnectionToServer :: try_create ());
Send Messages
// Synchronous call
auto response = connection -> create_window (rect, "My Window" sv );
i32 window_id = response . window_id ();
// Asynchronous call
connection -> invalidate_rect (window_id, dirty_rect);
Handle Events
// If server sends events to client, override handlers:
void handle_paint_event ( i32 window_id , Gfx :: IntRect rect ) override
{
// Handle paint request from server
}
Server Side
Implement Connection Handler
class ClientConnection final
: public WindowServer :: ConnectionFromClient
{
public:
virtual ~ClientConnection () override = default ;
private:
// Implement IPC methods
virtual Messages :: CreateWindowResponse create_window (
Gfx :: IntRect const& rect , String const& title ) override
{
auto window_id = m_server . create_window (rect, title);
return { window_id };
}
virtual void invalidate_rect (
i32 window_id , Gfx :: IntRect const& rect ) override
{
m_server . invalidate_window_rect (window_id, rect);
}
Server & m_server;
};
Accept Connections
// Server listens on Unix socket
auto server = TRY ( IPC :: MultiServer < ClientConnection >:: try_create ());
// Event loop handles incoming connections
return event_loop . exec ();
Common IPC Patterns
Service Discovery
Services listen on well-known socket paths:
// Standard service socket paths
/ tmp / session /% sid / portal / window // WindowServer
/ tmp / session /% sid / portal / audio // AudioServer
/ tmp / session /% sid / portal / clipboard // Clipboard
/ tmp / session /% sid / portal / filesystemaccess // FileSystemAccessServer
Multi-Client Services
Services handle multiple clients simultaneously:
class MyService {
public:
void run ()
{
// MultiServer manages multiple client connections
auto server = TRY ( IPC :: MultiServer < ClientConnection >:: try_create ());
// Each client gets own ClientConnection instance
server -> on_new_client = [ this ]( auto& client ) {
dbgln ( "New client connected" );
};
Core :: EventLoop :: current (). exec ();
}
};
Request-Response with Timeout
// Client can implement timeout for sync calls
Optional < Response > send_with_timeout ( Duration timeout )
{
auto start = Time :: now_monotonic ();
auto response = connection -> some_request ();
if ( Time :: now_monotonic () - start > timeout)
return {}; // Timeout
return response;
}
Event Loop Integration
IPC integrates seamlessly with LibCore’s event loop:
// IPC messages are processed via event loop
Core ::EventLoop loop;
auto connection = TRY ( WindowServer :: ConnectionToServer :: try_create ());
// Async messages don't block event loop
connection -> async_invalidate_rect (window_id, rect);
// Sync messages block until response (but event loop keeps running)
auto response = connection -> create_window (rect, title);
loop . exec ();
Security Considerations
Unix domain sockets use filesystem permissions:
Sockets in /tmp/session/%sid/ are user-private
Only processes with same session ID can connect
File permissions prevent unauthorized access
Services must validate all incoming data: virtual Messages :: Response handle_request (
i32 id , String const& data ) override
{
// Validate ID is in valid range
if (id < 0 || id >= m_items . size ())
return Error :: from_string_literal ( "Invalid ID" );
// Validate string is not too long
if ( data . length () > MAX_SIZE)
return Error :: from_string_literal ( "Data too large" );
// Process request...
}
Limit maximum message size
Limit number of concurrent connections
Implement rate limiting for expensive operations
Clean up resources when clients disconnect
Real-World Examples
WindowServer Communication
// Application creates window via IPC
auto window = GUI :: Window :: construct ();
window -> set_title ( "My Application" );
window -> resize ( 640 , 480 );
window -> show (); // Internally calls WindowServer IPC
// Behind the scenes:
// GUI::Window::show() ->
// ConnectionToWindowServer::create_window(...) ->
// IPC message to WindowServer ->
// WindowServer creates window ->
// Response with window_id
ImageDecoder Service
// Decode image in isolated process
auto connection = ImageDecoderClient :: Client :: try_create ();
// Send image data via file descriptor
auto bitmap = TRY ( connection -> decode_image (image_file));
// ImageDecoder runs in separate process for security
// Prevents malicious images from compromising main app
ConfigServer
// Read configuration value
auto config_client = TRY ( Config :: Client :: try_create ());
auto value = config_client -> read_string ( "MyApp" , "Settings" , "theme" );
// Write configuration value
config_client -> write_string ( "MyApp" , "Settings" , "theme" , "Dark" );
// ConfigServer persists settings to disk
IPC Performance:
Unix domain sockets are very fast (local communication)
Zero-copy for file descriptor passing
Minimal serialization overhead
Async messages have near-zero latency
Sync messages have ~µs round-trip time
Debugging IPC
Tools for debugging IPC issues:
# Enable IPC debug output
export IPC_DEBUG = 1
# Trace IPC messages
export IPC_TRACE = 1
# Monitor socket connections
ls -la /tmp/session/ * /portal/
# Check for stuck connections
lsof | grep socket
Further Reading
Event Loop How IPC integrates with the event system
Services Learn about system services that use IPC
LibIPC Source Explore LibIPC implementation
Example .ipc Files Study real IPC definitions in Userland/Services/