Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/renode-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
- name: Initialize west workspace
run: |
pip3 install west
west init -m https://github.com/zephyrproject-rtos/zephyr.git zephyr-workspace
west init -m https://github.com/pulseengine/zephyr.git --mr gale/sem-replacement zephyr-workspace
cd zephyr-workspace
west update --narrow -o=--depth=1
west sdk install
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zephyr-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
- name: Initialize west workspace
run: |
pip3 install west
west init -m https://github.com/zephyrproject-rtos/zephyr.git zephyr-workspace
west init -m https://github.com/pulseengine/zephyr.git --mr gale/sem-replacement zephyr-workspace
cd zephyr-workspace
west update --narrow -o=--depth=1
west sdk install
Expand Down
38 changes: 38 additions & 0 deletions ffi/include/gale_dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,44 @@ int32_t gale_dynamic_alloc_validate(uint32_t active,
int32_t gale_dynamic_free_validate(uint32_t active,
uint32_t *new_active);

/* ---- Phase 2: Full Decision API ---- */

struct gale_dynamic_alloc_decision {
uint8_t action; /* 0=ALLOC_OK, 1=POOL_FULL */
uint32_t new_active;
};

#define GALE_DYNAMIC_ACTION_ALLOC_OK 0
#define GALE_DYNAMIC_ACTION_POOL_FULL 1

/**
* Decide whether a dynamic pool allocation can proceed.
*
* @param active Current active stack count.
* @param max_threads Maximum threads in pool.
*
* @return Decision struct: action + new_active.
*/
struct gale_dynamic_alloc_decision gale_dynamic_alloc_decide(
uint32_t active, uint32_t max_threads);

struct gale_dynamic_free_decision {
uint8_t action; /* 0=FREE_OK, 1=UNDERFLOW */
uint32_t new_active;
};

#define GALE_DYNAMIC_ACTION_FREE_OK 0
#define GALE_DYNAMIC_ACTION_UNDERFLOW 1

/**
* Decide whether a dynamic pool free can proceed.
*
* @param active Current active stack count.
*
* @return Decision struct: action + new_active.
*/
struct gale_dynamic_free_decision gale_dynamic_free_decide(uint32_t active);

#ifdef __cplusplus
}
#endif
Expand Down
38 changes: 34 additions & 4 deletions ffi/include/gale_fatal.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
extern "C" {
#endif

/* Recovery action codes returned by gale_fatal_classify */
#define GALE_FATAL_ABORT_THREAD 0
#define GALE_FATAL_HALT 1
#define GALE_FATAL_IGNORE 2
/* Recovery action codes */
#define GALE_FATAL_ACTION_ABORT_THREAD 0
#define GALE_FATAL_ACTION_HALT 1
#define GALE_FATAL_ACTION_IGNORE 2

/* Legacy defines for backward compatibility */
#define GALE_FATAL_ABORT_THREAD GALE_FATAL_ACTION_ABORT_THREAD
#define GALE_FATAL_HALT GALE_FATAL_ACTION_HALT
#define GALE_FATAL_IGNORE GALE_FATAL_ACTION_IGNORE

/**
* Classify a fatal error: determine recovery action.
Expand All @@ -32,6 +37,31 @@ int32_t gale_fatal_classify(uint32_t reason,
uint32_t is_isr,
uint32_t test_mode);

/* ---- Phase 2: Full Decision API ---- */

struct gale_fatal_decision {
uint8_t action; /* 0=ABORT_THREAD, 1=HALT, 2=IGNORE */
int32_t ret; /* 0 on success, -EINVAL for unknown reason */
};

/**
* Full decision for fatal error classification.
*
* Returns a decision struct telling the C shim what recovery action
* to apply after k_sys_fatal_error_handler returns.
*
* @param reason Error reason code (0-4).
* @param is_isr 1 if in ISR context, 0 if in thread context.
* @param test_mode 1 if CONFIG_TEST, 0 for production.
*
* @return Decision struct: action + return code.
*
* Verified: FT1 (reason mapping), FT2 (panic halts), FT3 (recovery).
*/
struct gale_fatal_decision gale_k_fatal_decide(uint32_t reason,
uint32_t is_isr,
uint32_t test_mode);

#ifdef __cplusplus
}
#endif
Expand Down
20 changes: 20 additions & 0 deletions ffi/include/gale_futex.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ int32_t gale_futex_wake(uint32_t num_waiters,
uint32_t *woken,
uint32_t *remaining);

/* ---- Phase 2: Full Decision API ---- */

struct gale_futex_wait_decision {
uint8_t action; /* 0=BLOCK (pend on wait queue), 1=RETURN_EAGAIN */
int32_t ret; /* 0 if blocking, -EAGAIN/-ETIMEDOUT if not */
};

