AmendHub

Download:

jcs

/

subtext

/

amendments

/

625

uthread: Get rid of stack gaps, just put canaries behind stack bottom


jcs made amendment 625 9 months ago
--- uthread.c Tue Feb 28 19:02:38 2023 +++ uthread.c Fri Dec 12 16:41:21 2025 @@ -22,86 +22,81 @@ #include "uthread.h" #include "util.h" +#include "logger.h" -#define COORDINATOR_STACK_SIZE (1024UL * 100UL) -#define STACK_SIZE (1024UL * 50UL) -#define STACK_GAP 1024 -#define STACK_GAP_FILL 0xff -#define CANARY 0xdeadf00d +#define COORDINATOR_STACK_SIZE ((1024UL * 100UL) - 1) +#define UTHREAD_STACK_SIZE ((1024UL * 50UL) - 1) +#define UTHREAD_CANARY 0xdeadf00d jmp_buf uthread_coord_env; static struct uthread uthreads[NUM_UTHREADS]; struct uthread *uthread_current = NULL; -static Ptr main_stack_gap = NULL; -static char uthread_stack_gap_fill[STACK_GAP]; -unsigned long uthread_ApplLimit = 0; +unsigned long uthread_main_canary; void uthread_begin(struct uthread *uthread); /* * | A5 world | - * |-------------------| 0x26234E CurStackBase (stacks_top) - * | main stack | COORDINATOR_STACK_SIZE - * |-------------------| 0x260F4E - * | main stack gap | STACK_GAP - * |-------------------| 0x260C00 (main_stack_gap, upward) + * |-------------------| 0x2251b0 CurStackBase (stacks_top) + * | coordinator stack | COORDINATOR_STACK_SIZE + * |-------------------| 0x24934d (coordinator stack bottom) + * | (alignment) | + * |-------------------| 0x20c000 (uthread_stacks_top) * : (other threads) : - * |-------------------| 0x25DC00 ((STACK_SIZE - STACK_GAP) downward) - * | uthread 1 stack | + * |-------------------| 0x1da000 (uthreads[1].stack_top downward) + * | uthread 1 stack | STACK_SIZE * | | - * |-------------------| - * | uthread 1 gap | 0x25D001 (STACK_GAP upward) - * |-------------------| 0x25D000 (downward) - * | uthread 0 stack | + * |-------------------| 0x1cd802 (uthreads[1].stack_canary upward) + * |-------------------| 0x1cd801 (uthreads[1].stack_bottom) + * |-------------------| 0x1cd800 (uthreads[0].stack_top downward) + * | uthread 0 stack | STACK_SIZE * | | - * |-------------------| - * | uthread 0 gap | 0x25C401 (STACK_GAP upward) - * |-------------------| 0x25C400 ApplLimit (stacks_bottom) + * |-------------------| 0x1c1002 (uthreads[0].stack_canary upward) + * |-------------------| 0x1c1001 (uthreads[0].stack_bottom) + * |-------------------| 0x1c1000 ApplLimit (stacks_bottom) * | | * | heap | * | | - * |-------------------| 0x16F5D8 ApplZone + * |-------------------| 0x16f5D8 ApplZone */ void uthread_init(void) { - unsigned long stacks_top, stacks_bottom; + static unsigned long stacks_top, stacks_bottom, uthread_stacks_top, + loc; short i; stacks_top = (unsigned long)CurStackBase; - main_stack_gap = (Ptr)(stacks_top - COORDINATOR_STACK_SIZE - - STACK_GAP); /* align uthread stacks */ - main_stack_gap = (Ptr)((unsigned long)main_stack_gap - - ((unsigned long)main_stack_gap % 1024)); + uthread_stacks_top = stacks_top - COORDINATOR_STACK_SIZE; + uthread_stacks_top -= uthread_stacks_top % 1024; - stacks_bottom = (unsigned long)main_stack_gap - - (STACK_SIZE * NUM_UTHREADS); + uthread_main_canary = uthread_stacks_top + 2; + *(unsigned long *)uthread_main_canary = UTHREAD_CANARY; - if (stacks_bottom > stacks_top) - panic("stacks_bottom > stacks_top"); - - uthread_ApplLimit = stacks_bottom - (1024UL * 64); - if (uthread_ApplLimit < (unsigned long)ApplZone) + stacks_bottom = uthread_stacks_top - ((UTHREAD_STACK_SIZE + 1) * + NUM_UTHREADS); + if (stacks_bottom <= (unsigned long)ApplZone) panic("stacks_bottom < ApplZone"); - - SetApplLimit((Ptr)uthread_ApplLimit); + + SetApplLimit((Ptr)stacks_bottom); if (MemError()) - panic("Failed to SetApplLimit to %lu", uthread_ApplLimit); + panic("Failed to SetApplLimit to %lu", stacks_bottom); - /* color in our whole uthread stack space */ - memset((Ptr)uthread_ApplLimit, STACK_GAP_FILL, - (unsigned long)main_stack_gap + STACK_GAP - uthread_ApplLimit); - /* this is what we'll compare each gap to */ - memset(uthread_stack_gap_fill, STACK_GAP_FILL, STACK_GAP); - + loc = stacks_bottom + 1; for (i = 0; i < NUM_UTHREADS; i++) { uthreads[i].id = i; uthreads[i].state = UTHREAD_STATE_DEAD; - uthreads[i].stack_loc = stacks_bottom + (STACK_SIZE * (i + 1)) - 2; - uthreads[i].stack_gap = uthreads[i].stack_loc - STACK_SIZE + 2; + uthreads[i].stack_bottom = loc; + uthreads[i].stack_canary = uthreads[i].stack_bottom + 1; + uthreads[i].stack_top = uthreads[i].stack_bottom + + UTHREAD_STACK_SIZE; + loc = uthreads[i].stack_top + 1; } + if (loc > uthread_stacks_top + 1) + panic("uthreads ran into main stack"); + uthread_verify(); } @@ -118,8 +113,8 @@ uthread_add(void *func, void *arg) uthreads[i].arg = arg; uthreads[i].state = UTHREAD_STATE_SETUP; - /* color in stack gap just to be sure */ - memset((Ptr)uthreads[i].stack_gap, STACK_GAP_FILL, STACK_GAP); + memset((Ptr)uthreads[i].stack_bottom, 0, UTHREAD_STACK_SIZE); + *(unsigned long *)uthreads[i].stack_canary = UTHREAD_CANARY; return &uthreads[i]; } @@ -128,10 +123,36 @@ uthread_add(void *func, void *arg) } void +uthread_begin(struct uthread *uthread) +{ + register unsigned long stack_top = uthread->stack_top; + + asm { + move.l stack_top, a7 + }; + + /* add a canary at the bottom of our stack */ + *(unsigned long *)uthread->stack_canary = UTHREAD_CANARY; + + uthread->func(uthread, uthread->arg); + + uthread_verify(); + + /* uthread variable is probably trashed at this point */ + if (uthread_current->state == UTHREAD_STATE_REPEAT) + uthread_current->state = UTHREAD_STATE_SETUP; + else + uthread_current->state = UTHREAD_STATE_DEAD; + + longjmp(uthread_coord_env, UTHREAD_SETJMP_YIELDED); +} + +void uthread_yield(void) { - volatile long magic = CANARY; + volatile long magic = UTHREAD_CANARY; register unsigned long _sp = 0; + unsigned long n; asm { move.l a7, _sp @@ -139,24 +160,26 @@ uthread_yield(void) if (uthread_current == NULL) panic("uthread_yield not from a thread!"); - - uthread_verify(); - if ((uthread_current->stack_loc - _sp) > (STACK_SIZE / 2)) - panic("thread %d stack growing too large " - "[SP=0x%lx] [stack=0x%lx] [gap=0x%lx-0x%lx]", - uthread_current->id, _sp, uthread_current->stack_loc, - uthread_current->stack_gap, - uthread_current->stack_gap + STACK_GAP); + if (_sp > uthread_current->stack_top || + _sp < uthread_current->stack_bottom) + panic("thread %d stack pointer out of bounds [SP=0x%lx] " + "[top=0x%lx] [bottom=0x%lx]", uthread_current->id, _sp, + uthread_current->stack_top, uthread_current->stack_bottom); + if (uthread_current->stack_top - _sp > ((UTHREAD_STACK_SIZE * 9) / 10)) + warn("thread %d stack usage >= 90%%", uthread_current->id); + if (uthread_current->state != UTHREAD_STATE_SLEEPING) uthread_current->state = UTHREAD_STATE_YIELDING; + uthread_verify(); + if (setjmp(uthread_current->env) == 0) longjmp(uthread_coord_env, UTHREAD_SETJMP_YIELDED); /* will not return */ - if (magic != CANARY) + if (magic != UTHREAD_CANARY) panic("uthread stack canary dead!"); } @@ -179,27 +202,6 @@ uthread_wakeup(struct uthread *uthread) } void -uthread_begin(struct uthread *uthread) -{ - register unsigned long stack_loc = uthread->stack_loc; - asm { - move.l stack_loc, a7 - }; - - uthread->func(uthread, uthread->arg); - - uthread_verify(); - - /* uthread variable is probably trashed at this point */ - if (uthread_current->state == UTHREAD_STATE_REPEAT) - uthread_current->state = UTHREAD_STATE_SETUP; - else - uthread_current->state = UTHREAD_STATE_DEAD; - - longjmp(uthread_coord_env, UTHREAD_SETJMP_YIELDED); -} - -void uthread_coordinate(void) { short i; @@ -241,19 +243,26 @@ uthread_coordinate(void) void uthread_verify(void) { + register unsigned long _sp = 0; short i; - unsigned char *gap; + + asm { + move.l a7, _sp + }; + + if (*(unsigned long *)uthread_main_canary != UTHREAD_CANARY) + panic("coordinator thread canary died"); - gap = (unsigned char *)main_stack_gap; - if (memcmp(gap, uthread_stack_gap_fill, STACK_GAP) != 0) - panic("coordinator spilled into stack gap"); - for (i = 0; i < NUM_UTHREADS; i++) { if (uthreads[i].state == UTHREAD_STATE_DEAD) continue; - gap = (unsigned char *)(uthreads[i].stack_gap); - if (memcmp(gap, uthread_stack_gap_fill, STACK_GAP) != 0) - panic("thread %d spilled into stack gap", i); + if (*(unsigned long *)uthreads[i].stack_canary != UTHREAD_CANARY) + warn("thread %d stack canary died", i); + if (uthread_current && uthread_current == &uthreads[i]) { + if (uthread_current->stack_top - _sp > + ((UTHREAD_STACK_SIZE * 9) / 10)) + warn("thread %d stack usage >= 90%%", uthread_current->id); + } } } \ No newline at end of file --- uthread.h Tue Feb 28 17:58:38 2023 +++ uthread.h Fri Dec 12 16:04:29 2025 @@ -42,8 +42,9 @@ struct uthread { void (*func)(struct uthread *, void *); void *arg; unsigned long sleeping_until; - unsigned long stack_loc; - unsigned long stack_gap; + unsigned long stack_top; + unsigned long stack_bottom; + unsigned long stack_canary; }; extern struct uthread *uthread_current;