initial commit
authorBrian Norris <banorris@uci.edu>
Thu, 8 Mar 2012 02:10:59 +0000 (18:10 -0800)
committerBrian Norris <banorris@uci.edu>
Thu, 8 Mar 2012 02:10:59 +0000 (18:10 -0800)
Basic working copy of "threads," which execute until completion as soon as
they are launched.

Makefile [new file with mode: 0644]
libthreads.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..25b9459
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+BIN=libthreads
+SOURCE=libthreads.c
+FLAGS=
+
+all: ${BIN}
+
+${BIN}: ${SOURCE}
+       gcc -o ${BIN} ${SOURCE} ${FLAGS}
+
+clean:
+       rm -f ${BIN} *.o
diff --git a/libthreads.c b/libthreads.c
new file mode 100644 (file)
index 0000000..5f442b2
--- /dev/null
@@ -0,0 +1,121 @@
+#include <string.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <stdio.h>
+
+//#define CONFIG_DEBUG
+
+#ifdef CONFIG_DEBUG
+#define DBG() do { printf("Here: %s, L%d\n", __func__, __LINE__); } while (0)
+#define DEBUG(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define DBG()
+#define DEBUG(fmt, ...)
+#endif
+
+#define STACK_SIZE (1024 * 1024)
+
+struct thread {
+       void (*start_routine);
+       void *arg;
+       ucontext_t context;
+       void *stack;
+       int started;
+       int index;
+};
+
+static struct thread *current;
+static ucontext_t *cleanup;
+
+static void *stack_allocate(size_t size)
+{
+       return malloc(size);
+}
+
+int thread_create(struct thread *t, void (*start_routine), void *arg)
+{
+       static int created;
+       ucontext_t local;
+
+       DBG();
+
+       t->index = created++;
+       DEBUG("create thread %d\n", t->index);
+
+       t->start_routine = start_routine;
+       t->arg = arg;
+       t->started = 0;
+
+       /* Initialize state */
+       getcontext(&t->context);
+       t->stack = stack_allocate(STACK_SIZE);
+       t->context.uc_stack.ss_sp = t->stack;
+       t->context.uc_stack.ss_size = STACK_SIZE;
+       t->context.uc_stack.ss_flags = 0;
+       if (current)
+               t->context.uc_link = &current->context;
+       else
+               t->context.uc_link = cleanup;
+       makecontext(&t->context, t->start_routine, 1, t->arg);
+
+       return 0;
+}
+
+void thread_start(struct thread *t)
+{
+       DBG();
+
+       t->started = 1;
+       
+       if (current) {
+               struct thread *old = current;
+               current = t;
+               swapcontext(&old->context, &current->context);
+       } else {
+               current = t;
+               swapcontext(cleanup, &current->context);
+       }
+       DBG();
+}
+
+void a(int *idx)
+{
+       int i;
+
+       for (i = 0; i < 10; i++)
+               printf("Thread %d, loop %d\n", *idx, i);
+}
+
+void user_main()
+{
+       struct thread t1, t2;
+       int i = 1, j = 2;
+
+       thread_create(&t1, &a, &i);
+       thread_create(&t2, &a, &j);
+
+       printf("user_main() is going to start 2 threads\n");
+       thread_start(&t1);
+       thread_start(&t2);
+       printf("user_main() is finished\n");
+}
+
+int main()
+{
+       struct thread t;
+       ucontext_t main_context;
+       int pass = 0;
+
+       cleanup = &main_context;
+
+       thread_create(&t, &user_main, NULL);
+
+       getcontext(&main_context);
+       if (!pass++)
+               thread_start(&t);
+
+       DBG();
+
+       DEBUG("Exiting?\n");
+       return 0;
+}