One mutex mistake can freeze an entire trading engine. Here is how Kestrel's EventBus drain avoids it.
Introduction
One Line Freezes Everything
Your event bus can freeze forever, and the bug is one innocent line.
- Event bus
- Mutex
- Freeze
Handler Under a Lock
Here is the trap. A handler runs while the bus holds its lock.
- Lock still held
- Handler runs
Waiting on Yourself
The handler posts a new event. That needs the same lock. It waits on itself, forever.
- post needs the lock
- Circular wait
Lock, Then Swap
Kestrel's drain does it differently. Close the lock. Swap the entire queue into a local deque.
- Lock closes
- batch.swap(queue_)
Release Before Dispatch
Now open the lock. The shared queue is empty, and nobody is waiting.
- Lock opens
- Queue now empty
Handlers Fire Freely
Only then do handlers fire, one event at a time, from the private batch.
- Dispatch from batch
- Lock is open
Drain Loops Until Empty
If a handler posts, it simply locks, pushes, and leaves. Drain loops until the queue is truly empty.
- Post is safe
- Loop until empty
Nesting Throws Loudly
One more guard. A dispatching flag throws, EventBus drain re-entered, if anyone nests a drain.
- dispatching_ flag
- Throws on re-entry
Swap, Release, Dispatch
Never call a handler under a lock. Follow for more Kestrel internals.
- Lock
- Swap
- Release
- Dispatch