Skip to content

S12.15: Service thread idle yield #277

Description

@DavidCozens

Problem

Example/Common/ExampleServiceThread.c busy-spins:

while (!(*shutdown))
{
    SolidSyslog_Service();
}

When the buffer is empty and the store has no unsent records, _Service returns instantly and the loop hammers the CPU at 100%. On Windows, this also contends with the producer for the buffer mutex on every iteration.

Discovered alongside #275 / S12.14 architecture work — orthogonal but worth fixing for production realism of the example code.

Scope

  • ExampleServiceThread_Run takes an injected SolidSyslogSleepFunction and sleeps 1 ms unconditionally after every SolidSyslog_Service() call.
  • The SolidSyslogSleepFunction typedef and the POSIX/Windows wirings (SolidSyslogPosixSleep, SolidSyslogWindowsSleep) already exist for the TLS handshake retry — reuse them, no #ifdef needed.
  • SolidSyslog_Service itself stays void — the library makes no attempt here to signal idle state. That is deliberately deferred (see Future work below).
  • Cost: a 1 ms latency cap on every tick. Well below RFC 5424 timestamp precision.
  • Benefit: CPU usage drops from 100% to <1% when idle; producer lock contention disappears under load.

Test impact

  • Update ExampleServiceThreadTest to inject a counting SleepFake that flips the shutdown flag after the first call — proves the sleep was invoked once per tick at the expected millisecond count.
  • No core library tests change; the public API is unchanged.

Future work (out of scope for this story)

A later story can investigate signalling — making the service thread block until either a buffer write or a shutdown signal occurs, eliminating the 1 ms polling tick entirely. That would need cross-platform primitives (eventfd / SetEvent / RTOS task notifications) plumbed through the buffer abstraction and is a larger design effort. Keeping this story to a simple unconditional yield avoids committing to a particular signalling design now.

Notes

  • Independent of S12.12 and S12.14.
  • Library API surface is unchanged — this story lives entirely in Example/Common/ and the per-platform mains.

Parent epic: #31

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