Files
secs-gem/tests
raphael 9653a54584 docs+test: thread-safety contract for EquipmentDataModel
INTEGRATION.md §3 used to show a sensor-poll thread calling
model->svids.set_value() directly while the io_context thread reads
the same SVID for an inbound S1F3.  That's a data race — there are
zero locks anywhere in EquipmentDataModel and there's no intention
to add them.  The library is single-threaded by design; the doc was
just inviting trouble.

This commit makes the actual contract explicit:

- INTEGRATION.md §3: thread-safety callout box.  All access must run
  on the io_context that drives the HSMS connection.  Sensor updates
  from other threads marshal via asio::post(io.get_executor(), ...).
  Same applies to set_*_change_handler callbacks (they fire on the
  io_context thread; observers must be thread-safe or hand work off).

- README.md §3 (Monitoring & observability): added a paragraph noting
  that hooks fire on the io_context thread, blocking I/O inside a
  handler stalls the dispatcher, and metrics exporters must respect
  the same contract.

- tests/test_thread_safety.cpp: two scenarios that exercise the
  canonical pattern — N producer threads asio::post sensor updates
  onto a worker-driven io_context; reads marshal back through the
  io.  Catches obvious regressions (e.g. someone adding a
  "convenience" cross-thread mutator that bypasses the strand).

A passing run isn't proof of race-freedom under ThreadSanitizer —
it pins down the *pattern* customers should follow.  TSan integration
is a separate workstream.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 14:11:28 +02:00
..
2026-06-08 08:41:09 +02:00