Skip to content

prefork MPM: fix "httpd -k restart" leaving the server unable to serve - #727

Open
notroj wants to merge 4 commits into
apache:trunkfrom
notroj:prefork-restart
Open

prefork MPM: fix "httpd -k restart" leaving the server unable to serve#727
notroj wants to merge 4 commits into
apache:trunkfrom
notroj:prefork-restart

Conversation

@notroj

@notroj notroj commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

An ungraceful restart under prefork leaves the server with no children.
The listening socket stays open, so connections are accepted and never
answered: requests hang rather than fail.

prefork_run() kills the previous generation with
ap_unixd_killpg(getpgrp(), SIGHUP). The parent is in that group. Its
handler, sig_restart() in os/unix/unixd.c, has a guard against taking a
signal it is already handling, but unset_signals() has cleared
restart_pending by then, as a pconf cleanup during the config reload. So
the parent takes its own signal as a fresh restart request and loops:
kill children, come up, restart, repeat. The file comment at prefork.c:146
has always said the root process ignores this signal; it doesn't.

Introduced by 243c5fa (SVN r1892587), which moved the stop of the old
generation to after the config reload, and so to the far side of the flag
being cleared. Reproducible on trunk with a three-module config and no
mod_systemd involved:

httpd -k start && httpd -k restart

leaves zero children and a request that times out. 2.4.x is not affected:
it still stops children before the reload, where the guard does its job.

Also here:

  • test/modules/core/test_008_restart.py covers graceful reload, ungraceful
    restart with the parent pid unchanged, and two restarts in a row. It is
    MPM-generic, so it runs under whichever MPM the job builds. Verified
    under both event and prefork.
  • apache_hard_restart() and read_pid_file() move from the mod_systemd
    tests into HttpdTestEnv, for the above.
  • README.CHANGES gains two conventions: MPM changes are named for the MPM,
    and a bug which never reached a release needs no entry. Hence no changes
    entry here, this regression being trunk-only.

Not addressed: motorz has the identical killpg pattern at motorz.c:2417
and is likely affected, but it is experimental and I have not built or
tested it. Separately, restarting twice quickly makes mod_cgid fail to
bind its socket (AH01243) because the new daemon starts before the old
has unlinked it; the new test ignores that message rather than fixing it.

🤖 Generated with Claude Code

notroj and others added 4 commits August 29, 2026 18:21
  a bug which never reached a release needs no entry.

No functional change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
  killing the previous generation, which is signalled by process group
  and so includes the parent itself.

Fixes: 243c5fa (SVN r1892587)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
  Moved here from the mod_systemd tests, for use by other suites.

No functional change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant