AmendHub

Download:

jcs

/

subtext

/

amendments

/

3

uthread: Add stand-alone cooperative threading mechanism


jcs made amendment 3 over 2 years ago
--- uthread.c Tue Nov 30 08:25:37 2021 +++ uthread.c Tue Nov 30 08:25:37 2021 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <setjmp.h> + +#include "uthread.h" + +#define STACK_SIZE (1024 * 4) +#define CANARY 0xdeadf00d +#define NUM_UTHREADS 5 + +jmp_buf uthread_coord_env; +static struct uthread uthreads[NUM_UTHREADS] = { 0 }; +struct uthread *uthread_current = NULL; + +void uthread_begin(struct uthread *uthread); + +void +uthread_init(void) +{ + SetApplLimit(GetApplLimit() - (STACK_SIZE * (NUM_UTHREADS + 1))); + if (MemError()) { + SysBeep(20); + ExitToShell(); + } +} + +struct uthread * +uthread_add(void *func, void *arg) +{ + short i; + + 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; + return &uthreads[i]; + } + + return NULL; +} + +void +uthread_yield(void) +{ + volatile long magic = CANARY; + + 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) { + printf("canary clobbered!\n"); + SysBeep(20); + ExitToShell(); + } +} + +void +uthread_begin(struct uthread *uthread) +{ + register long stack = STACK_SIZE * (uthread->id + 2); + asm { + movea.l stack, a0 + sub.w a0, a7 + }; + + uthread->func(uthread, uthread->arg); + + if (uthread->state == UTHREAD_STATE_REPEAT) + uthread->state = UTHREAD_STATE_SETUP; + else + uthread->state = UTHREAD_STATE_DEAD; + + longjmp(uthread_coord_env, UTHREAD_SETJMP_YIELDED); +} + +void +uthread_coordinate(void) +{ + short i; + + for (i = 0; i < NUM_UTHREADS; i++) { + if (uthreads[i].state == UTHREAD_STATE_DEAD || + uthreads[i].state == UTHREAD_STATE_SLEEPING) + continue; + + switch (setjmp(uthread_coord_env)) { + case UTHREAD_SETJMP_DEFAULT: + uthread_current = &uthreads[i]; + + switch (uthread_current->state) { + case UTHREAD_STATE_SETUP: + uthread_current->state = UTHREAD_STATE_RUNNING; + uthread_begin(uthread_current); + break; + case UTHREAD_STATE_YIELDING: + uthread_current->state = UTHREAD_STATE_RUNNING; + longjmp(uthread_current->env, UTHREAD_SETJMP_YIELDED); + break; + } + break; + case UTHREAD_SETJMP_YIELDED: + break; + default: + SysBeep(20); + ExitToShell(); + } + } +} --- uthread.h Thu Nov 25 14:02:21 2021 +++ uthread.h Thu Nov 25 14:02:21 2021 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <setjmp.h> + +#ifndef __UTHREAD_H__ +#define __UTHREAD_H__ + +enum { + UTHREAD_STATE_DEAD, + UTHREAD_STATE_SETUP, + UTHREAD_STATE_RUNNING, + UTHREAD_STATE_YIELDING, + UTHREAD_STATE_SLEEPING, + UTHREAD_STATE_REPEAT +}; + +enum { + UTHREAD_SETJMP_DEFAULT, + UTHREAD_SETJMP_YIELDED +}; + +struct uthread { + short state; + short id; + jmp_buf env; + char *stack; + void (*func)(struct uthread *, void *); + void *arg; +}; + +void uthread_init(void); +struct uthread *uthread_add(void *func, void *arg); +void uthread_yield(void); +void uthread_coordinate(void); + +#endif /* __UTHREAD_H__ */