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); } } Select the Solaris/illumos os-support backend for Hammerhead in the Xorg DDX. hw/xfree86/os-support/meson.build picks the per-OS console backend from host_machine.system(). On Hammerhead uname sysname is "hammerhead", not "sunos", so the `elif host_machine.system() == 'sunos'` arm never fires and the build silently falls through to the generic *stub* backend (stub_init.c, VTsw_noop, etc.). That stub is a no-op: xf86OpenConsole() does nothing, so the server never touches /dev/console / VT_SETDISPINFO and can't drive the framebuffer console the M2 illumosfb driver targets. Hammerhead IS illumos, so the solaris arm (sun_init.c: /dev/console + VT_SETDISPINFO, sun_vid.c, sun_apm/bell, solaris-amd64.S port I/O) is exactly the load-bearing console layer we need. Extend the guard to match Hammerhead's sysname, mirroring the os/meson.build sunos-sysname patch (0001). --- a/hw/xfree86/os-support/meson.build +++ b/hw/xfree86/os-support/meson.build @@ -62,7 +62,7 @@ if host_machine.system() == 'linux' srcs_xorg_os_support += 'shared/pm_noop.c' endif -elif host_machine.system() == 'sunos' +elif host_machine.system() == 'sunos' or host_machine.system() == 'hammerhead' srcs_xorg_os_support += [ 'solaris/sun_apm.c', 'solaris/sun_bell.c', Fix build of the Solaris APM os-support file: include xf86_priv.h. XLibre moved the power-management hook declarations extern int (*xf86PMGetEventFromOs)(...); extern pmWait (*xf86PMConfirmEventToOs)(...); void xf86HandlePMEvents(int fd, void *data); into hw/xfree86/common/xf86_priv.h (lowercase-underscore), and updated the Linux backend (lnx_apm.c / lnx_acpi.c include "xf86_priv.h") but NOT the Solaris backend. hw/xfree86/os-support/solaris/sun_apm.c still includes only "xf86Priv.h" (capital-P, a different header), so on Hammerhead/illumos - the only platform that still compiles sun_apm.c - xf86OSPMOpen() fails with "xf86PMGetEventFromOs undeclared" (GCC 14 hard error). This never surfaced upstream because XLibre's CI has no illumos target. Add the missing include, matching lnx_apm.c. --- a/hw/xfree86/os-support/solaris/sun_apm.c +++ b/hw/xfree86/os-support/solaris/sun_apm.c @@ -58,6 +58,7 @@ #include "os.h" #include "xf86.h" +#include "xf86_priv.h" #include "xf86Priv.h" #include "xf86_os_support.h" #include "xf86_OSproc.h" Disable the X server input thread by default on Hammerhead/illumos. XLibre's threaded input (INPUTTHREAD, default on for non-Windows) runs a separate input thread whose ospoll uses the Solaris event-ports backend (port_getn / portfs). On illumos the input->main wakeup self-pipe fd is re-armed reporting POLLIN "ready" every cycle with nothing to deliver, so the input thread and the main thread ping-pong on that pipe as fast as the CPU allows: measured ~340k portfs+write/s on [InputThread] and ~225k portfs+read/s on [MainThread] = TWO fully pegged cores at idle (conky read CPU 247%, load avg 2.0), and a sluggish pointer because the saturated main thread services real motion late. The kbd/consms device fds themselves were fine (no repeated reads, errno 0) - it is purely the threaded-input wakeup pipe. Xvfb never hit this (no real input devices, no input thread). XLibre REMOVED the historic `-noThreadedInput` command-line flag (only `-dumbSched` still sets InputThreadEnable = FALSE, but that also disables the smart scheduler). Rather than depend on a launch flag that a boot service or .xinitrc could forget - reintroducing a 200%-CPU mystery - flip the compiled default so a plain `Xorg` invocation is correct. Input is then serviced in the main dispatch loop (the pre-2016 default; fully functional). The smart scheduler is left untouched. All InputThread machinery stays compiled in, so `-dumbSched`/future flags could still toggle it. This is an illumos/Solaris-specific XLibre defect (event-ports ospoll re-arm vs. the threaded-input self-pipe); XLibre CI has no illumos target. Worth filing upstream. Complements 0002-ospoll-port-listener-rearm. --- a/os/inputthread.c +++ b/os/inputthread.c @@ -44,7 +44,7 @@ #if INPUTTHREAD -Bool InputThreadEnable = TRUE; +Bool InputThreadEnable = FALSE; /** * An input device as seen by the threaded input facility