#define GALE_FUTEX_ACTION_BLOCK 0
#define GALE_FUTEX_ACTION_RETURN_EAGAIN 1

struct gale_futex_wait_decision gale_k_futex_wait_decide(
uint32_t val, uint32_t expected, uint32_t is_no_wait);

struct gale_futex_wake_decision {
uint32_t wake_limit; /* maximum number of threads to wake */
};

struct gale_futex_wake_decision gale_k_futex_wake_decide(
uint32_t num_waiters, uint32_t wake_all);

#ifdef __cplusplus
}
#endif
Expand Down
23 changes: 23 additions & 0 deletions ffi/include/gale_kheap.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,29 @@ int32_t gale_kheap_free_validate(uint32_t allocated_bytes,
uint32_t bytes,
uint32_t *new_allocated);

/* ---- Phase 2: Full Decision API ---- */

struct gale_kheap_alloc_decision {
uint8_t action; /* 0=RETURN_PTR, 1=PEND, 2=RETURN_NULL */
};

#define GALE_KHEAP_ACTION_RETURN_PTR 0
#define GALE_KHEAP_ACTION_PEND 1
#define GALE_KHEAP_ACTION_RETURN_NULL 2

struct gale_kheap_alloc_decision gale_k_kheap_alloc_decide(
uint32_t alloc_succeeded, uint32_t is_no_wait);

struct gale_kheap_free_decision {
uint8_t action; /* 0=FREE_ONLY, 1=FREE_AND_RESCHEDULE */
};

#define GALE_KHEAP_ACTION_FREE_ONLY 0
#define GALE_KHEAP_ACTION_FREE_AND_RESCHEDULE 1

struct gale_kheap_free_decision gale_k_kheap_free_decide(
uint32_t has_waiters);

#ifdef __cplusplus
}
#endif
Expand Down
22 changes: 22 additions & 0 deletions ffi/include/gale_mempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,28 @@ int32_t gale_mempool_alloc_validate(uint32_t allocated,
int32_t gale_mempool_free_validate(uint32_t allocated,
uint32_t *new_allocated);

/* ---- Phase 2: Full Decision API ---- */

struct gale_mempool_alloc_decision {
uint8_t action; /* 0=RETURN_PTR, 1=RETURN_NULL */
};

#define GALE_MEMPOOL_ACTION_RETURN_PTR 0
#define GALE_MEMPOOL_ACTION_RETURN_NULL 1

struct gale_mempool_alloc_decision gale_k_mempool_alloc_decide(
uint32_t alloc_succeeded);

struct gale_mempool_free_decision {
uint8_t action; /* 0=FREE_OK, 1=FREE_AND_RESCHEDULE */
};

#define GALE_MEMPOOL_ACTION_FREE_OK 0
#define GALE_MEMPOOL_ACTION_FREE_AND_RESCHEDULE 1

struct gale_mempool_free_decision gale_k_mempool_free_decide(
uint32_t has_waiters);

#ifdef __cplusplus
}
#endif
Expand Down
26 changes: 26 additions & 0 deletions ffi/include/gale_poll.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,32 @@ int32_t gale_poll_signal_raise(uint32_t *signaled,
*/
int32_t gale_poll_signal_reset(uint32_t *signaled);

/* ---- Phase 2: Full Decision API ---- */

struct gale_poll_signal_raise_decision {
uint32_t new_signaled; /* always 1 (raise sets signaled) */
int32_t new_result; /* result value to store */
uint8_t action; /* 0=NO_EVENT, 1=SIGNAL_EVENT */
};

#define GALE_POLL_ACTION_NO_EVENT 0
#define GALE_POLL_ACTION_SIGNAL_EVENT 1

/**
* Decide signal state for k_poll_signal_raise.
*
* C extracts current signaled state and whether a poll_event was dequeued
* (side effect). Rust decides the new signaled/result values and action.
*
* @param signaled Current signaled flag value.
* @param result_val Result value to store.
* @param has_poll_event 1 if a poll_event was dequeued, 0 otherwise.
*
* @return Decision struct with new_signaled, new_result, action.
*/
struct gale_poll_signal_raise_decision gale_k_poll_signal_raise_decide(
uint32_t signaled, int32_t result_val, uint32_t has_poll_event);

#ifdef __cplusplus
}
#endif
Expand Down
58 changes: 58 additions & 0 deletions ffi/include/gale_sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,64 @@ int32_t gale_sched_should_preempt(uint32_t current_is_cooperative,
uint32_t candidate_is_metairq,
uint32_t swap_ok);

/* ---- Phase 3: Sched Decision API ---- */

