From 8b2af1dd4772675680b8b23808886de5ce688cbc Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Mar 2012 18:10:59 -0800 Subject: [PATCH] initial commit Basic working copy of "threads," which execute until completion as soon as they are launched. --- Makefile | 11 +++++ libthreads.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 Makefile create mode 100644 libthreads.c diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..25b9459a --- /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 index 00000000..5f442b20 --- /dev/null +++ b/libthreads.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +//#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 = ¤t->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, ¤t->context); + } else { + current = t; + swapcontext(cleanup, ¤t->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; +} -- 2.34.1