Skip to content

FTPD: shutdown waits up to ~5 s on idle sessions — getline() poll interval bounds FTPD_QUIESCE detection #66

Description

@mgrossmann

Summary

ftpd_session_getline() (src/ftpd#ses.c:177-204) polls the control socket with
a 5 s select() timeout and re-checks FTPD_QUIESCE on every timeout. That is
deliberate and it works — it is the fix that closed #2. What remains is the
residual boundary: an idle session only notices a shutdown at the next poll
expiry, so terminate() can wait up to ~5 s in cthread_manager_term() before
the last worker exits.

The delay is bounded and it is ~5 s in total, not 5 s per session — workers poll
concurrently. So this is a latency wart on /P FTPD and /F FTPD,SHUTDOWN, not
a hang. Recording it so it is tracked rather than rediscovered.

Current behaviour

tv.tv_sec = 5;
tv.tv_usec = 0;
rc = select(sess->ctrl_sock + 1, &rfds, NULL, NULL, &tv);
if (rc < 0)
    return -1;

if (rc == 0) {
    /* select() timed out -- check shutdown and idle */
    if (sess->server->flags & FTPD_QUIESCE)
        return -1;
    ...

The real idle timeout is measured cumulatively across 5 s rounds via
sess->idle_start, so the poll interval is independent of idle_timeout.

Why the mvsMF fix does not transfer directly

mvsMF solved the equivalent problem by checking the httpd quiesce flag on each
poll iteration and adding a 0.10 s delay. The first half is already present
here
— the flag is checked on every poll.

The second half inverts. In the mvsMF case the 0.10 s delay made a busy poll
cheaper. In ftpd_session_getline() the select() is the blocking wait, so
lowering tv_sec 5 → 0.10 s does not add a delay, it removes one: it means
10 × SVC 75 per second per idle session, permanently, to save at most ~4.9 s
once at shutdown. On MVS 3.8j that trade is not worth making. Shortening the
poll is the wrong lever.

What the real lever is

Waking the blocked select() on demand, rather than shortening its timeout.
Both known mechanisms already have hazards documented in this repo:

  • Post the wakeup ECBftpd.c:404-408 records that ecb_post alone does
    not reliably wake DYN75 selectex; SVC 75 uses its own internal wait rather
    than an MVS WAIT on the ECB.
  • Close the socket under the workerftpd.c:391-396 records that closing
    a socket while another TCB holds it in select() can leave the TCP/IP control
    block undefined and hang select() indefinitely on 3.8j.

A third option is a self-pipe / loopback wakeup socket per session, added to the
fd_set, which shutdown writes one byte to. That costs one socket per session —
needs measuring against the memory budget before it is worth anything.

So this is research, not a one-liner.

Acceptance

  • Shutdown latency attributable to idle worker sessions is materially below the
    current ~5 s, or
  • the investigation concludes the current bounded 5 s is the right trade for
    3.8j and this issue is closed with that reasoning recorded.

Either outcome is fine. What is not fine is silently lowering the poll interval.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions