summaryrefslogtreecommitdiff
path: root/libptimc
diff options
context:
space:
mode:
Diffstat (limited to 'libptimc')
-rw-r--r--libptimc/libptimc.c125
-rw-r--r--libptimc/libptimc.h49
2 files changed, 174 insertions, 0 deletions
diff --git a/libptimc/libptimc.c b/libptimc/libptimc.c
new file mode 100644
index 0000000..3cda04b
--- /dev/null
+++ b/libptimc/libptimc.c
@@ -0,0 +1,125 @@
+#include "libptimc.h"
+
+static struct imcthread **THREADS = 0;
+static size_t N_THREADS = 0;
+static struct imcthread *CURRENT_THREAD = 0;
+static ucontext_t MASTER_CTX;
+
+static void switch_to_thread(struct imcthread *thread);
+static void imcthread_entry_point(int tid);
+
+static void resetter() {
+ for (int i = 0; i < N_THREADS; i++) {
+ free(THREADS[i]->ctx.uc_stack.ss_sp);
+ free(THREADS[i]);
+ }
+ free(THREADS);
+ THREADS = 0;
+ N_THREADS = 0;
+ CURRENT_THREAD = 0;
+}
+
+int imcthread_create(imcthread_t *threadp,
+ imcthread_attr_t *attr,
+ void *(*start_routine)(void *),
+ void *arg) {
+ assert(!attr);
+ THREADS = realloc(THREADS, (++N_THREADS) * sizeof(THREADS[0]));
+ THREADS[N_THREADS - 1] = calloc(1, sizeof(struct imcthread));
+
+ struct imcthread *thread = THREADS[N_THREADS - 1];
+ *threadp = thread;
+ thread->fn = start_routine;
+ thread->arg = arg;
+ thread->state = THREAD_STATE_FETUS;
+ thread->id = N_THREADS - 1;
+
+ assert(!getcontext(&thread->ctx));
+ thread->ctx.uc_stack.ss_size = 4 * 1024 * 1024;
+ thread->ctx.uc_stack.ss_sp = malloc(thread->ctx.uc_stack.ss_size);
+ thread->ctx.uc_link = 0;
+ makecontext(&thread->ctx, imcthread_entry_point, 1, thread->id);
+
+ return 0;
+}
+
+int imcthread_yieldh(hash_t hash) {
+ // pauses the current thread and returns to the master thread
+ assert(CURRENT_THREAD);
+ struct imcthread *thread = CURRENT_THREAD;
+
+ if (thread->state == THREAD_STATE_DEAD) {
+ for (size_t i = 0; i < N_THREADS; i++)
+ if (THREADS[i]->waiting_on == thread)
+ THREADS[i]->waiting_on = 0;
+ }
+
+ CURRENT_THREAD = 0;
+ swapcontext(&(thread->ctx), &MASTER_CTX);
+
+ return 0;
+}
+int imcthread_yield(void) { imcthread_yieldh(0); }
+
+static void *_imc_check_main(void *_) { imc_check_main(); return 0; }
+void check_main() {
+ register_resetter(resetter);
+
+ imcthread_t _thread;
+ imcthread_create(&_thread, NULL, _imc_check_main, NULL);
+
+ while (1) {
+ int n_alive = 0, n_avail = 0;
+ for (int i = 0; i < N_THREADS; i++) {
+ if (THREADS[i]->state == THREAD_STATE_DEAD) continue;
+ n_alive++;
+ if (THREADS[i]->waiting_on) continue;
+ n_avail++;
+ }
+ // check that we're not in a deadlock
+ if (!n_avail) { assert(!n_alive); break; }
+
+ int count = choose(n_avail, 0);
+ for (int i = 0; i < N_THREADS; i++) {
+ if (THREADS[i]->state == THREAD_STATE_DEAD) continue;
+ if (THREADS[i]->waiting_on) continue;
+ if (count--) continue;
+ switch_to_thread(THREADS[i]);
+ break;
+ }
+ }
+}
+
+int imcthread_joinh(imcthread_t thread, void **retval, hash_t hash) {
+ if (thread->state != THREAD_STATE_DEAD) {
+ CURRENT_THREAD->waiting_on = thread;
+ imcthread_yield();
+ }
+
+ if (retval) *retval = thread->retval;
+ return 0;
+}
+int imcthread_join(imcthread_t thread, void **retval) {
+ return imcthread_joinh(thread, retval, 0);
+}
+
+static void switch_to_thread(struct imcthread *thread) {
+ assert(!CURRENT_THREAD);
+ assert(thread->state != THREAD_STATE_DEAD);
+
+ CURRENT_THREAD = thread;
+ swapcontext(&MASTER_CTX, &(thread->ctx));
+}
+
+static void imcthread_entry_point(int tid) {
+ struct imcthread *thread = THREADS[tid];
+ thread->state = THREAD_STATE_ALIVE;
+ CURRENT_THREAD = thread;
+
+ void *result = thread->fn(thread->arg);
+
+ thread->retval = result;
+ thread->state = THREAD_STATE_DEAD;
+
+ imcthread_yield();
+}
diff --git a/libptimc/libptimc.h b/libptimc/libptimc.h
new file mode 100644
index 0000000..c6314dd
--- /dev/null
+++ b/libptimc/libptimc.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include "libimc.h"
+
+enum thread_state {
+ THREAD_STATE_FETUS,
+ THREAD_STATE_ALIVE,
+ THREAD_STATE_DEAD,
+};
+
+typedef struct imcthread {
+ void *(*fn)(void *);
+ void *arg;
+ enum thread_state state;
+ int id;
+ struct imcthread *waiting_on;
+ void *retval;
+
+ ucontext_t ctx;
+} *imcthread_t;
+
+typedef int imcthread_attr_t;
+
+int imcthread_create(imcthread_t *thread,
+ // only support NULL attr for now
+ imcthread_attr_t *attr,
+ void *(*start_routine)(void *),
+ void *arg);
+int imcthread_yield(void);
+int imcthread_join(imcthread_t thread, void **retval);
+
+int imcthread_yieldh(hash_t hash);
+int imcthread_joinh(imcthread_t thread, void **retval, hash_t hash);
+
+void check_main(void);
+
+extern void imc_check_main(void);
+
+#ifdef __cplusplus
+}
+#endif
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback