arena_types.h + arena_structs.h + arena_externs.h merged into arena.h,
keeping the three logical sections (TYPES / STRUCTS / EXTERNS) with
explicit dividers. arena_inlines_a.h and arena_inlines_b.h stay
separate; arena_inlines_b.h now carries a comment explaining why
merging the two would reintroduce a real #include cycle through
tcache_inlines.h -> arena_choose (the asymmetric cycle-breaker).
Two ordering gotchas this consolidation surfaced:
1. tsd_internals.h is included from tsd.h via tsd_generic.h, sometimes
long before arena.h is loaded (e.g. ckh.c includes ckh.h -> tsd.h
before jemalloc_internal_includes.h). TSD_INITIALIZER's expansion
in tsd_generic.h's function bodies references
ARENA_DECAY_NTICKS_PER_UPDATE, so it must already be defined.
Factor the constant into a new minimal header,
arena_decay_constants.h, that pulls nothing but jemalloc_preamble.h,
and include it from both arena.h and tsd_internals.h. arena_t is
still added as a forward decl in tsd_internals.h -- including
arena.h there would trigger arena_stats.h -> mutex.h -> tsd.h ->
re-entry into this very file.
2. extent_dss.h previously included arena_types.h for the arena_t
pointer type, but arena.h now includes extent_dss.h (it was a
STRUCTS-section dep). Forward-decl arena_t in extent_dss.h to
break that cycle.
Additional forward decls in tcache.h and large.h (arena_t *). These
were previously satisfied by the master include order loading
arena_types.h before everything else; with arena.h now in the EXTERNS
section, large.h and tcache.h are parsed earlier than arena.h, so
they need to declare arena_t themselves.
jemalloc_internal_externs.h's #include of arena_types.h was
vestigial -- the file uses no arena symbols. Dropped.
Header files are now self-contained, which makes the relationships
between the files clearer, and crucially allows LSP tools like `clangd`
to function correctly in all of our header files. I have verified that
the headers are self-contained (aside from the various Windows shims) by
compiling them as if they were C files – in a follow-up commit I plan to
add this to CI to ensure we don't regress on this front.
For better or worse, Jemalloc has a significant number of global
variables. Making all eligible global variables `static` and/or `const`
at least makes it slightly easier to reason about them, as these
qualifications communicate to the programmer restrictions on their use
without having to `grep` the whole codebase.
This is part of a broader change to make header files better represent the
dependencies between one another (see
https://github.com/jemalloc/jemalloc/issues/533). It breaks up component headers
into smaller parts that can be made to have a simpler dependency graph.
For the autogenerated headers (smoothstep.h and size_classes.h), no splitting
was necessary, so I didn't add support to emit multiple headers.
Rather than protecting dss operations with a mutex, use atomic
operations. This has negligible impact on synchronization overhead
during typical dss allocation, but is a substantial improvement for
extent_in_dss() and the newly added extent_dss_mergeable(), which can be
called multiple times during extent deallocations.
This change also has the advantage of avoiding tsd in deallocation paths
associated with purging, which resolves potential deadlocks during
thread exit due to attempted tsd resurrection.
This resolves#425.