From 987e1373775e2252da3c5d92fb90ccc98bedeecc Mon Sep 17 00:00:00 2001 From: Alessandre Laguierce Date: Fri, 21 Mar 2025 20:38:08 +0100 Subject: [PATCH] feat: begin rewrite --- src/thread/thread.c | 282 ++++++++++++++++++++++++++------------------ 1 file changed, 165 insertions(+), 117 deletions(-) diff --git a/src/thread/thread.c b/src/thread/thread.c index 66cbb94..4dc37f5 100644 --- a/src/thread/thread.c +++ b/src/thread/thread.c @@ -1,174 +1,222 @@ -#include #ifndef USE_PTHREAD #include "thread.h" #include "debug.h" #include "pthread.h" -#include #include #include +#include +#include #include #include -#define FINISHED 0x1 +#define FINISHED 0x1 +#define IS_FINISHED(entry) (entry->status & FINISHED) #define ALLOCATED 0x2 -#define WAITING 0x4 +#define WAS_ALLOCATED(entry) (entry->status & ALLOCATED) +#define WAITING 0x4 +#define IS_WAITING(entry) (entry->status & WAITING) +#define IS_WAITING_THREAD_FINISHED(entry) (((struct context_entry*)entry->retvalue)->status & FINISHED) +#define WAITED 0x8 +#define IS_WAITED(entry) (entry->status & WAITED) #ifndef STACK_SIZE #define STACK_SIZE 4096 #endif struct context_entry { - TAILQ_ENTRY(context_entry) link; - ucontext_t context; - thread_t id; - void *retvalue; - int valgrind_id; - char status; + TAILQ_ENTRY(context_entry) + link; + ucontext_t context; + thread_t id; + void* retvalue; + int valgrind_id; + char status; }; static TAILQ_HEAD(context_head, context_entry) head = TAILQ_HEAD_INITIALIZER(head); -static struct context_entry *running = 0; +static struct context_entry* running = NULL; static unsigned long long counter = 0; -int thread_yield(void) { - TRACE("thread_yield"); - if (counter <= 1) { - return 0; - } - struct context_entry *first = NULL; - int count = 0; - do { - if (count++ == counter) { - return 0; +int thread_yield(void) +{ + TRACE("thread_yield"); + if (counter <= 1) { + return 0; } - first = TAILQ_FIRST(&head); - if (!first) { - return -1; - } - TAILQ_REMOVE(&head, first, link); - TAILQ_INSERT_TAIL(&head, first, link); - } while ((first->status & FINISHED) || - ((first->status & WAITING) && !(((struct context_entry *)first->retvalue)->status & FINISHED)) || - (first->id == running->id)); - TRACE("PICKING %p (previous was %p)", first->id, running->id); - struct context_entry *old_runner = running; - running = first; - swapcontext(&old_runner->context, &running->context); - return 0; -} - -thread_t thread_self(void) { - if (running == NULL) { + 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)); + TRACE("PICKING %p (previous was %p)", first->id, running->id); + struct context_entry* old_runner = running; + running = first; + swapcontext(&old_runner->context, &running->context); return 0; - } - return running->id; } -void thread_function_wrapper(void *(*func)(void *), void *funcarg) { - TRACE("Wrapper for %p\n", func); - thread_exit(func(funcarg)); +thread_t thread_self(void) +{ + if (running == NULL) { + return 0; + } + return running->id; } -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)); - if (counter == 0) { +void thread_function_wrapper(void* (*func)(void*), void* funcarg) +{ + TRACE("Wrapper for %p\n", func); + thread_exit(func(funcarg)); +} + +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->id = 0; - new_entry->status = 0; + new_entry->context.uc_stack.ss_sp = malloc(STACK_SIZE); + new_entry->context.uc_stack.ss_size = STACK_SIZE; + 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; - TAILQ_INSERT_TAIL(&head, new_entry, link); - running = new_entry; + *newthread = new_entry->id; + makecontext(&new_entry->context, (void (*)(void))thread_function_wrapper, 2, func, funcarg); counter++; - 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->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; - new_entry->status = ALLOCATED; - new_entry->retvalue = 0; - *newthread = new_entry; - makecontext(&new_entry->context, (void (*)(void)) thread_function_wrapper, 2, func, funcarg); - counter++; - TAILQ_INSERT_TAIL(&head, new_entry, link); - return 0; + TAILQ_INSERT_TAIL(&head, new_entry, link); + return 0; } -void print_entry(struct context_entry *entry) { - TRACE("CONTEXT (%p, %p, %d);", entry, entry->id, (entry->status & FINISHED) > 0); +void print_entry(struct context_entry* entry) +{ + TRACE("CONTEXT (%p, %p, %d);", entry, entry->id, WAS_ALLOCATED(entry)); } -int thread_join(thread_t thread, void **retval) { - TRACE("Join thread %p", thread); - struct context_entry *entry; - TAILQ_FOREACH(entry, &head, link) { - if (entry->id != thread) { - continue; +int thread_join(thread_t thread, void** retval) +{ + TRACE("Join thread %p", thread); + struct context_entry* entry = thread; + if (IS_WAITED(entry)) { + return -1; } - TRACE("FIND %d",entry->status); + running->status |= WAITING; running->retvalue = entry; - while (!(entry->status & FINISHED)) { - TRACE("NOT FINISHED"); - thread_yield(); + entry->status |= WAITED; + + while (!IS_FINISHED(entry)) { + thread_yield(); } + running->status &= ~WAITING; - TRACE("AFTER"); if (retval) - *retval = entry->retvalue; + *retval = entry->retvalue; + TAILQ_REMOVE(&head, entry, link); - if (entry->status & ALLOCATED) { - TRACE("FREE\n"); - VALGRIND_STACK_DEREGISTER(entry->valgrind_id); - free(entry->context.uc_stack.ss_sp); - } else { - TRACE("NOT ALLOCATED\n"); + + if (WAS_ALLOCATED(entry)) { + VALGRIND_STACK_DEREGISTER(entry->valgrind_id); + free(entry->context.uc_stack.ss_sp); } free(entry); - if (--counter == 1) { - TAILQ_REMOVE(&head, running, link); - if (running->status & ALLOCATED) { - VALGRIND_STACK_DEREGISTER(running->valgrind_id); - free(running->context.uc_stack.ss_sp); - } - free(running); - running = 0; - counter = 0; - } + --counter; + TRACE("DEBUG %p,%d", running, WAS_ALLOCATED(running)); + return 0; - } - return -1; } -void thread_exit(void *retval) { - TRACE("Exit thread %p", running); - if (running == 0) +void thread_exit(void* retval) +{ + TRACE("Exit thread %p", running); + print_entry(running); + if (running == 0) + exit(0); + + running->status |= FINISHED; + running->retvalue = retval; + + if (counter > 1) + thread_yield(); exit(0); - running->status |= FINISHED; - running->retvalue = retval; - thread_yield(); - exit(0); } -int thread_mutex_init(thread_mutex_t *mutex) { - return pthread_mutex_init((pthread_mutex_t *) mutex, NULL); +void __attribute__((constructor)) setup_main_thread() +{ + TRACE("premain"); + struct context_entry* main = malloc(sizeof(*main)); + memset(main, 0, sizeof(*main)); + getcontext(&main->context); + main->id = main; + main->status = 0; + main->retvalue = 0; + TAILQ_INSERT_TAIL(&head, main, link); + running = main; + counter++; } -int thread_mutex_destroy(thread_mutex_t *mutex) { - return pthread_mutex_destroy((pthread_mutex_t *) mutex); + +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); } -int thread_mutex_lock(thread_mutex_t *mutex) { - return pthread_mutex_lock((pthread_mutex_t * )mutex); + +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); } -int thread_mutex_unlock(thread_mutex_t *mutex) { - return pthread_mutex_unlock((pthread_mutex_t *)mutex); + +int thread_mutex_init(thread_mutex_t* mutex) +{ + return pthread_mutex_init((pthread_mutex_t*)mutex, NULL); +} + +int thread_mutex_destroy(thread_mutex_t* mutex) +{ + return pthread_mutex_destroy((pthread_mutex_t*)mutex); +} + +int thread_mutex_lock(thread_mutex_t* mutex) +{ + return pthread_mutex_lock((pthread_mutex_t*)mutex); +} + +int thread_mutex_unlock(thread_mutex_t* mutex) +{ + return pthread_mutex_unlock((pthread_mutex_t*)mutex); } #endif