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__ */