1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
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 <Xvfb pid>: 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);
}
}
|