add channels to El — buffered MPMC channel with send/recv/close
Introduces Go-style channels as El's mid-flight communication primitive, completing the threading model: threads can now not only spawn/join but also communicate while running. Part 1 — seed layer (el_runtime.c / el_runtime.h): - Add __thread_create/__thread_join/__mutex_new/__mutex_lock/__mutex_unlock as C seed primitives (dlsym-based thread dispatch, pthread mutex table) - Add __channel_new/__channel_send/__channel_recv/__channel_try_recv/__channel_close as MPMC channel seed primitives backed by mutex + condvar + circular buffer - Bounded channels (cap > 0): circular buffer, sender blocks when full - Unbounded channels (cap == 0): dynamic array, grows on demand, never blocks - channel_close wakes all blocked recvers/senders; recv drains then returns "" Part 2 — El API (runtime/channel.el): - channel_new/send/recv/try_recv/close — thin wrappers over seed layer - channel_pipeline — spawn N worker threads reading from in_ch, applying fn_name, writing to out_ch; workers exit on "" sentinel from close - channel_drain — collect all messages from a closed channel into [String] - channel_fan_out — send a [String] list into a channel then close it Part 3 — codegen.el: - Register all 10 seed builtins (__thread_* + __channel_*) in builtin_arity so the arity checker validates call sites at compile time
This commit is contained in:
@@ -749,6 +749,39 @@ el_val_t trace_span_start(el_val_t name);
|
||||
el_val_t trace_span_end(el_val_t span_handle);
|
||||
el_val_t emit_event(el_val_t name, el_val_t duration_ms);
|
||||
|
||||
/* ── Threading seed primitives ────────────────────────────────────────────────
|
||||
* These are the low-level C primitives that back thread.el and channel.el.
|
||||
* El programs call them via their El wrappers (spawn, join, __mutex_new, etc.)
|
||||
* rather than directly.
|
||||
*
|
||||
* __thread_create(fn_name, arg) — dlsym-resolves fn_name, spawns pthread,
|
||||
* returns a slot index (Int) usable with __thread_join.
|
||||
* __thread_join(tid) — joins the thread, returns its String result.
|
||||
* __mutex_new() — allocates a mutex, returns handle (Int).
|
||||
* __mutex_lock(m) — locks mutex m (blocks until available).
|
||||
* __mutex_unlock(m) — unlocks mutex m. */
|
||||
|
||||
el_val_t __thread_create(el_val_t fn_name, el_val_t arg);
|
||||
el_val_t __thread_join(el_val_t tid);
|
||||
el_val_t __mutex_new(void);
|
||||
void __mutex_lock(el_val_t m);
|
||||
void __mutex_unlock(el_val_t m);
|
||||
|
||||
/* ── Channel seed primitives ─────────────────────────────────────────────────
|
||||
* Buffered MPMC channels. All values are Strings; handles are Ints.
|
||||
*
|
||||
* __channel_new(capacity) — create channel; cap=0 means unbounded.
|
||||
* __channel_send(ch, msg) — push msg; blocks if bounded and full.
|
||||
* __channel_recv(ch) — pop msg; blocks until available; "" on closed+empty.
|
||||
* __channel_try_recv(ch) — non-blocking pop; "" if empty.
|
||||
* __channel_close(ch) — mark closed; wakes all blocked recvers/senders. */
|
||||
|
||||
el_val_t __channel_new(el_val_t capacity);
|
||||
void __channel_send(el_val_t ch, el_val_t msg);
|
||||
el_val_t __channel_recv(el_val_t ch);
|
||||
el_val_t __channel_try_recv(el_val_t ch);
|
||||
void __channel_close(el_val_t ch);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user