Systems Programming for OS Work¶
Warmwind patches Sway (C), Chromium (C++), and builds tooling in Rust. This article covers memory safety tradeoffs, IPC patterns, file descriptor passing (the foundation of Wayland buffer sharing), process management, build systems used across the stack, and contributing upstream.
Memory Safety: Rust vs C¶
| Aspect | C (Sway, wlroots) | Rust (new tooling) |
|---|---|---|
| Memory management | Manual (malloc/free) |
Ownership + borrow checker |
| Use-after-free | Runtime crash or exploit | Compile-time error |
| Data races | Possible, use mutexes | Prevented by Send/Sync traits |
| FFI | Native | extern "C" + unsafe blocks |
| Ecosystem | wlroots, Mesa, kernel | wayland-rs, smithay, nix crate |
Rust's ownership model in 30 seconds:
fn main() {
let buffer = vec![0u8; 4096]; // buffer owns heap allocation
let view = &buffer[..]; // immutable borrow -- buffer can't be freed
process(view);
// buffer dropped here -- memory freed automatically
}
fn process(data: &[u8]) { // borrows, doesn't own
// can read data, can't free or resize it
}
C equivalent requires discipline:
void process(const uint8_t *data, size_t len);
int main(void) {
uint8_t *buffer = malloc(4096);
process(buffer, 4096);
free(buffer); // forget this = leak, double this = corruption
return 0;
}
IPC Patterns¶
| Mechanism | Use case in Warmwind stack |
|---|---|
| Unix sockets | Wayland protocol, Sway IPC |
| D-Bus | systemd control, desktop notifications |
| Shared memory | Wayland wl_shm buffers, memfd_create |
| Pipes | Process supervision, log forwarding |
| dma-buf (fd passing) | GPU buffer sharing between processes |
Unix Domain Sockets¶
// Server (compositor side)
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
snprintf(addr.sun_path, sizeof(addr.sun_path),
"%s/wayland-0", getenv("XDG_RUNTIME_DIR"));
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 128);
D-Bus¶
# Introspect systemd's manager interface
busctl introspect org.freedesktop.systemd1 /org/freedesktop/systemd1
# Programmatically restart a service
busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager RestartUnit ss "sway.service" "replace"
File Descriptor Passing (SCM_RIGHTS)¶
The foundation of Wayland buffer sharing. One process sends an fd over a Unix socket; the receiving process gets a new fd referencing the same kernel object.
// Send an fd over a Unix socket
void send_fd(int socket, int fd_to_send) {
struct msghdr msg = {0};
struct cmsghdr *cmsg;
char buf[CMSG_SPACE(sizeof(int))];
struct iovec iov = { .iov_base = "x", .iov_len = 1 };
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(int));
sendmsg(socket, &msg, 0);
}
This is how Wayland clients pass dma-buf fds to the compositor. The compositor imports the fd as an EGLImage for texturing -- zero copies.
Process Management¶
fork/exec Pattern¶
pid_t pid = fork();
if (pid == 0) {
// Child: become Chromium
execvp("chromium", (char *[]){"chromium", "--kiosk", NULL});
_exit(127); // exec failed
}
// Parent: store pid, set up signal handler
Signal Handling¶
// Reap zombies without blocking
void sigchld_handler(int sig) {
(void)sig;
while (waitpid(-1, NULL, WNOHANG) > 0);
}
struct sigaction sa = {
.sa_handler = sigchld_handler,
.sa_flags = SA_RESTART | SA_NOCLDSTOP
};
sigaction(SIGCHLD, &sa, NULL);
Zombie Prevention¶
A zombie is a terminated child whose parent hasn't called waitpid(). In a
compositor managing child processes (Chromium, WayVNC), always:
- Handle
SIGCHLDwithwaitpid(-1, &status, WNOHANG)in a loop. - Or use
prctl(PR_SET_CHILD_SUBREAPER, 1)to adopt orphaned descendants. - Or set
SIGCHLDtoSIG_IGN(Linux-specific: auto-reaps).
Build Systems¶
| Project | Build system | Key commands |
|---|---|---|
| wlroots/Sway | Meson + Ninja | meson setup build && ninja -C build |
| FreeRDP | CMake + Ninja/Make | cmake -B build -G Ninja && ninja -C build |
| Chromium | GN + Ninja | gn gen out/Release && autoninja -C out/Release |
| Rust projects | Cargo | cargo build --release |
| Linux kernel | Kbuild (Make) | make defconfig && make -j$(nproc) |
Meson example (wlroots development):
meson setup build -Dxwayland=disabled -Dbackends=drm,headless
ninja -C build
sudo ninja -C build install
Contributing Upstream¶
The posting says "open-source collaboration, upstream contributions." Here is the workflow for wlroots/Sway (GitLab MR) and Chromium (Gerrit CL):
wlroots/Sway (GitLab):
git clone https://gitlab.freedesktop.org/wlroots/wlroots.git
git checkout -b fix-screencopy-damage
# Make changes, test
git commit -s # -s adds Signed-off-by (DCO requirement)
# Push to fork, open Merge Request
Chromium (Gerrit):
git new-branch fix-ozone-wayland
# Make changes
git cl upload # uploads to Gerrit for code review
# Respond to review comments, update patch
git cl upload # re-uploads amended commit
Key practices:
- One logical change per commit/MR. Separate refactoring from behavior changes.
- Include test coverage. wlroots uses custom test harness; Chromium uses gtest.
- Follow existing code style exactly (
clang-formatfor C/C++,rustfmtfor Rust). - Engage constructively with review feedback. Upstream maintainers are volunteers.
- Reference the issue/bug number in the commit message.
Glossary
- Ownership (Rust)
- Each value has exactly one owner. When the owner goes out of scope, the value is dropped.
- Borrow checker
- Rust compiler pass enforcing that references don't outlive their referents and exclusive access is exclusive.
- SCM_RIGHTS
- Ancillary data type for
sendmsg()/recvmsg()that transfers file descriptors between processes. - Zombie process
- Terminated process whose exit status hasn't been collected by its parent via
wait(). - DCO (Developer Certificate of Origin)
- Lightweight CLA alternative.
Signed-off-by:in commit message certifies right to contribute. - Meson
- Modern build system used by wlroots, Sway, Mesa, and many GNOME/freedesktop projects.
- GN (Generate Ninja)
- Chromium's meta-build system. Processes
.gnandBUILD.gnfiles to emit Ninja build files. - CL (Change List)
- Chromium/Gerrit term for a patch submitted for code review. Equivalent to a pull request.