/** @file */ #include #include #include #include "mythread.h" /** l'état statique de la bibliothèque */ static struct { mythread_list_t ready_list; mythread_list_t blocked_list; mythread_t current; } mythread; /* ********************************************************* */ /* quelques fonctions auxiliaires bien utiles */ static void _mythread_schedule(void) { if(mythread_list_empty(mythread.ready_list)) { fprintf(stderr, "deadlock!\n"); abort(); } mythread_t next = mythread_list_pop_front(mythread.ready_list); mythread_t prev = mythread_self(); mythread.current = next; next->status = active; if(prev) swapcontext(&prev->ucp, &next->ucp); else setcontext(&next->ucp); } static inline void _mythread_block(enum _mythread_status_e why, mythread_list_t chain) { mythread_t self = mythread_self(); self->status = why; mythread_list_push_back(chain, self); _mythread_schedule(); } static inline void _mythread_unblock(mythread_t t, mythread_list_t chain) { mythread_list_erase(chain, t); t->status = ready; mythread_list_push_back(mythread.ready_list, t); } /* ********************************************************* */ /* la gestion du démarrage */ struct _mythread_args_s { int argc; char**argv; }; static void* _mythread_main(void*_args) { struct _mythread_args_s*args = (struct _mythread_args_s*)_args; int rc = mythread_main(args->argc, args->argv); exit(rc); } void mythread_init(int argc, char**argv) { mythread_t main_thread; struct _mythread_args_s args = { .argc = argc, .argv = argv }; mythread.ready_list = mythread_list_new(); mythread.blocked_list = mythread_list_new(); mythread.current = NULL; mythread_create(&main_thread, NULL, &_mythread_main, &args); _mythread_schedule(); } int main(int argc, char**argv) { mythread_init(argc, argv); return 0; } /* ********************************************************* */ /* création et destruction d'un thread */ mythread_t mythread_self(void) { return mythread.current; } void mythread_yield(void) { _mythread_block(ready, mythread.ready_list); } static void _mythread_starter_stub(mythread_func_t f, void*arg) { void*result = (*f)(arg); mythread_t self = mythread_self(); self->result = result; if(self->joining && self->joining->status == wait_join) { _mythread_unblock(self->joining, mythread.blocked_list); } _mythread_block(terminated, mythread.blocked_list); } int mythread_create(mythread_t*tid, const mythread_attr_t*attr, mythread_func_t start_routine, void*arg) { const size_t stack_size = MYTHREAD_STACK_SIZE; mythread_t t = mythread_new(); getcontext(&t->ucp); t->ucp.uc_stack.ss_size = stack_size; t->ucp.uc_stack.ss_sp = malloc(stack_size); t->ucp.uc_stack.ss_flags = 0; t->ucp.uc_link = NULL; makecontext(&t->ucp, (void*)&_mythread_starter_stub, 2, start_routine, arg); t->joining = NULL; t->status = ready; mythread_list_push_back(mythread.ready_list, t); if(tid) *tid = t; return 0; } int mythread_join(mythread_t t, void**result) { t->joining = mythread_self(); while(t->status != terminated) { _mythread_block(wait_join, mythread.blocked_list); } if(result) *result = t->result; free(t->ucp.uc_stack.ss_sp); mythread_list_erase(mythread.blocked_list, t); mythread_delete(t); return 0; } /* ********************************************************* */ /* gestion des mutexes */ int mythread_mutex_init(mythread_mutex_t*m, const mythread_mutexattr_t*attr) { m->count = 0; m->chain = mythread_list_new(); m->holder = NULL; return 0; } int mythread_mutex_destroy(mythread_mutex_t*m) { mythread_list_delete(m->chain); return 0; } int mythread_mutex_lock(mythread_mutex_t*m) { while(m->count) { _mythread_block(wait_mutex, m->chain); } m->count++; m->holder = mythread_self(); return 0; } int mythread_mutex_unlock(mythread_mutex_t*m) { m->count--; m->holder = NULL; if(!mythread_list_empty(m->chain)) { mythread_t t = mythread_list_front(m->chain); _mythread_unblock(t, m->chain); } return 0; } /* ********************************************************* */ /* gestion des conditions */ int mythread_cond_init(mythread_cond_t*c, mythread_condattr_t*attr) { c->chain = mythread_list_new(); return 0; } int mythread_cond_destroy(mythread_cond_t*c) { mythread_list_delete(c->chain); return 0; } int mythread_cond_signal(mythread_cond_t*c) { mythread_t t = mythread_list_front(c->chain); _mythread_unblock(t, c->chain); return 0; } int mythread_cond_broadcast(mythread_cond_t*c) { mythread_itor_t i; for(i = mythread_list_begin(c->chain); i != mythread_list_end(c->chain); i = mythread_list_next(i)) { _mythread_unblock(i, c->chain); } return 0; } int mythread_cond_wait(mythread_cond_t*c, mythread_mutex_t*m) { mythread_mutex_unlock(m); _mythread_block(wait_cond, c->chain); mythread_mutex_lock(m); return 0; }