libTSClient Design#
Overview#
libTSClient is the shared memory IPC library that connects the TimeSlave process to the TimeDaemon process. It provides a lock-free, single-writer/multi-reader communication channel using a seqlock protocol over POSIX shared memory.
The library is intentionally minimal — it consists of three headers and two source files — to keep the IPC boundary simple, auditable, and suitable for safety-critical deployments.
Architecture#
Components#
GptpIpcChannel#
Defines the shared memory layout as the GptpIpcRegion structure:
Field |
Type |
Purpose |
|---|---|---|
|
|
Validation constant ( |
|
|
Seqlock counter. Odd values indicate a write in progress; even values indicate a consistent state. |
|
|
The actual time synchronization payload (PTP status, Sync/FollowUp data, peer delay data, local clock reference). |
The structure is aligned to 64 bytes (cache line size) to prevent false sharing between the writer and reader processes.
The default POSIX shared memory name is /gptp_ptp_info (defined as kGptpIpcName).
GptpIpcPublisher#
The single-writer component, used by TimeSlave:
Init(name)— Creates the POSIX shared memory segment viashm_open(O_CREAT | O_RDWR), sizes it withftruncate(), maps it withmmap(PROT_READ | PROT_WRITE), and writes the magic number.Publish(info)— Writes aPtpTimeInfousing the seqlock protocol:Increment
seq(becomes odd — signals write in progress)memcpythe dataIncrement
seq(becomes even — signals write complete)
Destroy()— Unmaps and unlinks the shared memory segment.
GptpIpcReceiver#
The multi-reader component, used by the TimeDaemon (via RealPTPEngine):
Init(name)— Opens the existing shared memory segment viashm_open(O_RDONLY)and maps it withmmap(PROT_READ). Validates the magic number.Receive()— ReadsPtpTimeInfousing the seqlock protocol with up to 20 retries:Read
seq(must be even, otherwise retry)memcpythe dataRead
seqagain (must match step 1, otherwise retry — torn read detected)Return
std::optional<PtpTimeInfo>(empty if all retries exhausted)
Close()— Unmaps the shared memory.
Seqlock protocol#
The seqlock provides the following properties:
Lock-free for readers — Readers never block the writer. A torn read is detected and retried transparently.
Single writer — Only one process (TimeSlave) writes to the shared memory. No writer-writer contention.
Bounded retry — The receiver retries up to 20 times. Under normal operation, retries are rare because the write is a single
memcpyof a small struct.Cache-line alignment — The 64-byte alignment of
GptpIpcRegionprevents false sharing, which is critical for cross-process shared memory performance.
Data type#
The PtpTimeInfo structure (defined in score/TimeDaemon/code/common/data_types/ptp_time_info.h)
is the payload transferred through the IPC channel. It contains:
Field |
Content |
|---|---|
|
Synchronization flags (synchronized, timeout, time leap indicators) |
|
Sync and FollowUp message timestamps and correction fields |
|
Peer delay measurement results |
Local clock value |
Reference timestamp from |
Build integration#
The library is built as a Bazel cc_library target:
//score/libTSClient:gptp_ipc
It links against -lrt for POSIX shared memory (shm_open, shm_unlink) and
depends on the PtpTimeInfo data type from the TimeDaemon common module.
Both TimeSlave and TimeDaemon link against libTSClient — the publisher side in
TimeSlave, the receiver side in TimeDaemon.