What
src/thdmgr/clibthdi.h and include/clibthdi.h are byte-identical copies of the same header. It is the only duplicated header in the tree — a sweep of every src/**/*.h against include/ turns up no other pair.
Why it is a trap and not just untidy
Every translation unit in src/thdmgr reaches it with a quoted include:
which searches the including file's own directory first. So:
- the library compiles against
src/thdmgr/clibthdi.h
- consumers get
include/clibthdi.h, which is what sdk/mklibc.py installs into the cc370 sysroot
The two agree only by accident of nobody having edited one of them. This header declares CTHDMGR, CTHDWORK and CTHDQUE — control blocks with fixed offsets that httpd decodes field by field (httpcons.c d_cthdmgr() / d_cthdwork()). A field added to one copy and not the other means the library and every consumer disagree about a struct layout, silently: no warning, no link error, just an offset that is right on one side of the boundary and wrong on the other.
Found while implementing #11 — the first edit to the header compiled against the stale copy and failed with CTHDWORK_STATE_STUCK undeclared, which is the lucky outcome. Adding a struct field rather than a #define would have linked and run.
Same class as #17's two try() wrappers: one logical thing kept in two files, where every future fix costs two edits and one chance to touch the wrong one.
Fix
Delete src/thdmgr/clibthdi.h and let the quoted include fall through to -I include, which sdk/mklibc.py already passes (CFLAGS carries -I{ROOT}/include alongside -I{ROOT}/src/thdmgr). Nothing else should have to move — include/clibthdi.h includes clibthrd.h, which resolves on the same path.
Deliberately not done as part of #11: that is a fix PR, and changing which file the whole thread manager compiles against is a build-structure change that wants its own before/after — ideally a comparison of the generated .s for all eight src/thdmgr translation units, which should come out byte-identical since the two headers are the same today. Both copies were updated in lockstep there instead, which keeps the trap alive but keeps the fix reviewable.
Check before closing
src/thdmgr/files.txt and src/thdmgr/makefile may name the header; confirm neither breaks. And re-run the duplicate sweep afterwards, because it is cheap:
for f in $(find src -name '*.h'); do
b=$(basename $f); [ -f "include/$b" ] && echo "DUP $f"
done
What
src/thdmgr/clibthdi.handinclude/clibthdi.hare byte-identical copies of the same header. It is the only duplicated header in the tree — a sweep of everysrc/**/*.hagainstinclude/turns up no other pair.Why it is a trap and not just untidy
Every translation unit in
src/thdmgrreaches it with a quoted include:which searches the including file's own directory first. So:
src/thdmgr/clibthdi.hinclude/clibthdi.h, which is whatsdk/mklibc.pyinstalls into the cc370 sysrootThe two agree only by accident of nobody having edited one of them. This header declares
CTHDMGR,CTHDWORKandCTHDQUE— control blocks with fixed offsets that httpd decodes field by field (httpcons.cd_cthdmgr()/d_cthdwork()). A field added to one copy and not the other means the library and every consumer disagree about a struct layout, silently: no warning, no link error, just an offset that is right on one side of the boundary and wrong on the other.Found while implementing #11 — the first edit to the header compiled against the stale copy and failed with
CTHDWORK_STATE_STUCK undeclared, which is the lucky outcome. Adding a struct field rather than a#definewould have linked and run.Same class as #17's two
try()wrappers: one logical thing kept in two files, where every future fix costs two edits and one chance to touch the wrong one.Fix
Delete
src/thdmgr/clibthdi.hand let the quoted include fall through to-I include, whichsdk/mklibc.pyalready passes (CFLAGScarries-I{ROOT}/includealongside-I{ROOT}/src/thdmgr). Nothing else should have to move —include/clibthdi.hincludesclibthrd.h, which resolves on the same path.Deliberately not done as part of #11: that is a fix PR, and changing which file the whole thread manager compiles against is a build-structure change that wants its own before/after — ideally a comparison of the generated
.sfor all eightsrc/thdmgrtranslation units, which should come out byte-identical since the two headers are the same today. Both copies were updated in lockstep there instead, which keeps the trap alive but keeps the fix reviewable.Check before closing
src/thdmgr/files.txtandsrc/thdmgr/makefilemay name the header; confirm neither breaks. And re-run the duplicate sweep afterwards, because it is cheap: