Skip to content

S11.09: Sweep — AtomicCounter family + TLS + FatFs onto PoolAllocator #412

Description

@DavidCozens

Parent epic: #29

Context

S11.08 (#410 / #411) closed the FreeRTOS sweep — the third platform sweep. This story
closes out E11's class-by-class migration with the AtomicCounter family + TLS +
FatFs
classes that were explicitly deferred from S11.04 – S11.08 because they don't
sit cleanly under one platform umbrella. Four classes across three Platform/
subtrees; all four are storage-cast today and get the canonical 3-TU split +
SolidSyslogPoolAllocator treatment.

Class Lines Vtable base Today's shape State
StdAtomicCounter 75 AtomicCounter Storage-cast _Atomic uint32_t
WindowsAtomicCounter 80 AtomicCounter Storage-cast volatile LONG
TlsStream 460 Stream Storage-cast SSL_CTX*, SSL*, BIO_METHOD*, config
FatFsFile 145 File Storage-cast FIL, IsOpen

Out of scope per E11 epic: all of Platform/Posix/, Platform/Windows/ (bar
WindowsAtomicCounter), Platform/FreeRtos/ — those are S11.06 / S11.07 / S11.08
(done). SolidSyslog core retrofit is S11.10. Wholesale MISRA storage-cast
deviation removal is S11.11.

Decisions locked in pre-raise

1. One new public GoF null — SolidSyslogNullAtomicCounter. Symmetric with the
S11.06 wave (NullDatagram, NullStream, NullFile, NullResolver) that introduced
publicly-visible nulls when more than one platform implementation shares a vtable
base. Both StdAtomicCounter (Linux/clang/gcc) and WindowsAtomicCounter (MSVC)
need a pool-exhaustion fallback; both are gated mutually-exclusive in tests
(HAVE_STDATOMIC_H / HAVE_WINDOWS_INTERLOCKED), so a TU-private fallback would
duplicate; and a future FreeRTOS atomic counter (if <stdatomic.h> isn't viable on
some port) would reach for the same fallback. Public shape now is consistent.

SolidSyslogNullAtomicCounter_Get's Increment returns 1U unconditionally —
RFC 5424 §7.3.1 requires sequenceIds in [1, 2^31-1] and never 0. Returning 1U
looks like the post-power-on / post-wrap state, which is the safest indistinguishable
behaviour.

No other new public nulls — NullStream (S11.06) covers TlsStream; NullFile
(S11.06) covers FatFsFile.

Fallback Consumer in S11.09 Source
SolidSyslogNullAtomicCounter StdAtomicCounter S11.09 new
SolidSyslogNullAtomicCounter WindowsAtomicCounter S11.09 new
SolidSyslogNullStream TlsStream S11.06
SolidSyslogNullFile FatFsFile S11.06

2. Pool size defaults — all four at 1U. None of the four has a use case for
multiple concurrent instances in any single target today.

Class Tunable Default
StdAtomicCounter SOLIDSYSLOG_STD_ATOMIC_COUNTER_POOL_SIZE 1U
WindowsAtomicCounter SOLIDSYSLOG_WINDOWS_ATOMIC_COUNTER_POOL_SIZE 1U
TlsStream SOLIDSYSLOG_TLS_STREAM_POOL_SIZE 1U
FatFsFile SOLIDSYSLOG_FATFS_FILE_POOL_SIZE 1U

3. Three-TU split per class — unchanged from prior sweeps:

  • SolidSyslog<Class>.c — vtable + _Initialise(base, ...) + _Cleanup(base).
  • SolidSyslog<Class>Private.h — concrete struct + private signatures, TU-internal.
  • SolidSyslog<Class>Static.c — pool + _Create/_Destroy/IndexFromHandle
    • CleanupAtIndex + fallback assignment. Helpers static inline per 78c059e.

4. AtomicCounter whitebox-test access preserved. Today
Tests/SolidSyslog{Std,Windows}AtomicCounterTestHelper.c reach into the production
.c via #include to call StdAtomicCounter_Init / WindowsAtomicCounter_Init
for the wraparound test (positioning the counter near INT32_MAX). After the split,
the _Init helper stays in SolidSyslog<*>AtomicCounter.c alongside _Increment
(struct definition moves to *Private.h); the TestHelper continues to
whitebox-include the .c and additionally gets the include path for *Private.h.
Wraparound test mechanism unchanged.

5. TlsStream is refactor-only. Bounded handshake retry via the injected
SolidSyslogSleepFunction, the BIO_METHOD lifecycle, SNI / cipher-list / trust-anchor
/ client-cert configuration, and all OpenSSL error handling preserved verbatim. The
OpenSslFake seam stays intact for unit tests.

6. FatFsFile's SOLIDSYSLOG_FATFS_FILE_SIZE of 180 intptrs is deleted along
with the public Storage typedef.
The struct (carrying the full FIL with the
512-byte sector buffer) moves to the private header; sizing is validated internally
by SOLIDSYSLOG_STATIC_ASSERT in SolidSyslogFatFsFile.c. The S21.03 follow-up that
was going to make FF_MAX_SS > 512 overridable becomes simpler — the override is now
purely a pool-internal concern, not a public-API one.

7. No new MISRA suppressions. Storage-cast deviations on all four classes are
removed by this story.

8. File-scope statics carry the class-prefix shape (StdAtomicCounter_InUse,
StdAtomicCounter_Pool, StdAtomicCounter_Allocator) from the start.

9. INTERFACE-library shapes preserved. Platform/FatFs/CMakeLists.txt stays an
INTERFACE target — SolidSyslogFatFsFileStatic.c joins SolidSyslogFatFsFile.c in
every consumer's source list:

  • Bdd/Targets/FreeRtos/CMakeLists.txt
  • Tests/FatFs/CMakeLists.txt

Platform/Atomics/CMakeLists.txt, Platform/OpenSsl/CMakeLists.txt, and
Platform/Windows/CMakeLists.txt's HAVE_WINDOWS_INTERLOCKED block all stay
PRIVATE-source — the new *Static.c is added alongside the existing entry.

Sequencing on the work branch

Recommended commit shape on refactor/s11-09-atomics-tls-fatfs-sweep:

  1. feat: S11.09 add SolidSyslogNullAtomicCounter
  2. refactor: S11.09 migrate StdAtomicCounter onto PoolAllocator
  3. refactor: S11.09 migrate WindowsAtomicCounter onto PoolAllocator
  4. refactor: S11.09 migrate FatFsFile onto PoolAllocator
  5. refactor: S11.09 migrate TlsStream onto PoolAllocator
  6. docs: update DEVLOG for S11.09

Squash-merge title: feat: S11.09 AtomicCounter family + TLS + FatFs onto PoolAllocator.

Per-class scope

For each of the four classes, the migration commit lands:

  1. SolidSyslog<Class>.c — vtable + _Initialise(base, ...) + _Cleanup(base).
  2. SolidSyslog<Class>Private.h — TU-internal struct + private signatures.
  3. SolidSyslog<Class>Static.c — pool + Create/Destroy/IndexFromHandle/CleanupAtIndex.
  4. Public header — delete <Class>Storage typedef and SOLIDSYSLOG_*_SIZE
    enum; drop the storage parameter from _Create (TlsStream keeps its config
    parameter).
  5. Tunable in Core/Interface/SolidSyslogTunablesDefaults.h.
  6. Error messages in Core/Source/SolidSyslogErrorMessages.h.
  7. CMakeLists entries for the new *Static.c TU
    (Platform/<sub>/CMakeLists.txt for PRIVATE; Bdd/Targets/FreeRtos/CMakeLists.txt
    and Tests/FatFs/CMakeLists.txt for FatFs INTERFACE consumers).
  8. Existing test file — drop <*>Storage locals; switch to handle-based teardown.
  9. New Pool TEST_GROUP — 9 tests mirroring SolidSyslogWindowsMutexPool.
  10. AtomicCounter TestHelper include-path update for *Private.h (both Std and Windows).
  11. CLAUDE.md audience-table row updated.
  12. Caller updates in BDD targets:
    • Bdd/Targets/Linux/main.c — drop counterStorage
    • Bdd/Targets/Windows/BddTargetWindows.c — drop counterStorage
    • Bdd/Targets/FreeRtos/main.c — drop atomicCounterStorage + storeFileStorage
    • Bdd/Targets/Common/BddTargetTlsSender_OpenSsl_{Posix,Winsock}Tcp.c — drop tlsStreamStorage
    • Tests/OpenSslIntegration/SolidSyslogTlsStreamIntegrationTest.cpp — drop tlsStreamStorage{}

Public API changes

/* Before */
struct SolidSyslogAtomicCounter* SolidSyslogStdAtomicCounter_Create(SolidSyslogStdAtomicCounterStorage*);
struct SolidSyslogAtomicCounter* SolidSyslogWindowsAtomicCounter_Create(SolidSyslogWindowsAtomicCounterStorage*);
struct SolidSyslogFile*          SolidSyslogFatFsFile_Create(SolidSyslogFatFsFileStorage*);
struct SolidSyslogStream*        SolidSyslogTlsStream_Create(SolidSyslogTlsStreamStorage*, const struct SolidSyslogTlsStreamConfig*);

/* After */
struct SolidSyslogAtomicCounter* SolidSyslogStdAtomicCounter_Create(void);
struct SolidSyslogAtomicCounter* SolidSyslogWindowsAtomicCounter_Create(void);
struct SolidSyslogFile*          SolidSyslogFatFsFile_Create(void);
struct SolidSyslogStream*        SolidSyslogTlsStream_Create(const struct SolidSyslogTlsStreamConfig*);

/* New */
struct SolidSyslogAtomicCounter* SolidSyslogNullAtomicCounter_Get(void);

<Class>Storage typedefs and SOLIDSYSLOG_*_SIZE enums deleted from public headers.

Acceptance criteria

  1. All four target classes migrated onto SolidSyslogPoolAllocator. Per-class
    *Static.c lands at ≤ ~72 lines mirroring the S11.07 / S11.08 baseline.
  2. Public SolidSyslog{Std,Windows}AtomicCounterStorage, SolidSyslogTlsStreamStorage,
    SolidSyslogFatFsFileStorage types and their SOLIDSYSLOG_*_SIZE enums gone from
    Platform/Atomics/Interface/, Platform/Windows/Interface/,
    Platform/OpenSsl/Interface/, Platform/FatFs/Interface/.
  3. SolidSyslogNullAtomicCounter lands as a new public class
    (Core/Interface/SolidSyslogNullAtomicCounter.h +
    Core/Source/SolidSyslogNullAtomicCounter.c); Increment returns 1U.
  4. Per-class Pool TEST_GROUP — 9 tests mirroring SolidSyslogWindowsMutexPool.
  5. All previously existing tests continue to pass — including the AtomicCounter
    wraparound test that uses the whitebox _Init helper.
  6. TlsStream handshake/retry/SNI/cipher/cert semantics preserved verbatim; the
    migration is refactor-only.
  7. FatFsFile's f_open/f_close/f_read/f_write/f_sync-after-write semantics
    preserved verbatim.
  8. All host gates green from gcc devcontainer: debug, sanitize, coverage, tidy,
    cppcheck, clang-format. Clang-debug, IWYU run via the clang container.
  9. cppcheck-misra produces no new findings vs main. Per-class storage-cast
    deviations evaporate for all four classes — record which in DEVLOG per
    feedback_cppcheck_misra_invariant.
  10. Coverage at 100% line for every new and migrated file (including
    SolidSyslogNullAtomicCounter).
  11. Validation step: per migrated class, re-run the full suite at
    SOLIDSYSLOG_<CLASS>_POOL_SIZE=3 via SOLIDSYSLOG_USER_TUNABLES_FILE.
  12. Validated locally on MSVC per feedback_local_msvcWindowsAtomicCounter
    tests run under VS 2026 + vcpkg on the native box, not relying on CI alone.
  13. DEVLOG entry on the work branch BEFORE the PR per feedback_devlog_in_pr, with
    handoff notes for the MSVC validation pass.

Out of scope

  • POSIX / Windows / FreeRTOS adapter sweeps — S11.06 / S11.07 / S11.08 (done).
  • SolidSyslog core retrofit — S11.10.
  • Wholesale MISRA storage-cast deviation removal (the per-class deviation rows
    evaporate naturally here; the broader D.002 cleanup is S11.11).
  • mbedTLS-based TLS stream — S08.07 (S08.07: TLS via mbedTLS on FreeRTOS #272), not yet implemented.
  • SOLIDSYSLOG_FATFS_FILE_SIZE override mechanism for FF_MAX_SS > 512
    (planned S21.03 follow-up — becomes simpler post-S11.09 since the size leaves the
    public surface).

Memory pointers for the next session

  • CLAUDE.md + SKILL.md.
  • MEMORY.md, especially:
    • project_e11_static_pool_design
    • project_e11_three_tu_split
    • project_pool_allocator_helper
    • project_configlock_injection
    • feedback_storage_pattern — obsoleted per class as each migrates
    • feedback_bad_setup_contract — fallback severity vocabulary
    • feedback_discuss_production_changes
    • feedback_tdd_and_review_style
    • feedback_no_premature_generalisation
    • feedback_cppcheck_misra_invariant
    • feedback_devlog_in_pr
    • feedback_pr_template
    • feedback_no_git_commit_dash_s
    • feedback_no_merge
    • feedback_local_msvc — validate MSVC locally before pushing
    • feedback_iwyu_local_invocation
    • project_header_configured_platforms — FatFs INTERFACE shape constraint
  • E11 epic body (E11: Static-Allocation Variant #29).
  • S11.06 / S11.07 / S11.08 DEVLOG entries (POSIX + Windows + FreeRTOS precedents).

Open questions for the next session

  • SolidSyslogNullAtomicCounter_Get return type — return the base
    (struct SolidSyslogAtomicCounter*) or a Self type? S11.06 nulls return the base
    (SolidSyslogNullStream_Get returns SolidSyslogStream*), so follow that for
    consistency. Confirm at first commit.
  • TlsStream Config defensive-copy — Create captures *config by value into the
    slot. The integrator's SolidSyslogTlsStreamConfig lifetime requirement (must
    outlive the slot until _Destroy?) is unchanged from main since the struct is
    copied into the slot. Verify the contract on the public header comment matches.
  • Whether to fold S11.10 (SolidSyslog core retrofit) into this PR — small in
    scope (pool size 1 fixed, no tunable), shares the same review surface. Default:
    keep separate per epic plan; reconsider if S11.09 lands light.

Metadata

Metadata

Assignees

No one assigned

    Labels

    storyStory issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions