AmendHub

jcs

/

subtext

/

amendments

/

236

uthread: Pre-allocate threads, put gaps between each stack

Add a verification function that verifies that each gap hasn't been
written to.

jcs made amendment 236 2 months ago
--- uthread.c Sat Jul 16 21:42:21 2022 +++ uthread.c Wed Aug 3 14:25:06 2022 @@ -23,21 +23,72 @@ #include "uthread.h" #include "util.h" -#define STACK_SIZE (1024 * 5) -#define CANARY 0xdeadf00d - jmp_buf uthread_coord_env; -static struct uthread uthreads[NUM_UTHREADS] = { 0 }; +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; 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) + * : (other threads) : + * |-------------------| 0x25DC00 ((STACK_SIZE - STACK_GAP) downward) + * | uthread 1 stack | + * | | + * |-------------------| + * | uthread 1 gap | 0x25D001 (STACK_GAP upward) + * |-------------------| 0x25D000 (downward) + * | uthread 0 stack | + * | | + * |-------------------| + * | uthread 0 gap | 0x25C401 (STACK_GAP upward) + * |-------------------| 0x25C400 ApplLimit (stacks_bottom) + * | | + * | heap | + * | | + * |-------------------| 0x16F5D8 ApplZone + */ void uthread_init(void) { - SetApplLimit(GetApplLimit() - (STACK_SIZE * (NUM_UTHREADS + 1))); + unsigned long stacks_top, stacks_bottom; + 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)); + + stacks_bottom = (unsigned long)main_stack_gap - + (STACK_SIZE * NUM_UTHREADS); + + uthread_ApplLimit = stacks_bottom; // - (1024 * 5); + SetApplLimit((Ptr)uthread_ApplLimit); if (MemError()) - panic("Failed to SetApplLimit"); + panic("Failed to SetApplLimit to %lu", uthread_ApplLimit); + + /* color in our stack gap */ + memset(main_stack_gap, STACK_GAP_FILL, STACK_GAP); + memset(uthread_stack_gap_fill, STACK_GAP_FILL, STACK_GAP); + + 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)); + uthreads[i].stack_gap = uthreads[i].stack_loc - STACK_SIZE + 1; + } + + uthread_verify(); } struct uthread * @@ -48,11 +99,14 @@ uthread_add(void *func, void *arg) for (i = 0; i < NUM_UTHREADS; i++) { if (uthreads[i].state != UTHREAD_STATE_DEAD) continue; - - uthreads[i].id = i; + uthreads[i].func = func; uthreads[i].arg = arg; uthreads[i].state = UTHREAD_STATE_SETUP; + + /* color in stack gap */ + memset((Ptr)uthreads[i].stack_gap, STACK_GAP_FILL, STACK_GAP); + return &uthreads[i]; } @@ -63,19 +117,33 @@ void uthread_yield(void) { volatile long magic = CANARY; - + register unsigned long _sp = 0; + + asm { + move.l a7, _sp + }; + if (uthread_current == NULL) panic("uthread_yield not from a thread!"); - + + 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 (uthread_current->state != UTHREAD_STATE_SLEEPING) uthread_current->state = UTHREAD_STATE_YIELDING; - + if (setjmp(uthread_current->env) == 0) longjmp(uthread_coord_env, UTHREAD_SETJMP_YIELDED); /* will not return */ if (magic != CANARY) - panic("canary clobbered!"); + panic("uthread stack canary dead!"); + + uthread_verify(); } void @@ -92,16 +160,16 @@ uthread_msleep(unsigned long millis) void uthread_begin(struct uthread *uthread) { - register long stack_offset = STACK_SIZE * (uthread->id + 2); + register unsigned long stack_loc = uthread->stack_loc; asm { - movea.l stack_offset, a0 - sub.w a0, a7 + move.l stack_loc, a7 }; - + uthread->func(uthread, uthread->arg); - - /* uthread variable is probably trashed at this point */ + + uthread_verify(); + /* uthread variable is probably trashed at this point */ if (uthread_current->state == UTHREAD_STATE_REPEAT) uthread_current->state = UTHREAD_STATE_SETUP; else @@ -113,7 +181,8 @@ uthread_begin(struct uthread *uthread) void uthread_coordinate(void) { - short i; + short i, n; + unsigned char *gap; for (i = 0; i < NUM_UTHREADS; i++) { if (uthreads[i].state == UTHREAD_STATE_DEAD) @@ -146,4 +215,25 @@ uthread_coordinate(void) } uthread_current = NULL; + uthread_verify(); +} + +void +uthread_verify(void) +{ + short i; + unsigned char *gap; + + 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); + } } --- uthread.h Sat Jul 16 21:42:35 2022 +++ uthread.h Wed Aug 3 14:25:24 2022 @@ -19,7 +19,12 @@ #ifndef __UTHREAD_H__ #define __UTHREAD_H__ -#define NUM_UTHREADS 5 +#define NUM_UTHREADS 8 +#define COORDINATOR_STACK_SIZE (1024 * 10) +#define STACK_SIZE (1024 * 3) +#define STACK_GAP 255 +#define STACK_GAP_FILL 0xff +#define CANARY 0xdeadf00d enum { UTHREAD_STATE_DEAD, @@ -39,16 +44,21 @@ struct uthread { short state; short id; jmp_buf env; - char *stack; void (*func)(struct uthread *, void *); void *arg; unsigned long sleeping_until; + unsigned long stack_loc; + unsigned long stack_gap; }; +extern struct uthread *uthread_current; +extern unsigned long uthread_ApplLimit; + void uthread_init(void); struct uthread *uthread_add(void *func, void *arg); void uthread_yield(void); void uthread_coordinate(void); void uthread_msleep(unsigned long millis); +void uthread_verify(void); #endif /* __UTHREAD_H__ */