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;