Pull latest libakerror: static TLS fix landed
All checks were successful
akbasic CI Build / cmake_build (push) Successful in 3m25s
akbasic CI Build / sanitizers (push) Successful in 4m48s
akbasic CI Build / coverage (push) Successful in 4m18s
akbasic CI Build / akgl_build (push) Successful in 8m6s
akbasic CI Build / mutation_test (push) Successful in 16m49s
All checks were successful
akbasic CI Build / cmake_build (push) Successful in 3m25s
akbasic CI Build / sanitizers (push) Successful in 4m48s
akbasic CI Build / coverage (push) Successful in 4m18s
akbasic CI Build / akgl_build (push) Successful in 8m6s
akbasic CI Build / mutation_test (push) Successful in 16m49s
libakerror main now includes the fix for issue #37 (per-TU static TLS akerr_last_ignored -> single extern definition in src/error.c, one copy per thread instead of one per translation unit) and issue #38 (project() now stamps 2.0.3, matching the release notes). Bump deps/libakerror to origin/main (9249f8c) and update MAINTENANCE.md: drop the now-stale 'IGNORE change costs' subsection and the 2.0.2/2.0.3 version-disagreement note, since both are resolved upstream. Verified: build/basic has no TLS segment and zero -Wunused-variable warnings for akerr_last_ignored; 114/114 tests pass. Co-Authored-By: Andrew Kesterson <andrew@aklabs.net>
This commit is contained in:
@@ -163,7 +163,7 @@ guards every dependency with `if(NOT TARGET ...)`, so a top-level build must def
|
||||
`akerror::akerror` and `akstdlib::akstdlib` from `deps/libakerror` and `deps/libakstdlib`
|
||||
**before** `add_subdirectory(deps/libakgl)`, or the targets are declared twice.
|
||||
|
||||
That order is load-bearing for a second reason: `deps/libakerror` is at **2.0.2**, whose 2.0.0
|
||||
That order is load-bearing for a second reason: `deps/libakerror` is at **2.0.3**, whose 2.0.0
|
||||
was a source and ABI break carrying an soname (`libakerror.so.2`). `libakstdlib` and `libakgl`
|
||||
must be compiled against that header, not a 1.x one, and an installed `libakerror.so.1` must
|
||||
not be picked up. The break is quiet if you get it wrong: the context behind `IGNORE` became
|
||||
@@ -174,46 +174,22 @@ a mixed build leaks pool slots or frees one twice rather than failing to link.
|
||||
|
||||
| Submodule | Version | soname | ABI rule | Version API |
|
||||
|---|---|---|---|---|
|
||||
| `deps/libakerror` | 2.0.2 | `libakerror.so.2` | major only | **none** — no version macro; `include/akbasic/error.h` feature-tests `AKERR_THREAD_SAFE` and `AKERR_EXIT_STATUS_UNREPRESENTABLE` instead |
|
||||
| `deps/libakerror` | 2.0.3 | `libakerror.so.2` | major only | **none** — no version macro; `include/akbasic/error.h` feature-tests `AKERR_THREAD_SAFE` and `AKERR_EXIT_STATUS_UNREPRESENTABLE` instead |
|
||||
| `deps/libakstdlib` | 0.2.0 | `libakstdlib.so.0.2` | **`MAJOR.MINOR` while major is 0** | `AKSL_VERSION_*`, `aksl_version()`, `AKSL_VERSION_CHECK()` |
|
||||
| `deps/libakgl` | 0.9.0 | `libakgl.so.0.9` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` |
|
||||
|
||||
**The `libakerror` row is what `project(akerror VERSION ...)` declares, and it disagrees with
|
||||
that library's own release notes**, which carry a "Release 2.0.3" section describing CI-only
|
||||
changes. The version the build stamps into the soname and into
|
||||
`akerrorConfigVersion.cmake` is 2.0.2; nothing consumers can observe says 2.0.3. Read the
|
||||
table as the ABI and the notes as the changelog, and do not "correct" this row to 2.0.3
|
||||
without the upstream `project()` bump to go with it. Reported as `libakerror` issue #38.
|
||||
`project(akerror VERSION ...)` now stamps 2.0.3, matching that library's own "Release 2.0.3"
|
||||
release notes. It previously disagreed — the soname and `akerrorConfigVersion.cmake` still
|
||||
said 2.0.2 while the notes described 2.0.3 — but that was `libakerror` issue #38, which is
|
||||
closed; the table and the notes agree again.
|
||||
|
||||
#### What 2.0.2's `IGNORE` change costs, measured
|
||||
|
||||
`IGNORE` now takes a *copy* of the context so the pool slot can be released, which fixes a
|
||||
real leak. The copy lives in the public header as a file-scope `static`:
|
||||
|
||||
```c norun
|
||||
static AKERR_THREAD_LOCAL akerr_ErrorContext akerr_last_ignored;
|
||||
```
|
||||
|
||||
`static` means one per translation unit, and `AKERR_THREAD_LOCAL` means each one is
|
||||
thread-local. `sizeof(akerr_ErrorContext)` is **37,296 bytes**, so:
|
||||
|
||||
| Build | TLS segment of `build/basic` |
|
||||
|---|---|
|
||||
| libakerror 2.0.1 | none at all |
|
||||
| libakerror 2.0.2 | 1,417,248 bytes — **1.35 MiB**, per thread |
|
||||
|
||||
38 copies × 37,296 accounts for the segment exactly; `readelf -sW build/basic` shows all 38.
|
||||
It scales with translation-unit count, not with anything about the program, and every thread
|
||||
a host game spawns pays it again — which is worth knowing in a tree that spent a release
|
||||
taking `akbasic_Runtime` from 10.75 MiB to 2.40 MiB.
|
||||
|
||||
It also emits **84 `-Wunused-variable` warnings**, one per TU that includes `akerror.h`
|
||||
without using `IGNORE`. Nothing here builds with `-Werror`, so it is noise rather than a
|
||||
failure — but a consumer that does cannot include the header.
|
||||
|
||||
**Both are `libakerror` issue #37 and neither is worked around here**, per the rule above: a
|
||||
one-line `extern` in the header and a definition in `src/error.c` fixes it upstream, and
|
||||
patching our copy would fork the submodule. Delete this subsection when it lands.
|
||||
`IGNORE` still takes a *copy* of the ignored context so the pool slot can be released, which
|
||||
fixes a real leak, but the copy no longer costs TLS per translation unit. It was a file-scope
|
||||
`static` in the public header — one copy per TU, 37,296 bytes each, 1.35 MiB of thread-local
|
||||
storage in `build/basic` alone, plus 84 `-Wunused-variable` warnings for every TU that never
|
||||
called `IGNORE`. `libakerror` issue #37 moved it to an `extern` declaration in the header with
|
||||
a single definition in `src/error.c`, which restores one copy per thread and silences the
|
||||
warning. Issue #37 is closed and this subsection is gone accordingly.
|
||||
|
||||
For both 0.x libraries the soname carries `MAJOR.MINOR` deliberately: 0.1 and 0.2 are
|
||||
*different* ABIs, and both become major-only at 1.0. Do not read `0.1 → 0.2` as a compatible
|
||||
|
||||
Reference in New Issue
Block a user