Skip to content

Phase 2: Convert all 12 remaining modules to decision struct pattern#5

Merged
avrabe merged 16 commits intomainfrom
worktree-full-kernel-replacement
Mar 21, 2026
Merged

Phase 2: Convert all 12 remaining modules to decision struct pattern#5
avrabe merged 16 commits intomainfrom
worktree-full-kernel-replacement

Conversation

@avrabe
Copy link
Contributor

@avrabe avrabe commented Mar 20, 2026

Summary

Converts all 12 remaining wired kernel modules from arithmetic-oracle to Extract→Decide→Apply decision struct pattern. Combined with Phase 1 (sem, PR #4), this completes all 13 wired modules.

Modules Converted

Module Structs Commit
stack GaleStackPush/PopDecision e35df30
fifo/lifo GaleFifo/LifoPut/GetDecision 9e94f65
mem_slab GaleMemSlabAlloc/FreeDecision 9f38dbe
timer GaleTimerExpire/StatusDecision 7f713eb
event GaleEventPost/WaitDecision 675e9da
queue GaleQueueInsert/GetDecision ed15b80
mbox GaleMboxPut/GetDecision 05e8dfc
timeout GaleTimeoutAdd/Abort/AnnounceDecision b902af9
msgq GaleMsgqPut/GetDecision 5056aec
mutex GaleMutexLock/UnlockDecision 69fee98

Test plan

  • cargo test — 66 test suites, 0 failures
  • cargo build --manifest-path ffi/Cargo.toml — compiles
  • CI: All 25 checks pass

🤖 Generated with Claude Code

avrabe and others added 16 commits March 20, 2026 06:01
Rewrite k_mem_slab_alloc and k_mem_slab_free in the C shim to use the
Extract/Decide/Apply pattern with Rust decision structs, matching the
semaphore PoC. Rust now decides the action (ALLOC_OK/PEND/NOMEM and
FREE_OK/WAKE_THREAD); C extracts kernel state, calls Rust, and applies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace direct gale_stack_push_validate/pop_validate calls with the
Extract→Decide→Apply pattern using GaleStackPushDecision and
GaleStackPopDecision structs.

Push: C peeks at wait queue head (no side effect), passes count/capacity/
has_waiter to Rust. Rust returns STORE_DATA, WAKE_WAITER, or FULL.
C applies: unpend+wake, store+advance, or reject with -ENOMEM.

Pop: C passes count and is_no_wait to Rust. Rust returns POP_OK (with
ret=0 for data or ret=-EBUSY for empty+no_wait) or PEND_CURRENT.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add GaleFifoPutDecision, GaleFifoGetDecision, GaleLifoPutDecision, and
GaleLifoGetDecision structs following the proven Extract-Decide-Apply
pattern from semaphore. Rust decides whether to wake a waiter or insert
data (put) and whether to dequeue, pend, or return empty (get).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace pointer-based gale_timer_expire/gale_timer_status_get with
Extract-Decide-Apply decision structs (GaleTimerExpireDecision,
GaleTimerStatusDecision). C extracts timer->status and timer->period,
Rust returns a decision struct with the new status value, C applies it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite gale_event.c to use Extract-Decide-Apply with Rust decision
structs. k_event_post_internal uses GaleEventPostDecision for masked
bitmask computation, k_event_wait_internal and event_walk_op use
GaleEventWaitDecision for ANY/ALL condition checks and pend/timeout
decisions. Removes are_wait_conditions_met helper in favor of the
unified decision struct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite queue_insert and z_impl_k_queue_get in gale_queue.c to use
the Extract→Decide→Apply pattern with Rust decision structs.

C extracts kernel state (wait queue, list emptiness), Rust decides the
action (WAKE vs INSERT, DEQUEUE vs RETURN_NULL vs PEND), C applies it.
Data movement (linked list insertion, alloc nodes) stays in C.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite mbox_message_put and k_mbox_get in gale_mbox.c to use
the Extract→Decide→Apply pattern with Rust decision structs.

C extracts kernel state (rx/tx queue scan, message matching), Rust
decides the post-scan action (MATCHED vs RETURN_ENOMSG vs PEND),
C applies it. Data movement (message copy, async descriptors) stays
in C.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace raw pointer output params in gale_timeout_add/abort/announce
with decision structs (GaleTimeoutAddDecision, GaleTimeoutAbortDecision,
GaleTimeoutAnnounceDecision) following the Extract->Decide->Apply pattern.
Legacy pointer-based API retained as thin wrappers for backward compat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite z_impl_k_msgq_put and z_impl_k_msgq_get to use the
Extract-Decide-Apply pattern: C extracts kernel state (spinlock,
wait queue side effects), Rust decides the action via decision
structs, C applies the result.

- GaleMsgqPutDecision: PUT_OK / WAKE_READER / PEND_CURRENT / RETURN_FULL
- GaleMsgqGetDecision: GET_OK / WAKE_WRITER / PEND_CURRENT / RETURN_EMPTY
- put_front stays with Phase 1 API (always K_NO_WAIT, no decision needed)
- Data copy (memcpy) remains in C; Rust decides index/count updates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rust decides the lock/unlock action via GaleMutexLockDecision and
GaleMutexUnlockDecision structs; C applies the decision including
priority inheritance adjustments. Overflow protection preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ar, futex, poll)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pipe, queue, mbox, fifo, lifo)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tructure modules

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ENOMSG, ETIMEDOUT, ECANCELED, EOVERFLOW, and EADDRINUSE used Linux
values instead of Zephyr's. This caused msgq boundary tests to fail:
Rust returned -42 (Linux ENOMSG) but Zephyr tests expect -35.

Fixed all five mismatched constants in both src/error.rs and
plain/src/error.rs to match zephyr/lib/libc/minimal/include/errno.h.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After a reader wakes from a direct copy by a writer, buf.used may
already satisfy the request. The decision struct conversion moved
the buf.used == len check inside the READ_OK/WAKE_WRITER branches,
so when the loop re-entered and Rust returned READ_PEND (because the
ring buffer was empty), the reader hung forever despite having all
its data.

Add buf.used >= len guard at the top of the for(;;) loop, matching
the unconditional check in upstream Zephyr's k_pipe_read. This also
fixes the semaphore test_sem_multi_take_timeout_diff_sem hang, which
used a pipe for inter-thread result reporting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gale_k_pipe_read_decide had a guard (size > 0) that prevented
WAKE_WRITER from ever being returned for zero-size pipes. Upstream
Zephyr wakes writers unconditionally when pipe_full() (space == 0),
which is always true for zero-size pipes. Without this wake, the
reader pends and no writer ever runs copy_to_pending_readers.

Remove the size > 0 guard so the condition becomes used >= size,
which for zero-size pipes is 0 >= 0 = true. This lets writers
copy data directly to readers via the swap_data mechanism.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@avrabe avrabe merged commit e404c7e into main Mar 21, 2026
25 checks passed
@avrabe avrabe deleted the worktree-full-kernel-replacement branch March 21, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant