External sources Linx.Process draws on — kernel docs, prior art, and
the Erlang/Elixir conventions that shape the API.
A living doc — add to it as new sources inform a decision.
Kernel side
The syscalls and namespace concepts Linx.Process exposes:
clone(2)— the syscall that creates the child;CLONE_NEW*flags pick which namespaces are fresh.setns(2)— whatenter/2uses to join an existing process's namespaces.execve(2)— the child's final act after the checkpoint.unshare(2)— in-place namespace creation. Documented for context; not exposed (the BEAM can't safely unshare its own scheduler thread, and the Port helper has no use casespawn/1doesn't cover).namespaces(7)— the overview page. The per-type pages document the specifics:pid_namespaces(7),network_namespaces(7),mount_namespaces(7),user_namespaces(7),uts_namespaces(7),ipc_namespaces(7),cgroup_namespaces(7),time_namespaces(7).
The Port boundary
The agent talks ETF to the BEAM over fd 3/4:
- Erlang External Term Format spec — the wire format on fd 3/4.
erl_interface/eiman page — the C library the agent uses to encode and decode ETF. Statically linked (libei.a); the path is resolved by the Mix compiler via:code.root_dir/0.Port.open/2/:erlang.open_port/2— the:nouse_stdio+{:packet, 4}options that route control over fd 3/4 and leave fd 0/1/2 free for the workload.
Prior art
- tini,
dumb-init,
catatonit — established
upstream
mini_initbinaries. - runc's
libcontainer— the reference container-runtime implementation in Go;nsenter,setns_init, and the checkpoint relay design parallellinx_process. - conmon — the per-container agent in the podman/CRI-O world. The "clone parent = conmon" framing carries through here: the Port-spawned agent IS conmon, sized down to its essentials.
Build
- The
:linx_processMix compiler (lib/mix/tasks/compile.linx_process.ex) — mirrors the:netlink_nifone but builds an executable, statically linkinglibeifrom the OTP install.