Ladybird’s multi-process architecture depends on two tightly coupled libraries: LibCore, which abstracts the operating system and drives asynchronous I/O through a cooperative event loop, and LibIPC, which layers type-safe message passing on top of UNIX sockets so that the browser’s isolated processes can communicate without sharing memory. Together they underpin nearly every long-running component in the browser — from the UI process to the per-tab WebContent renderer, the ImageDecoder, and the RequestServer.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ladybirdBrowser/ladybird/llms.txt
Use this file to discover all available pages before exploring further.
LibCore — OS Abstraction and Event Loop
LibCore — OS Abstraction and Event Loop
LibCore is the POSIX abstraction layer used throughout Ladybird. It wraps file descriptors, processes, sockets, timers, and signals behind C++ classes that integrate with the event loop. It targets Linux, macOS, and (via separate implementation files) Windows and other POSIX systems.
EventLoop
Core::EventLoop is the heart of any LibCore application. It runs a cooperative, single-threaded event dispatcher: exec() enters the loop, repeatedly calling pump(), which blocks in select(2) until an event is ready, then dispatches all pending callbacks before sleeping again.Key operations on EventLoop:exec()— enters the event loop and runs untilquit()is called. Returns an exit code, so the patternreturn app.exec()is conventional in GUI entrypoints.pump(WaitMode)— processes one batch of pending events. Called byexec()in a loop. TheWaitModecontrols whetherpump()usesselect(2)to sleep until an event is ready (WaitForEvents) or polls without blocking (PollForEvents). Under the hood,pump()calls into the platform-specificEventLoopImplementationwhich invokesselect(2)on registered notifier file descriptors and the wake pipe, using the nearest timer deadline as theselect(2)timeout.deferred_invoke(callback)— schedulescallbackto run on the next event loop iteration without blocking the caller.wake()— writes to the event loop’s wake pipe so that a sleepingselect(2)call returns immediately, causing the loop to process any newly posted events. This is the safe way to signal an event loop from another thread.EventLoop::register_signal(signo, handler)— registers a POSIX signal handler that fires as a normal event on the calling thread’s event loop, avoiding the re-entrancy pitfalls of raw POSIX signal handlers.
EventLoop::current() returns the topmost loop on the calling thread.Thread safety and wake pipeEvent loops are per-thread: all global state (notifiers, timers, event loop stack) is stored in thread-local variables. To safely signal an event loop running on another thread, call wake(), which writes to an internal pipe that select(2) is watching. This causes the sleeping loop to wake and process the new event.Core::Timer
Core::Timer wraps the event loop’s timer registration behind a convenient class. Set an interval in milliseconds, attach a callback with on_timeout, and start the timer. Timers can fire once or repeatedly.Core::Notifier
Core::Notifier fires a callback whenever a file descriptor becomes readable or writable. It registers the fd with the event loop’s select(2) watch set so that the loop wakes up and dispatches the on_activation callback as soon as the fd is ready.Other LibCore Utilities
| Class | Purpose |
|---|---|
Core::File | Async-capable file I/O with ErrorOr API. |
Core::Socket / Core::TCPSocket / Core::LocalSocket | Non-blocking socket wrappers integrated with the event loop. |
Core::LocalServer | Listens on a UNIX-domain socket and accepts connections. |
Core::Process | Spawns and monitors child processes. |
Core::AnonymousBuffer | Shared anonymous memory (backed by memfd on Linux, similar on macOS). Used to pass bitmaps and other large data between processes without copying. |
Core::MappedFile | Memory-maps a file read-only via mmap(2). |
Core::ArgsParser | Command-line argument parsing. |
Core::DirIterator | Iterates over directory entries. |
Dos and Don’ts with EventLoop
LibIPC — Type-Safe Inter-Process Communication
LibIPC — Type-Safe Inter-Process Communication
LibIPC enables Ladybird’s separate processes to communicate by exchanging typed messages over UNIX-domain socket pairs. Each service defines its own IPC protocol; the framework handles serialisation, deserialisation, and connection lifecycle.
Architecture
Ladybird uses a multi-process architecture:- Main UI process — coordinates the browser window and user interaction.
- WebContent (one per tab) — renders pages and runs JavaScript in a sandboxed process.
- ImageDecoder — decodes images out-of-process to limit the blast radius of malformed image data.
- RequestServer — performs network connections on behalf of the renderer, keeping raw socket access out of the sandboxed tab process.
IPC::ConnectionFromClient— the server side of a connection, representing one connected client.IPC::ConnectionToServer— the client side, used by the process that initiated the connection.
IPC::Connection base that owns the underlying Core::LocalSocket and integrates with the event loop via a Core::Notifier on the socket’s file descriptor.Message Passing
IPC::Message is the base type for all IPC messages. Each message carries a message ID and a serialised payload. The framework provides IPC::Encoder and IPC::Decoder for converting C++ types to and from the binary wire format.Messages can be:- One-way (fire-and-forget) — the caller sends the message and continues immediately.
- Synchronous (blocking call) — the caller sends a request message and pumps the event loop in a nested fashion until the reply arrives.
Transport and File Descriptor Passing
IPC::Transport abstracts the underlying channel. On POSIX systems this is a socketpair(2) UNIX-domain socket, which also supports sending open file descriptors via SCM_RIGHTS — used to pass AnonymousBuffer handles (shared bitmaps) and other OS resources between processes without data copying.IPC::Attachment encapsulates file descriptors that travel alongside a message.Service Roles
| Service | Protocol role |
|---|---|
| WebContent | Receives paint commands and events from the UI; responds with rendered bitmaps via ShareableBitmap. |
| ImageDecoder | Receives encoded image data, returns decoded DecodedImageData frames. |
| RequestServer | Performs HTTP/HTTPS requests on behalf of WebContent; streams response data back over the IPC socket. |
