#!/bin/sh # Build script for xlibre-xserver (Meson, Template B) — Xvfb-only headless build. # # THE crux port of the desktop initiative. Builds ONLY the Xvfb DDX (headless # software framebuffer): no hardware/DRM/GL, no udev/logind, no xorg/xephyr/etc. # x11vnc (Task 7a) later bridges the Xvfb display to VNC. # # XLibre has BSD CI but no illumos/Hammerhead target, so this port carries # Hammerhead portability patches in patches/ (applied below). # # Meson option notes (verified against this tree's meson_options.txt): # * -Dgbm / -Dxf86-input-null from the original manifest capture do NOT # exist as options in 25.1.8 and are intentionally dropped (gbm is only # ever probed as required:false, and the null input driver isn't an # option here). Intent preserved: Xvfb on, all hardware/GL/DRM off. # * -Dsha1=libcrypto uses base OpenSSL's libcrypto (find_library('crypto') # resolves /usr/lib/libcrypto.so; in base /usr/include). # * libdrm/pciaccess/epoxy/gbm are all probed required:false in meson.build, # so the -D*=false switches don't trip a hard missing-dependency error on # Hammerhead (none of those libs exist here). Verified by source read. set -e # Resolve the port dir (holds patches/) BEFORE cd'ing into the extracted source. PORTDIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) cd "$SRCDIR" # --- Hammerhead/illumos portability patches (rationale in each patch header) --- for p in "$PORTDIR"/patches/*.patch; do [ -f "$p" ] || continue echo "==> Applying patch: $(basename "$p")" patch -p1 < "$p" done export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig:/usr/lib/pkgconfig:$PKG_CONFIG_PATH" # Template B illumos flags: __EXTENSIONS__ + _POSIX_PTHREAD_SEMANTICS select the # XPG/POSIX prototypes (msg_control, *_r, etc.). coral's default CFLAGS is only # "-O2 -pipe" and its LDFLAGS is just "-R$PREFIX/lib", so add the rest here. export CFLAGS="${CFLAGS} -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS" export LDFLAGS="${LDFLAGS} -L$PREFIX/lib -Wl,-R,$PREFIX/lib" meson setup build \ --prefix="$PREFIX" \ --libdir=lib \ --buildtype=release \ -Dxvfb=true \ -Dxorg=false -Dxephyr=false -Dxnest=false -Dxfbdev=false -Dxwin=false -Dxquartz=false \ -Dglamor=false -Dglx=false -Dglx_dri=false \ -Ddri1=false -Ddri2=false -Ddri3=false -Ddrm=false \ -Dudev=false -Dudev_kms=false -Dhal=false \ -Dsystemd_logind=false -Dsystemd_notify=false -Dseatd_libseat=false \ -Dsuid_wrapper=false -Dxcsecurity=false -Dxselinux=false \ -Dpciaccess=false -Dagp=false -Dint10=false -Dvgahw=false \ -Dxf86bigfont=false -Dtests=false \ -Ddocs=false -Ddevel-docs=false -Ddocs-pdf=false \ -Dxf86-input-inputtest=false \ -Ddtrace=false -Dlinux_acpi=false -Dlinux_apm=false \ -Dsha1=libcrypto \ -Dxkb_dir=/usr/local/share/X11/xkb \ -Dxkb_bin_dir=/usr/local/bin \ -Dxkb_output_dir=/var/lib/xkb ninja -C build -j${JOBS:-1} DESTDIR="$PKGDIR" ninja -C build install # xlibre-xserver - XLibre X server, built Xvfb-only (headless software framebuffer) # THE crux port of the desktop initiative. No hardware/DRM/GL DDX - just Xvfb, # which x11vnc then bridges to VNC. XLibre has no illumos upstream target, so # this port carries Hammerhead/illumos portability patches (see patches/). # https://github.com/X11Libre/xserver [package] name = "xlibre-xserver" version = "25.1.8" release = 1 description = "XLibre X server (Xvfb-only headless build)" url = "https://github.com/X11Libre/xserver" license = "MIT" maintainer = "Chris Tusa " arch = "x86_64" [dependencies] runtime = ["pixman", "libX11", "libXfont2", "libxkbfile", "libXau", "libXdmcp", "libXext", "font-util", "xkeyboard-config", "xkbcomp", "xauth"] build = ["pixman", "xorgproto", "xtrans", "libXfont2", "libxkbfile", "font-util", "util-macros", "libX11", "libXau", "libXdmcp", "libXext", "libXfixes"] [[source]] file = "xlibre-xserver-25.1.8.tar.gz" urls = ["https://github.com/X11Libre/xserver/archive/refs/tags/xlibre-xserver-25.1.8.tar.gz"] checksum = "18091f53e8700801b61f0d20c30d850d1060cb31f6a0d2046249bb413809ae16" [build] parallel = true Treat Hammerhead like Solaris/illumos in the os-layer meson build. Meson derives host_machine.system() from uname sysname, which on Hammerhead is "hammerhead", not "sunos". The os/ static library's Solaris branch (which adds -lsocket/-lnsl and the _XOPEN_SOURCE/__EXTENSIONS__ defines needed for struct msghdr.msg_control and the XPG socket API) therefore never fires, producing undefined socket()/gethostbyname() symbols at link time. Hammerhead IS illumos, so extend the guard to match its sysname. --- a/os/meson.build +++ b/os/meson.build @@ -63,7 +63,7 @@ os_c_args = [] # eg. struct msghdr -> msg_control -if host_machine.system() == 'sunos' +if host_machine.system() == 'sunos' or host_machine.system() == 'hammerhead' os_c_args += '-D_XOPEN_SOURCE=1' os_c_args += '-D_XOPEN_SOURCE_EXTENDED=1' os_c_args += '-D__EXTENSIONS__' Fix inverted re-arm check in the illumos event-ports (PORT_SOURCE_FD) ospoll backend - the listening socket only ever accepted exactly one client for the lifetime of the server. Root cause (found 2026-07-22, hh-alpha9, Task 8 M5 integration test): illumos event ports are one-shot per delivered event - once port_getn() returns an event for a PORT_SOURCE_FD object, that fd is automatically dissociated from the port and MUST be re-associated (port_associate() again, done here via epoll_mod()) to keep receiving further events on it. ospoll_wait()'s PORT-backend dispatch loop re-arms level-triggered fds with: if (osfd->trigger == ospoll_trigger_level && !xorg_list_is_empty(&osfd->deleted)) { epoll_mod(ospoll, osfd); } osfd->deleted is the intrusive list node ospoll_remove() links onto ospoll->deleted when an fd is torn down (see the xorg_list_add call right after port_dissociate() in ospoll_remove()). So xorg_list_is_empty(&osfd->deleted) is true exactly when this specific fd has NOT just been removed by its own callback - i.e. it's still a live, valid fd safe to re-arm. The listening socket is a level-triggered fd that lives for the entire server lifetime and is never removed, so its deleted node is always empty. With the `!` in front, the condition only fires when the fd HAS just been deleted (backwards - re-arming an fd that's about to be freed), and never fires for the common "still alive" case. Net effect: the listen socket's single initial port_associate() (done at ospoll_add time) gets consumed by the first accept() event and is never renewed, so every connection after the first sits unnoticed in the kernel accept backlog forever. Confirmed via truss -p : after the first client's full connection setup, port_getn() goes back to sleeping and no further accept(4, ...) call is ever made, even though a second client's connect() has already completed at the socket layer (visible in `netstat -f unix` as a live but un-accepted pair). Fix: drop the negation so accepting fds get re-armed, and only skip fds that were actually just torn down. --- a/os/ospoll.c +++ b/os/ospoll.c @@ -638,7 +638,7 @@ osfd->callback(osfd->fd, xevents, osfd->data); if (osfd->trigger == ospoll_trigger_level && - !xorg_list_is_empty(&osfd->deleted)) { + xorg_list_is_empty(&osfd->deleted)) { epoll_mod(ospoll, osfd); } }