htsweb.c:310 ends the server with:
htsthread_wait_n(background_threads - 1);
background_threads counts the threads that must not be waited for: the client_ping pinger, plus one per launched mirror. Subtracting one from it asks the wait to leave one fewer thread outstanding than there are non-joinable ones, so with no mirror launched it degrades to htsthread_wait_n(0) while the pinger still holds a slot. client_ping() never returns on POSIX (it loops until the parent dies, then calls exit()), so the wait cannot be satisfied.
Normally this is invisible: the pinger kills the process when the launcher script goes away. It shows on the error path, where help_server() fails fast and there is no mirror to excuse the off-by-one:
$ python3 -c "import socket,os,time; s=socket.socket(); s.bind(('127.0.0.1',18747)); s.listen(1); print(os.getpid()); time.sleep(300)" &
$ htsserver /usr/share/httrack/ --port 18747 --ppid <that pid>
Unable to initialize a temporary server (no remaining port)
EXITED
<hangs>
Master hangs there in 4 runs out of 10 (it is a race with the pinger's own start). Rebuilding with background_threads instead of background_threads - 1 hangs in 0 out of 10.
Found while working on #747. That fix counts a thread from the moment it is spawned rather than when it starts running, which closes the window the pinger was slipping through, and takes this from 4 in 10 to 10 in 10. The off-by-one is the actual defect and predates it.
htsweb.c:310ends the server with:background_threadscounts the threads that must not be waited for: theclient_pingpinger, plus one per launched mirror. Subtracting one from it asks the wait to leave one fewer thread outstanding than there are non-joinable ones, so with no mirror launched it degrades tohtsthread_wait_n(0)while the pinger still holds a slot.client_ping()never returns on POSIX (it loops until the parent dies, then callsexit()), so the wait cannot be satisfied.Normally this is invisible: the pinger kills the process when the launcher script goes away. It shows on the error path, where
help_server()fails fast and there is no mirror to excuse the off-by-one:Master hangs there in 4 runs out of 10 (it is a race with the pinger's own start). Rebuilding with
background_threadsinstead ofbackground_threads - 1hangs in 0 out of 10.Found while working on #747. That fix counts a thread from the moment it is spawned rather than when it starts running, which closes the window the pinger was slipping through, and takes this from 4 in 10 to 10 in 10. The off-by-one is the actual defect and predates it.