Honor QUIESCE/SHUTDOWN in the send-stall retry loops - #206
Conversation
The paced no-progress retry in send_all() and send_raw_all() waits out up to 10 seconds of closed receive window without looking at httpd->flag. A worker sitting in that loop when the operator enters P HTTPD keeps sleeping and retrying against a client that has stopped reading, and shutdown waits for the workers -- so a stalled client delayed the stop by up to the full stall budget. Same family as #122: every wait a worker performs has to honor quiesce. Both loops now check HTTPD_FLAG_QUIESCE/SHUTDOWN before each pause and fail the send instead of waiting, so a shutdown interrupts an in-progress stall within one SEND_STALL_PAUSE. Deliberately narrow: only the stall wait is cut short. A send that is making progress continues during quiesce, so in-flight responses to healthy clients still drain gracefully; only a client that has stopped reading while the server is stopping is cut off, and in the chunked path the torn- chunk handling (drop framing, clear keep-alive) applies as usual. Fixes #205
|
Live-Test auf MVS: die Stall-Strecke selbst ist erstmals bestätigt, die Quiesce-Prüfung dieses PRs aber noch nicht. Warum ein Stall von außen schwer zu erzeugen ist. Die MVS-Sockets laufen bei dieser Konfiguration über Host-Sockets (Linux-Listener auf 0.0.0.0:8080), und der Linux-Sendepuffer tunt bis Bestätigt (#200/#202, Stall-Budget): 150 pipelined Requests (~13,8 MB), Client liest 40 s lang gar nichts, Nur 2,26 von 13,8 MB kamen an, danach hat der Server die Verbindung geschlossen. Genau das erwartete Verhalten: Puffer voll → Nicht bestätigt (dieser PR): Dass ein Warnung für Nachahmer: Der 150-Request-Test hat Hercules zum Absturz gebracht (SIGSEGV im Watchdog-Diagnosepfad, |
|
Live-Nachweis erbracht — GRÜN. Er war erst möglich, nachdem der darunterliegende Plattformfehler behoben war: Hercules' X'75'-SEND ( Testaufbau: durchgehende Stall-Last statt Einzelschuss — 4 gestaffelte Verbindungen, je 150 pipelined Requests (~14 MB), die nie lesen und sich alle 15 s erneuern. Dass die Worker wirklich in Stall-Pausen sitzen, ist an der Antwortzeit messbar: 0,95 s statt der üblichen 0,07 s. Ergebnis: Port 8080 nach 1,12 s zu, Adressraum nach 3 s beendet — auf dem Niveau eines Stops ganz ohne Last (Baseline 1,22 s). Kein Nebenbefund, ebenfalls erstmals live bestätigt: Das Stall-Budget aus #200/#202 feuert — 150 pipelined Requests mit 40 s Funkstille enden mit serverseitigem Close statt Endlos-Spin, während httpd parallel in ~90 ms weiter ausliefert. Repro, Patch und beide Messreihen sind in |
Fixes #205
The paced no-progress retry from #200 (
send_all()inhttpprtv.c) and #202 (send_raw_all()inhttpsend.c) waited out up to 10 s of closed receive window without looking athttpd->flag— a worker sitting in that loop when the operator entersP HTTPDdelayed shutdown by up to the full stall budget, since shutdown waits for the workers (#122 family).Both loops now check
HTTPD_FLAG_QUIESCE | HTTPD_FLAG_SHUTDOWNbefore each pause and fail the send instead of waiting, so a shutdown interrupts an in-progress stall within oneSEND_STALL_PAUSE(100 ms).Deliberately narrow: only the stall wait is cut short. A send making progress (
rc > 0) continues during quiesce, so in-flight responses to healthy clients still drain gracefully. A cut-off in the chunked path goes through the torn-chunk handling from #202 (framing dropped, keep-alive cleared,CSTATE_DONEset).Verification
make modulesclean (cc370,-Wall -Werror),make test-host98 assertions pass.curl --limit-rate 1kon/.dm?l=4096), issueP HTTPDmid-transfer; the server must come down promptly (within ~100 ms of the workers' next stall iteration) instead of waiting out the stall budget, and the curl gets a truncated-but-cleanly-closed connection.