#define GALE_SCHED_SELECT_RUNQ 0
#define GALE_SCHED_SELECT_IDLE 1
#define GALE_SCHED_SELECT_METAIRQ_PREEMPTED 2

struct gale_sched_next_up_decision {
uint8_t action; /* 0=SELECT_RUNQ, 1=SELECT_IDLE, 2=SELECT_METAIRQ_PREEMPTED */
};

/**
* Decide which thread to run next (uniprocessor).
*
* The C shim extracts boolean flags from kernel state, Rust decides
* the scheduling policy, C applies the decision.
*
* @param has_runq_thread 1 if run queue has a best thread.
* @param runq_best_is_metairq 1 if the runq best thread is MetaIRQ.
* @param has_metairq_preempted 1 if a coop thread was preempted by MetaIRQ.
* @param metairq_preempted_is_ready 1 if the preempted thread is still ready.
*
* @return Decision struct with action field.
*/
struct gale_sched_next_up_decision gale_k_sched_next_up_decide(
uint32_t has_runq_thread,
uint32_t runq_best_is_metairq,
uint32_t has_metairq_preempted,
uint32_t metairq_preempted_is_ready);

#define GALE_SCHED_PREEMPT 1
#define GALE_SCHED_NO_PREEMPT 0

struct gale_sched_preempt_decision {
uint8_t should_preempt; /* 1=preempt, 0=no preempt */
};

/**
* Decide whether the candidate thread should preempt current.
*
* Mirrors kthread.h:should_preempt with Extract-Decide-Apply:
* 1. swap_ok (yield) -> always preempt
* 2. current prevented from running -> preempt
* 3. current preemptible OR candidate MetaIRQ -> preempt
* 4. otherwise -> no preempt (cooperative protection)
*
* @param is_cooperative 1 if current thread is cooperative.
* @param candidate_is_metairq 1 if candidate is MetaIRQ.
* @param swap_ok 1 if explicit yield allows swap.
* @param current_is_prevented 1 if current is pended/suspended/dummy.
*
* @return Decision struct with should_preempt field.
*/
struct gale_sched_preempt_decision gale_k_sched_preempt_decide(
uint32_t is_cooperative,
uint32_t candidate_is_metairq,
uint32_t swap_ok,
uint32_t current_is_prevented);

#ifdef __cplusplus
}
#endif
Expand Down
66 changes: 66 additions & 0 deletions ffi/include/gale_smp_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,72 @@ int32_t gale_smp_start_cpu_validate(uint32_t active_cpus,
int32_t gale_smp_stop_cpu_validate(uint32_t active_cpus,
uint32_t *new_active);

/* ---- Phase 2: Full Decision API ---- */

struct gale_smp_start_decision {
uint8_t action; /* 0=START_OK, 1=ALL_ACTIVE */
uint32_t new_active;
};

#define GALE_SMP_ACTION_START_OK 0
#define GALE_SMP_ACTION_ALL_ACTIVE 1

/**
* Decide whether a CPU can be started.
*
* @param active_cpus Current active CPU count.
* @param max_cpus Maximum CPUs in system.
*
* @return Decision struct: action + new_active.
*/
struct gale_smp_start_decision gale_smp_start_cpu_decide(
uint32_t active_cpus, uint32_t max_cpus);

struct gale_smp_stop_decision {
uint8_t action; /* 0=STOP_OK, 1=LAST_CPU */
uint32_t new_active;
};

#define GALE_SMP_ACTION_STOP_OK 0
#define GALE_SMP_ACTION_LAST_CPU 1

/**
* Decide whether a CPU can be stopped.
*
* @param active_cpus Current active CPU count.
*
* @return Decision struct: action + new_active.
*/
struct gale_smp_stop_decision gale_smp_stop_cpu_decide(uint32_t active_cpus);

/* ---- C-side helpers (defined in gale_smp_state.c) ---- */

/**
* Checked CPU start: validates via Rust decision, updates active count.
*
* @param id CPU id to start.
* @param max_cpus Maximum CPUs in system.
*
* @return 0 on success, -EBUSY if all CPUs already active.
*/
int gale_smp_cpu_start_checked(int id, unsigned int max_cpus);

/**
* Checked CPU stop: validates via Rust decision, updates active count.
*
* @param id CPU id to stop.
*
* @return 0 on success, -EINVAL if only CPU 0 remains.
*/
int gale_smp_cpu_stop_checked(int id);

/**
* Get the current Gale-tracked active CPU count.
*
* @return Current active CPU count.
*/
unsigned int gale_smp_active_cpus_get(void);

#ifdef __cplusplus
}
#endif
Expand Down
Loading
Loading