Commit Graph

5 Commits

Author SHA1 Message Date
Vladimir Dubrovin
023eb8f830 Event loops: served on by default, the data relayed by the loops
loopmode is cb unless a configuration says otherwise, as -L2 had it
for a service: its clients on event loops, a connection's data relayed
by the loop itself where nothing but the sockets is between its sides.
A service whose clients cannot share a thread (threadperclient: PAM,
LDAP, FilePlugin, names resolved by the system, -ne) or listening for
connections back (-R) still gives each a thread, as do the standalone
services and builds without fibers. loopmode on and -L keep the loops
with the relay on the client's stack; loopmode off and -L0 a thread
for each client.

The man page tells of cb. tests/run.py --loopmode takes the mode
(cb, on, off) to give every configuration, with two loops; the Linux
workflow runs the suite once more with a thread for each client, which
is no longer what a configuration gets by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 11:49:51 +03:00
Vladimir Dubrovin
c55f736a0d Clients of TCP services on event loops, served by fibers
With -L, or loopmode on for the services which follow, the clients of a
TCP service are served on event loops: loops threads (by default one
for each CPU) each run a loop, and each client is given in turn to one
of them, which serves it on a fiber with the same code a thread runs.
Its waits in sockpoll() wait in the loop, its sockets and a timer
registered there, and the fiber goes on once one is ready or the time
is out; a sleep is a timer alone. A client costs a stack, as large as
its thread's would be, and no thread. The loops start with the first
client served on one and run as long as the process; each keeps up to
256 idle fibers for its next clients.

srvspawn() posts the client to its loop once it is counted, what is
posted made before so that posting cannot fail. A service whose clients
cannot share a thread (threadperclient), or listening for connections
back (-R), all of its clients waiting for one socket, which a loop
waits for once, keeps a thread for each client, as does every service
of a build or a processor without fibers, and the standalone services.

tests/run.py --loopmode runs every configuration with loopmode on, on
two loops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 23:00:16 +03:00
Vladimir Dubrovin
6428c4423f tests: reload cases that hold on slow runners
The downloads spanning a reload asked httpsrv for 64 KB blocks 60 ms
apart, meant as two seconds; but httpsrv sends at most 8 KB a block, so
they took 245 waits, some 15 seconds, and on the CI runners, whose
timers stretch, more than the 20 the cases waited. They now ask for
400 KB in 8 KB blocks 40 ms apart, two seconds indeed, and are waited
for up to a minute.

The UDP part of the takeover case slept 1.5 s after the reload adding
its udppm and then counted every datagram unanswered as lost; it now
asks until the service answers first, and wants more than 20
datagrams through the reloads rather than 100, what a slow runner can
send. That none is lost is the check.

On a failure, run.py prints every log line with a result code other
than 0, not only the last lines, so the reason a connection ended is
shown wherever it was logged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:25:07 +03:00
Vladimir Dubrovin
facc35e287 Make the TLS and port-range cases hold on every platform
The MITM case reached its origin by address, so it depended on the
certificate 3proxy spoofs carrying an IP alternative name. It does when the
upstream certificate is copied, which is what happens on Linux and macOS
but not on Windows, where the client then refused the connection. Point a
name at 127.0.0.1 with nsrecord instead, and check the chain rather than
the name: an intercepted certificate names the upstream host, not the one
that was asked for. The log assertions gain from it too, since the name is
better evidence than a port that the request was seen.

nsrecord needs nserver as well as nscache, and has to follow nscache, so
say that in the manual: the record goes into the table nscache allocates,
and the table is only consulted when nserver is set.

The port-range fallback was exercised with a range the same case had
already used, so on a busy machine it could fail to bind for the ordinary
reason rather than the one under test. Use privileged ports, which nothing
can take.

When a case fails, print what its servers wrote: the reason usually goes to
the server's stderr, which was captured and then thrown away.
2026-08-26 09:11:56 +03:00
Vladimir Dubrovin
73fbf9d262 Add tests 2026-08-25 18:03:50 +03:00