Skip to content

feat(loop): add EventLoopService (dispatcher drain + timer wheel)#30

Merged
tgiachi merged 2 commits into
developfrom
feature/eventloop
Jul 2, 2026
Merged

feat(loop): add EventLoopService (dispatcher drain + timer wheel)#30
tgiachi merged 2 commits into
developfrom
feature/eventloop

Conversation

@tgiachi

@tgiachi tgiachi commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

Ports Moongate's GameLoopService into SquidStd as a general-purpose EventLoopService: a dedicated background thread (SquidStd-EventLoop) that each frame drains the IMainThreadDispatcher and advances the timer wheel (ITimerService.UpdateTicksDelta), idle-sleeps when a tick produced no work, exposes tick metrics via IMetricProvider, and warns on slow ticks.

Opt-in via RegisterEventLoop() and mutually exclusive with TimerWheelPumpService — both advance the timer wheel, so a shared ITimerWheelDriver marker makes the exclusivity structural.

Changes

  • New abstractions (SquidStd.Core): IEventLoopService (pure — Core doesn't reference Abstractions), ITimerWheelDriver marker, EventLoopConfig (IdleCpuEnabled/IdleSleepMs/SlowTickThresholdMs).
  • EventLoopService (SquidStd.Services.Core): implements IEventLoopService, ISquidStdService, IMetricProvider, ITimerWheelDriver, IDisposable; internal Tick() extracted for deterministic tests.
  • RegisterEventLoop(): fail-fast if a timer-wheel driver is already registered; maps the loop to ITimerWheelDriver and IMetricProvider.
  • Mutual exclusivity: TimerWheelPumpService now implements ITimerWheelDriver; the three pump registration sites map the marker, and the WorkerManager/Mail guards switched from IsRegistered<TimerWheelPumpService>() to IsRegistered<ITimerWheelDriver>() — so registering the event loop suppresses the pump auto-registration (no double wheel advance).

Test Plan

  • Tick() drains dispatcher, advances the timer wheel, returns work; idle path; metrics prefix eventloop; start/stop thread executes posted work (5 tests)
  • Registration: fail-fast after pump, driver+metric-provider mapping, both types implement the marker (4 tests)
  • Verified empirically: the mapped IMetricProvider appears in the IEnumerable<IMetricProvider> collection and is the SAME singleton; mutual exclusivity holds both directions
  • Full suite 999/999; build 0 errors, 0 new warnings

var dispatcher = new MainThreadDispatcherService();
var timer = new FakeTimerService();
using var loop = new EventLoopService(dispatcher, timer, new EventLoopConfig());
var signal = new ManualResetEventSlim(false);
@tgiachi
tgiachi merged commit f37b607 into develop Jul 2, 2026
3 checks passed
@tgiachi
tgiachi deleted the feature/eventloop branch July 2, 2026 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants