Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [Unreleased]

### Fixed
- **`eos_queue_send` / `eos_queue_receive`:** A full send/recv waiter table now returns `EOS_KERN_NO_MEMORY` instead of blocking a task that can never be woken, matching mutex and semaphore behavior.
- **`eos_queue_create`:** Size check now uses division so `item_size * capacity` cannot wrap `size_t` on 32-bit targets and overflow the 1024-byte queue store.
- **`eos_sem_create`:** Reject `initial > max` and `max` values that do not fit in `int32_t`, so the counting-semaphore invariant cannot be created already broken.
- **`eos_mutex_lock`:** Recursive lock returns `EOS_KERN_FULL` at `uint8_t` saturation instead of wrapping `rec_count` to 0 and leaving the mutex stuck.
Expand Down
18 changes: 12 additions & 6 deletions kernel/src/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,13 @@ int eos_queue_send(eos_queue_handle_t h, const void *item, uint32_t timeout_ms)
return EOS_KERN_FULL;
}

uint8_t caller = (uint8_t)eos_task_get_current();
if (g_q[h].send_waiter_count < Q_MAX_WAITERS) {
g_q[h].send_waiters[g_q[h].send_waiter_count++] = caller;
if (g_q[h].send_waiter_count >= Q_MAX_WAITERS) {
eos_port_exit_critical(crit);
return EOS_KERN_NO_MEMORY;
}

uint8_t caller = (uint8_t)eos_task_get_current();
g_q[h].send_waiters[g_q[h].send_waiter_count++] = caller;
eos_task_block_with_timeout(caller, timeout_ms);
eos_port_exit_critical(crit);
eos_port_yield();
Expand Down Expand Up @@ -146,10 +149,13 @@ int eos_queue_receive(eos_queue_handle_t h, void *item, uint32_t timeout_ms)
return EOS_KERN_EMPTY;
}

uint8_t caller = (uint8_t)eos_task_get_current();
if (g_q[h].recv_waiter_count < Q_MAX_WAITERS) {
g_q[h].recv_waiters[g_q[h].recv_waiter_count++] = caller;
if (g_q[h].recv_waiter_count >= Q_MAX_WAITERS) {
eos_port_exit_critical(crit);
return EOS_KERN_NO_MEMORY;
}

uint8_t caller = (uint8_t)eos_task_get_current();
g_q[h].recv_waiters[g_q[h].recv_waiter_count++] = caller;
eos_task_block_with_timeout(caller, timeout_ms);
eos_port_exit_critical(crit);
eos_port_yield();
Expand Down
53 changes: 52 additions & 1 deletion tests/test_kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,55 @@ static void test_queue_full(void) {
printf("[PASS] queue full/peek\n");
}

/* ---- Queue send waiter overflow ---- */

static eos_queue_handle_t q7_q;
static eos_task_handle_t q7_waiters[EOS_MAX_TASKS];
static int q7_next, q7_total, q7_overflow_reported, q7_enqueued;
static void (*q7_yield_hook)(void);

static void q7_hook(void)
{
if (q7_next >= q7_total) return;
eos_task_handle_t w = q7_waiters[q7_next++];
eos_task_set_current_internal(w);
int item = 0;
int rc = eos_queue_send(q7_q, &item, EOS_WAIT_FOREVER);
if (rc == EOS_KERN_NO_MEMORY) q7_overflow_reported = 1;
else q7_enqueued++;
}

static void test_queue_send_waiter_overflow(void) {
eos_kernel_init();
assert(eos_queue_create(&q7_q, sizeof(int), 1) == EOS_KERN_OK);

int filler = 42;
assert(eos_queue_send(q7_q, &filler, EOS_NO_WAIT) == EOS_KERN_OK);

q7_total = 0;
for (int i = 0; i < EOS_MAX_TASKS - 2; i++) {
char name[8];
snprintf(name, sizeof(name), "qs%d", i);
q7_waiters[q7_total++] = eos_task_create(name, test_entry, NULL, (uint8_t)(10 + i), 512);
assert(q7_waiters[q7_total - 1] >= 0);
Comment on lines +168 to +171
}
q7_next = 0;
q7_enqueued = 0;
q7_overflow_reported = 0;

q7_yield_hook = q7_hook;
eos_task_set_current_internal(q7_waiters[q7_next++]);
int item = 1;
int rc = eos_queue_send(q7_q, &item, EOS_WAIT_FOREVER);
if (rc == EOS_KERN_NO_MEMORY) q7_overflow_reported = 1;
q7_yield_hook = NULL;

assert(q7_enqueued > 0);
assert(q7_overflow_reported);
assert(eos_queue_delete(q7_q) == EOS_KERN_OK);
printf("[PASS] queue send waiter overflow\n");
}

static void test_task_stats(void) {
eos_kernel_init();
int h = eos_task_create("stats_task", test_entry, NULL, 3, 1024);
Expand Down Expand Up @@ -222,6 +271,7 @@ void eos_port_yield(void)
{
if (g_yield_owner >= 0)
g_yield_prio = eos_task_get_priority_internal((eos_task_handle_t)g_yield_owner);
if (q7_yield_hook) q7_yield_hook();
}
void eos_port_start_scheduler(void) {}
uint32_t *eos_port_init_stack(uint32_t *s, void (*e)(void*), void *a) { (void)e; (void)a; return s - 17; }
Expand Down Expand Up @@ -268,6 +318,7 @@ int main(void) {
test_semaphore();
test_queue();
test_queue_full();
printf("=== ALL KERNEL TESTS PASSED (10/10) ===\n");
test_queue_send_waiter_overflow();
printf("=== ALL KERNEL TESTS PASSED (11/11) ===\n");
return 0;
}