nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@5: #include nuclear@10: #include nuclear@5: #include "resman.h" nuclear@5: #include "dynarr.h" nuclear@5: #include "threadpool.h" nuclear@5: nuclear@5: struct resource { nuclear@11: int id; nuclear@5: char *name; nuclear@5: void *data; nuclear@10: int result; /* last callback-reported success/fail code */ nuclear@10: nuclear@10: int done_pending; nuclear@10: pthread_mutex_t done_lock; nuclear@5: }; nuclear@5: nuclear@5: struct resman { nuclear@11: struct resource **res; nuclear@10: struct thread_pool *tpool; nuclear@5: nuclear@5: resman_load_func load_func; nuclear@10: resman_done_func done_func; nuclear@5: resman_destroy_func destroy_func; nuclear@5: nuclear@5: void *load_func_cls; nuclear@10: void *done_func_cls; nuclear@5: void *destroy_func_cls; nuclear@5: }; nuclear@5: nuclear@5: nuclear@5: static int find_resource(struct resman *rman, const char *fname); nuclear@5: static int add_resource(struct resman *rman, const char *fname, void *data); nuclear@10: static void work_func(void *data, void *cls); nuclear@5: nuclear@5: struct resman *resman_create(void) nuclear@5: { nuclear@5: struct resman *rman = malloc(sizeof *rman); nuclear@5: if(resman_init(rman) == -1) { nuclear@5: free(rman); nuclear@5: return 0; nuclear@5: } nuclear@5: return rman; nuclear@5: } nuclear@5: nuclear@5: void resman_free(struct resman *rman) nuclear@5: { nuclear@5: resman_destroy(rman); nuclear@5: free(rman); nuclear@5: } nuclear@5: nuclear@5: int resman_init(struct resman *rman) nuclear@5: { nuclear@5: memset(rman, 0, sizeof *rman); nuclear@5: nuclear@10: if(!(rman->tpool = tpool_create(TPOOL_AUTO))) { nuclear@10: return -1; nuclear@10: } nuclear@10: tpool_set_work_func(rman->tpool, work_func, rman); nuclear@10: nuclear@5: if(!(rman->res = dynarr_alloc(0, sizeof *rman->res))) { nuclear@10: tpool_free(rman->tpool); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@5: void resman_destroy(struct resman *rman) nuclear@5: { nuclear@5: int i; nuclear@5: if(!rman) return; nuclear@5: nuclear@5: for(i=0; ires); i++) { nuclear@5: if(rman->destroy_func) { nuclear@11: rman->destroy_func(i, rman->destroy_func_cls); nuclear@5: } nuclear@11: free(rman->res[i]); nuclear@5: } nuclear@5: dynarr_free(rman->res); nuclear@10: nuclear@10: tpool_free(rman->tpool); nuclear@5: } nuclear@5: nuclear@5: nuclear@5: void resman_set_load_func(struct resman *rman, resman_load_func func, void *cls) nuclear@5: { nuclear@5: rman->load_func = func; nuclear@5: rman->load_func_cls = cls; nuclear@5: } nuclear@5: nuclear@10: void resman_set_done_func(struct resman *rman, resman_done_func func, void *cls) nuclear@5: { nuclear@10: rman->done_func = func; nuclear@10: rman->done_func_cls = cls; nuclear@5: } nuclear@5: nuclear@5: void resman_set_destroy_func(struct resman *rman, resman_destroy_func func, void *cls) nuclear@5: { nuclear@5: rman->destroy_func = func; nuclear@5: rman->destroy_func_cls = cls; nuclear@5: } nuclear@5: nuclear@5: int resman_lookup(struct resman *rman, const char *fname, void *data) nuclear@5: { nuclear@5: int ridx; nuclear@5: nuclear@5: if((ridx = find_resource(rman, fname)) != -1) { nuclear@5: return ridx; nuclear@5: } nuclear@5: nuclear@5: /* resource not found, create a new one and start a loading job */ nuclear@5: return add_resource(rman, fname, data); nuclear@5: } nuclear@5: nuclear@5: void resman_wait(struct resman *rman, int id) nuclear@5: { nuclear@5: /* TODO */ nuclear@5: } nuclear@5: nuclear@5: int resman_poll(struct resman *rman) nuclear@5: { nuclear@10: int i, num_res; nuclear@10: nuclear@10: if(!rman->done_func) { nuclear@10: return 0; /* no done callback; there's no point in checking anything */ nuclear@10: } nuclear@10: nuclear@10: num_res = dynarr_size(rman->res); nuclear@10: for(i=0; ires[i]; nuclear@10: nuclear@12: printf("locking mutex %d\n", res->id); nuclear@10: pthread_mutex_lock(&res->done_lock); nuclear@10: if(!res->done_pending) { nuclear@12: printf(" unlocking mutex %d\n", res->id); nuclear@10: pthread_mutex_unlock(&res->done_lock); nuclear@10: continue; nuclear@10: } nuclear@10: nuclear@10: /* so a done callback *is* pending... */ nuclear@10: res->done_pending = 0; nuclear@11: rman->done_func(i, rman->done_func_cls); nuclear@12: printf(" unlocking mutex %d\n", res->id); nuclear@10: pthread_mutex_unlock(&res->done_lock); nuclear@10: } nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@11: const char *resman_get_res_name(struct resman *rman, int res_id) nuclear@11: { nuclear@11: if(res_id >= 0 && res_id < dynarr_size(rman->res)) { nuclear@11: return rman->res[res_id]->name; nuclear@11: } nuclear@11: return 0; nuclear@11: } nuclear@5: nuclear@5: void resman_set_res_data(struct resman *rman, int res_id, void *data) nuclear@5: { nuclear@5: if(res_id >= 0 && res_id < dynarr_size(rman->res)) { nuclear@11: rman->res[res_id]->data = data; nuclear@5: } nuclear@5: } nuclear@5: nuclear@5: void *resman_get_res_data(struct resman *rman, int res_id) nuclear@5: { nuclear@5: if(res_id >= 0 && res_id < dynarr_size(rman->res)) { nuclear@11: return rman->res[res_id]->data; nuclear@5: } nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@11: int resman_get_res_result(struct resman *rman, int res_id) nuclear@10: { nuclear@10: if(res_id >= 0 && res_id < dynarr_size(rman->res)) { nuclear@11: return rman->res[res_id]->result; nuclear@10: } nuclear@10: return -1; nuclear@10: } nuclear@10: nuclear@5: static int find_resource(struct resman *rman, const char *fname) nuclear@5: { nuclear@5: int i, sz = dynarr_size(rman->res); nuclear@5: nuclear@5: for(i=0; ires[i]->name, fname) == 0) { nuclear@5: return i; nuclear@5: } nuclear@5: } nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: static int add_resource(struct resman *rman, const char *fname, void *data) nuclear@5: { nuclear@5: int idx = dynarr_size(rman->res); nuclear@11: struct resource *res; nuclear@11: struct resource **tmparr; nuclear@5: nuclear@11: if(!(res = malloc(sizeof *res))) { nuclear@5: return -1; nuclear@5: } nuclear@11: res->id = idx; nuclear@11: res->name = strdup(fname); nuclear@11: assert(res->name); nuclear@11: res->data = data; nuclear@5: nuclear@12: pthread_mutex_init(&res->done_lock, 0); nuclear@12: nuclear@11: if(!(tmparr = dynarr_push(rman->res, &res))) { nuclear@11: free(res); nuclear@11: return -1; nuclear@11: } nuclear@11: rman->res = tmparr; nuclear@5: nuclear@10: /* start a loading job ... */ nuclear@11: tpool_add_work(rman->tpool, rman->res[idx]); nuclear@5: return idx; nuclear@5: } nuclear@10: nuclear@10: /* this is the background work function which handles all the nuclear@10: * first-stage resource loading... nuclear@10: */ nuclear@10: static void work_func(void *data, void *cls) nuclear@10: { nuclear@10: struct resource *res = data; nuclear@10: struct resman *rman = cls; nuclear@10: nuclear@11: res->result = rman->load_func(res->name, res->id, rman->load_func_cls); nuclear@12: nuclear@12: printf("locking mutex %d\n", res->id); nuclear@10: pthread_mutex_lock(&res->done_lock); nuclear@10: res->done_pending = 1; nuclear@12: printf(" unlocking mutex %d\n", res->id); nuclear@10: pthread_mutex_unlock(&res->done_lock); nuclear@10: }