- spawn placement: round-robin across shards (same-shard when the engine is absent/single); the actor's mailbox and delivery belong to its HOME thread — a spawn to another shard travels as an ADOPT envelope, a send as a SEND envelope (mutex-guarded inbox + eventfd wake; the spec's lock-free rings stay a disclosed deviation until 9e measures the mutex) - workers: first envelope triggers lazy full-vm init UNDER the inbox mutex (TSan caught the memset racing a concurrent push, twice — the second was inbox_push reading wake_efd outside the lock; both fixed, gate x8 + battery clean); serve loop = adopt -> run to drained -> wait on the plane (the wake eventfd is watched by io_uring POLL_ADD oneshot / epoll level-triggered on BOTH backends) - ownership across heaps: every allocation stamps rt->shard_id into the header (the field reserved since iteration 2); a drop on the wrong shard routes home as a FREE envelope — the owner's arena stays single-threaded by construction; at teardown routed frees become no-ops (arenas die wholesale) which is what un-danced the freed-mutex ASan SEGV the first ordering had - WO-E222: an actor's state or message type that is (or transitively contains) an inferred-traced class refuses at the spawn/send — with round-robin every actor is potentially remote; corpus-pinned (compile-fail/traced-send, inference-aware: Box contains ?Node) - determinism narrowed per spec: oop-e2e pins WO_SHARDS=1 (exact outputs); the fibers gate grows multi-shard SET assertions + a TSan run (wovm-tsan target; setarch -R fallback for kernel 6.5+ ASLR) - NEXT_RUNNABLE honors engine shutdown for parked workers (deadlock hole closed); io_wait's adopt-wake (rc 1) no longer reads as fatal - battery: oop-e2e 93/0, fibers 10/0 x8 (+WO_IO=epoll), log-watcher 7/0, employee 8/0, web-app 21/0, deps 8/0, runtime tests 16/16 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
88 lines
2.3 KiB
C
88 lines
2.3 KiB
C
#include "cont.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
wo_multi *wo_multi_new(wo_rt *rt, uint8_t elem_kind) {
|
|
wo_multi *m = wo_arena_alloc(&rt->arena, sizeof(wo_multi));
|
|
if (!m) return NULL;
|
|
memset(m, 0, sizeof(*m));
|
|
m->h.class_id = WO_CLS_MULTI;
|
|
m->h.shard_id = rt->shard_id;
|
|
m->elem_kind = elem_kind;
|
|
return m;
|
|
}
|
|
|
|
int wo_multi_push(wo_multi *m, uint64_t v) {
|
|
if (m->len == m->cap) {
|
|
uint32_t ncap = m->cap ? m->cap * 2 : 8;
|
|
uint64_t *ni = realloc(m->items, (size_t)ncap * sizeof(uint64_t));
|
|
if (!ni) return -1;
|
|
m->items = ni;
|
|
m->cap = ncap;
|
|
}
|
|
m->items[m->len++] = v;
|
|
return 0;
|
|
}
|
|
|
|
int wo_multi_get(const wo_multi *m, uint64_t idx, uint64_t *out) {
|
|
if (idx >= m->len) return -1;
|
|
*out = m->items[idx];
|
|
return 0;
|
|
}
|
|
|
|
wo_map *wo_map_new(wo_rt *rt, uint8_t key_kind, uint8_t val_kind) {
|
|
wo_map *m = wo_arena_alloc(&rt->arena, sizeof(wo_map));
|
|
if (!m) return NULL;
|
|
memset(m, 0, sizeof(*m));
|
|
m->h.class_id = WO_CLS_MAP;
|
|
m->h.shard_id = rt->shard_id;
|
|
m->key_kind = key_kind;
|
|
m->val_kind = val_kind;
|
|
return m;
|
|
}
|
|
|
|
static int key_eq(const wo_map *m, uint64_t a, uint64_t b) {
|
|
if (m->key_kind == WO_K_TEXT)
|
|
return wo_str_eq((const wo_str *)(uintptr_t)a,
|
|
(const wo_str *)(uintptr_t)b);
|
|
return a == b;
|
|
}
|
|
|
|
static int map_find(const wo_map *m, uint64_t k) {
|
|
for (uint32_t i = 0; i < m->len; i++)
|
|
if (key_eq(m, m->keys[i], k)) return (int)i;
|
|
return -1;
|
|
}
|
|
|
|
int wo_map_set(wo_map *m, uint64_t k, uint64_t v, uint64_t *old) {
|
|
int i = map_find(m, k);
|
|
if (i >= 0) {
|
|
*old = m->vals[i];
|
|
m->vals[i] = v;
|
|
return 1;
|
|
}
|
|
if (m->len == m->cap) {
|
|
uint32_t ncap = m->cap ? m->cap * 2 : 8;
|
|
uint64_t *nk = realloc(m->keys, (size_t)ncap * sizeof(uint64_t));
|
|
if (!nk) return -1;
|
|
m->keys = nk;
|
|
uint64_t *nv = realloc(m->vals, (size_t)ncap * sizeof(uint64_t));
|
|
if (!nv) return -1;
|
|
m->vals = nv;
|
|
m->cap = ncap;
|
|
}
|
|
m->keys[m->len] = k;
|
|
m->vals[m->len] = v;
|
|
m->len++;
|
|
return 0;
|
|
}
|
|
|
|
int wo_map_get(const wo_map *m, uint64_t k, uint64_t *out) {
|
|
int i = map_find(m, k);
|
|
if (i < 0) return -1;
|
|
*out = m->vals[i];
|
|
return 0;
|
|
}
|
|
|
|
int wo_map_has(const wo_map *m, uint64_t k) { return map_find(m, k) >= 0; }
|