- Zig 96.2%
- Shell 3.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
sift landed it today, so no copy survives outside this package -- which was the point. Snapshot(T) is still comb-only, pending publish-by-swap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
| scripts | ||
| src | ||
| .devkit.conf | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| DESIGN.md | ||
| LICENSE | ||
| README.md | ||
handoff
Worker threads produce results; one consumer thread reads them. This is the bit in between. Zig 0.16, no dependencies.
Extracted from comb, shared with sift. Design notes in DESIGN.md.
sync
Zig 0.16 moved std.Thread.Mutex and Condition behind the std.Io vtable, so
taking a lock means threading an Io through every call site. For a library
that spawns its own OS threads that is pure friction. sync binds libc pthread
directly.
Mutex:lock,unlock,deinitCondition:wait(mutex),signal,broadcast,deinit
Snapshot(T)
A published result set with a version counter. Producers append under a lock and
bump the generation; the consumer calls tick(), which refreshes a private copy
only if the generation moved, then reads it unlocked via items().
So you can poll as often as you like, copy only when something actually changed, and never iterate results while holding the producers' lock.
Producer side: append, appendSlice, replace, clear, setRunning.
Consumer side: tick, items, isRunning, count.
Beyond that:
- If
Thascloneanddeinit, the snapshot owns its items: they are cloned in, each buffer into its own arena, so a round frees in one reset and the two buffers can never dangle each other. Without those declsTis copied by value and the arena code compiles away. beginRound()empties the published set without bumping the generation, so the consumer holds the previous view instead of flashing empty for a frame between rounds. The next publish exposes the change.tailInto(from, out)drains incrementally, for consumers that stream results out rather than re-clone the whole view every frame.
Not included: the worker pool, and job scheduling or coalescing. Those differ per engine.
Use
const handoff = @import("handoff");
var snap: handoff.Snapshot(Result) = .{};
defer snap.deinit(allocator);
// worker threads
try snap.append(allocator, result);
// consumer thread
const status = try snap.tick(allocator);
if (status.changed) render(snap.items());
zig build test runs the suite. Needs libc (pthread); the module sets
link_libc itself.
MIT.