diff --git a/src/thread/thread.c b/src/thread/thread.c index 4dc37f5..5c86b21 100644 --- a/src/thread/thread.c +++ b/src/thread/thread.c @@ -24,6 +24,11 @@ #define STACK_SIZE 4096 #endif +// Variables to free at the end of the processus +static char stack_for_freeing[STACK_SIZE] = {0}; +static int stack_valgrind_id = 0; +static ucontext_t context_for_freeing; + struct context_entry { TAILQ_ENTRY(context_entry) link; @@ -41,22 +46,28 @@ static unsigned long long counter = 0; int thread_yield(void) { TRACE("thread_yield"); - if (counter <= 1) { + if (counter <= 1) return 0; - } + struct context_entry* first = NULL; int count = 0; do { if (count++ == counter) { return 0; } + first = TAILQ_FIRST(&head); if (!first) { return -1; } + TAILQ_REMOVE(&head, first, link); TAILQ_INSERT_TAIL(&head, first, link); - } while (IS_FINISHED(first) || IS_WAITING(first) && !IS_WAITING_THREAD_FINISHED(first) || (first->id == running->id)); + } while ( + IS_FINISHED(first) + || IS_WAITING(first) && !IS_WAITING_THREAD_FINISHED(first) + || (first->id == running->id)); + TRACE("PICKING %p (previous was %p)", first->id, running->id); struct context_entry* old_runner = running; running = first; @@ -83,19 +94,27 @@ int thread_create(thread_t* newthread, void* (*func)(void*), void* funcarg) TRACE("Create a new thread that execute function %p", func); struct context_entry* new_entry = malloc(sizeof(*new_entry)); memset(new_entry, 0, sizeof(*new_entry)); + getcontext(&new_entry->context); + new_entry->context.uc_stack.ss_sp = malloc(STACK_SIZE); new_entry->context.uc_stack.ss_size = STACK_SIZE; + new_entry->context.uc_stack.ss_flags = 0; + new_entry->valgrind_id = VALGRIND_STACK_REGISTER( new_entry->context.uc_stack.ss_sp, new_entry->context.uc_stack.ss_sp + new_entry->context.uc_stack.ss_size); + new_entry->id = new_entry; TRACE("ALLOCATED %p", new_entry); new_entry->status = ALLOCATED; - new_entry->retvalue = 0; + new_entry->retvalue = NULL; + *newthread = new_entry->id; + makecontext(&new_entry->context, (void (*)(void))thread_function_wrapper, 2, func, funcarg); counter++; + TAILQ_INSERT_TAIL(&head, new_entry, link); return 0; } @@ -127,6 +146,7 @@ int thread_join(thread_t thread, void** retval) TAILQ_REMOVE(&head, entry, link); + TRACE("DEBUG %p,%d", entry, WAS_ALLOCATED(entry)); if (WAS_ALLOCATED(entry)) { VALGRIND_STACK_DEREGISTER(entry->valgrind_id); free(entry->context.uc_stack.ss_sp); @@ -142,14 +162,32 @@ void thread_exit(void* retval) { TRACE("Exit thread %p", running); print_entry(running); - if (running == 0) + if (running == 0) { exit(0); + } running->status |= FINISHED; running->retvalue = retval; - if (counter > 1) + if (counter > 1) { thread_yield(); + } + exit(0); +} + +void clear_context(void) +{ + TRACE("INSIDE CLEAR"); + struct context_entry* last = NULL; + while (!TAILQ_EMPTY(&head)) { + last = TAILQ_FIRST(&head); + TAILQ_REMOVE(&head, last, link); + if (WAS_ALLOCATED(last)) { + free(last->context.uc_stack.ss_sp); + } + free(last); + } + VALGRIND_STACK_DEREGISTER(stack_valgrind_id); exit(0); } @@ -161,42 +199,29 @@ void __attribute__((constructor)) setup_main_thread() getcontext(&main->context); main->id = main; main->status = 0; - main->retvalue = 0; + main->retvalue = NULL; TAILQ_INSERT_TAIL(&head, main, link); running = main; counter++; -} -void clear_context(void) -{ - struct context_entry *running; - while (TAILQ_EMPTY(&head)) { - TRACE("CONTEXT %p", running); - running = TAILQ_FIRST(&head); - if (WAS_ALLOCATED(running)) { - TRACE("ALLOCATED"); - VALGRIND_STACK_DEREGISTER(running->id); - free(running->context.uc_stack.ss_sp); - } - free(running); - } - exit(0); + getcontext(&context_for_freeing); + stack_valgrind_id = VALGRIND_STACK_REGISTER(stack_for_freeing, stack_for_freeing + STACK_SIZE); + context_for_freeing.uc_stack.ss_sp = stack_for_freeing; + context_for_freeing.uc_stack.ss_size = STACK_SIZE; + makecontext(&context_for_freeing, (void (*)(void)) clear_context, 1, running); } void __attribute__((destructor)) clear_last_thread() { TRACE("POST"); - ucontext_t old; - ucontext_t garbage_cleaner; - getcontext(&old); - getcontext(&garbage_cleaner); - char stack[STACK_SIZE] = { 0 }; - memcpy(stack, old.uc_stack.ss_sp, STACK_SIZE); - garbage_cleaner.uc_stack.ss_sp = stack; - garbage_cleaner.uc_stack.ss_size = STACK_SIZE; - print_entry(running); - makecontext(&garbage_cleaner, (void (*)(void))clear_context, 0); - swapcontext(&old, &garbage_cleaner); + // Running is the initial main thread. Just free the entry. + if (!WAS_ALLOCATED(running)) { + free(running); + exit(0); + } + + swapcontext(&running->context, &context_for_freeing); + exit(0); } int thread_mutex_init(thread_mutex_t* mutex)