Tina: A Thread-per-Core, Zero-Allocation Concurrency Framework

Hi everyone,

Over the past few months, I’ve been building a concurrency framework in Odin called Tina.

My goal was to combine the fault-tolerance model of Erlang/OTP with the mechanical sympathy of Seastar (and a few ideas from reading the works of the folks at TigerBeetle).

Odin’s data-oriented design philosophy made me decide to implement my design in Odin, although my initial plan was to do it in Zig. I am sharing it here to get your feedback and any architectural critique.

The Core Architecture

Tina is a strictly bounded, shared-nothing concurrency framework. It operates on a few absolute constraints:

  1. Thread-per-Core (Shards): Tina does not use work-stealing. Each OS thread (a “Shard”) is pinned to a core and runs its own cooperative scheduler.
  2. Isolates & Effects: You do not write callbacks, promise, or async/await. You write “Isolates” (state machines, like Erlang processes) that react to messages and return Effect values (e.g., .receive, .io, .call, .reply). The framework interprets the Effect and handles the scheduling/dispatching.
  3. Static Allocation: Tina performs zero dynamic allocations after boot. At startup, each Shard allocates a single “Grand Arena.” All mailboxes, I/O buffers, and typed arenas for the Isolates are carved out of this. If a mailbox fills up, ctx.send() returns .mailbox_full. The system sheds load rather than OOM-crashing.

100% Deterministic Simulation Testing (DST)

Because Tina abstracts the clock, network, and I/O backend (io_uring/kqueue/IOCP), the entire framework can run in a single-threaded simulation loop. Same seed + Same boot spec = Same execution order. You can inject network partitions, dropped messages, and simulated disk latency to find race conditions instantly, and reproduce them perfectly. This also works nicely with Odin’s test package, because you can use t.Seed and get your test replayable.

I published some docs today which should *hopefully make it easy to understand why certain things are designed the way they are, and how to explore them and build various programs (e.g. network proxy, http libraries…). There are examples on non-blocking TCP server and client, guides on non-blocking I/O.

I would highly value any code review, specifically regarding the memory allocation boundaries and the sigaltstack trap boundary used for Tier 2 fault containment.

2 Likes