D373 - Asking must not take, and waiting must not hold

decided - 2026-08-29

select is what turns a server's loop: klogsrv calls it between listen and accept, so without it the loop never turns and the guest takes its error path having served nothing. Two things about implementing it were not obvious until they were written down.

Asking must not take

The standard library has no readiness primitive, so the only way to find out whether a listener has a connection waiting is to accept one. Which means the naive select consumes exactly what it was asked to report: the guest is told a connection is ready, calls accept, and waits forever for the next one - having had the first taken by the call that only asked.

So a listener carries the connection select found, and the guest's own accept takes it before it waits on anything. A stream is asked by peek, which is a read that does not advance; nothing is consumed there either.

Zero bytes from a peek is also ready, and that matters: an end-of-file is a read that returns immediately, and a select that called it not-ready would park a guest on a connection that had already closed.

Waiting must not hold

accept blocks, because the interface does. The first version blocked while holding the descriptor table, which is every file call in the process - including the select on another thread that would have been the thing to say a connection had arrived. A guest with one thread would not have noticed and a guest with two would have deadlocked, in a way that looked like a hang in guest code.

So the listener is cloned, the table is dropped, and the wait happens outside it. The general shape: a lock held across a blocking call is a deadlock waiting for a second thread.

And polling is stated rather than hidden

Readiness is asked in a loop a millisecond apart. That costs latency a real select would not, and a guest measuring its own wakeup latency would see it. It is in the knowledge file, because the alternative - saying nothing - is how a difference like that becomes somebody else's unexplained measurement later.