libresman

annotate src/resman.c @ 12:84f55eab27cb

ok now it sortof works, probably something is failing in the done callback mechanism
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 08 Feb 2014 04:21:08 +0200
parents bebc065a941f
children a42888d26839
rev   line source
nuclear@5 1 #include <stdio.h>
nuclear@5 2 #include <stdlib.h>
nuclear@5 3 #include <string.h>
nuclear@5 4 #include <assert.h>
nuclear@10 5 #include <pthread.h>
nuclear@5 6 #include "resman.h"
nuclear@5 7 #include "dynarr.h"
nuclear@5 8 #include "threadpool.h"
nuclear@5 9
nuclear@5 10 struct resource {
nuclear@11 11 int id;
nuclear@5 12 char *name;
nuclear@5 13 void *data;
nuclear@10 14 int result; /* last callback-reported success/fail code */
nuclear@10 15
nuclear@10 16 int done_pending;
nuclear@10 17 pthread_mutex_t done_lock;
nuclear@5 18 };
nuclear@5 19
nuclear@5 20 struct resman {
nuclear@11 21 struct resource **res;
nuclear@10 22 struct thread_pool *tpool;
nuclear@5 23
nuclear@5 24 resman_load_func load_func;
nuclear@10 25 resman_done_func done_func;
nuclear@5 26 resman_destroy_func destroy_func;
nuclear@5 27
nuclear@5 28 void *load_func_cls;
nuclear@10 29 void *done_func_cls;
nuclear@5 30 void *destroy_func_cls;
nuclear@5 31 };
nuclear@5 32
nuclear@5 33
nuclear@5 34 static int find_resource(struct resman *rman, const char *fname);
nuclear@5 35 static int add_resource(struct resman *rman, const char *fname, void *data);
nuclear@10 36 static void work_func(void *data, void *cls);
nuclear@5 37
nuclear@5 38 struct resman *resman_create(void)
nuclear@5 39 {
nuclear@5 40 struct resman *rman = malloc(sizeof *rman);
nuclear@5 41 if(resman_init(rman) == -1) {
nuclear@5 42 free(rman);
nuclear@5 43 return 0;
nuclear@5 44 }
nuclear@5 45 return rman;
nuclear@5 46 }
nuclear@5 47
nuclear@5 48 void resman_free(struct resman *rman)
nuclear@5 49 {
nuclear@5 50 resman_destroy(rman);
nuclear@5 51 free(rman);
nuclear@5 52 }
nuclear@5 53
nuclear@5 54 int resman_init(struct resman *rman)
nuclear@5 55 {
nuclear@5 56 memset(rman, 0, sizeof *rman);
nuclear@5 57
nuclear@10 58 if(!(rman->tpool = tpool_create(TPOOL_AUTO))) {
nuclear@10 59 return -1;
nuclear@10 60 }
nuclear@10 61 tpool_set_work_func(rman->tpool, work_func, rman);
nuclear@10 62
nuclear@5 63 if(!(rman->res = dynarr_alloc(0, sizeof *rman->res))) {
nuclear@10 64 tpool_free(rman->tpool);
nuclear@5 65 return -1;
nuclear@5 66 }
nuclear@5 67
nuclear@5 68 return 0;
nuclear@5 69 }
nuclear@5 70
nuclear@5 71 void resman_destroy(struct resman *rman)
nuclear@5 72 {
nuclear@5 73 int i;
nuclear@5 74 if(!rman) return;
nuclear@5 75
nuclear@5 76 for(i=0; i<dynarr_size(rman->res); i++) {
nuclear@5 77 if(rman->destroy_func) {
nuclear@11 78 rman->destroy_func(i, rman->destroy_func_cls);
nuclear@5 79 }
nuclear@11 80 free(rman->res[i]);
nuclear@5 81 }
nuclear@5 82 dynarr_free(rman->res);
nuclear@10 83
nuclear@10 84 tpool_free(rman->tpool);
nuclear@5 85 }
nuclear@5 86
nuclear@5 87
nuclear@5 88 void resman_set_load_func(struct resman *rman, resman_load_func func, void *cls)
nuclear@5 89 {
nuclear@5 90 rman->load_func = func;
nuclear@5 91 rman->load_func_cls = cls;
nuclear@5 92 }
nuclear@5 93
nuclear@10 94 void resman_set_done_func(struct resman *rman, resman_done_func func, void *cls)
nuclear@5 95 {
nuclear@10 96 rman->done_func = func;
nuclear@10 97 rman->done_func_cls = cls;
nuclear@5 98 }
nuclear@5 99
nuclear@5 100 void resman_set_destroy_func(struct resman *rman, resman_destroy_func func, void *cls)
nuclear@5 101 {
nuclear@5 102 rman->destroy_func = func;
nuclear@5 103 rman->destroy_func_cls = cls;
nuclear@5 104 }
nuclear@5 105
nuclear@5 106 int resman_lookup(struct resman *rman, const char *fname, void *data)
nuclear@5 107 {
nuclear@5 108 int ridx;
nuclear@5 109
nuclear@5 110 if((ridx = find_resource(rman, fname)) != -1) {
nuclear@5 111 return ridx;
nuclear@5 112 }
nuclear@5 113
nuclear@5 114 /* resource not found, create a new one and start a loading job */
nuclear@5 115 return add_resource(rman, fname, data);
nuclear@5 116 }
nuclear@5 117
nuclear@5 118 void resman_wait(struct resman *rman, int id)
nuclear@5 119 {
nuclear@5 120 /* TODO */
nuclear@5 121 }
nuclear@5 122
nuclear@5 123 int resman_poll(struct resman *rman)
nuclear@5 124 {
nuclear@10 125 int i, num_res;
nuclear@10 126
nuclear@10 127 if(!rman->done_func) {
nuclear@10 128 return 0; /* no done callback; there's no point in checking anything */
nuclear@10 129 }
nuclear@10 130
nuclear@10 131 num_res = dynarr_size(rman->res);
nuclear@10 132 for(i=0; i<num_res; i++) {
nuclear@11 133 struct resource *res = rman->res[i];
nuclear@10 134
nuclear@12 135 printf("locking mutex %d\n", res->id);
nuclear@10 136 pthread_mutex_lock(&res->done_lock);
nuclear@10 137 if(!res->done_pending) {
nuclear@12 138 printf(" unlocking mutex %d\n", res->id);
nuclear@10 139 pthread_mutex_unlock(&res->done_lock);
nuclear@10 140 continue;
nuclear@10 141 }
nuclear@10 142
nuclear@10 143 /* so a done callback *is* pending... */
nuclear@10 144 res->done_pending = 0;
nuclear@11 145 rman->done_func(i, rman->done_func_cls);
nuclear@12 146 printf(" unlocking mutex %d\n", res->id);
nuclear@10 147 pthread_mutex_unlock(&res->done_lock);
nuclear@10 148 }
nuclear@5 149 return 0;
nuclear@5 150 }
nuclear@5 151
nuclear@11 152 const char *resman_get_res_name(struct resman *rman, int res_id)
nuclear@11 153 {
nuclear@11 154 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 155 return rman->res[res_id]->name;
nuclear@11 156 }
nuclear@11 157 return 0;
nuclear@11 158 }
nuclear@5 159
nuclear@5 160 void resman_set_res_data(struct resman *rman, int res_id, void *data)
nuclear@5 161 {
nuclear@5 162 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 163 rman->res[res_id]->data = data;
nuclear@5 164 }
nuclear@5 165 }
nuclear@5 166
nuclear@5 167 void *resman_get_res_data(struct resman *rman, int res_id)
nuclear@5 168 {
nuclear@5 169 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 170 return rman->res[res_id]->data;
nuclear@5 171 }
nuclear@5 172 return 0;
nuclear@5 173 }
nuclear@5 174
nuclear@11 175 int resman_get_res_result(struct resman *rman, int res_id)
nuclear@10 176 {
nuclear@10 177 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 178 return rman->res[res_id]->result;
nuclear@10 179 }
nuclear@10 180 return -1;
nuclear@10 181 }
nuclear@10 182
nuclear@5 183 static int find_resource(struct resman *rman, const char *fname)
nuclear@5 184 {
nuclear@5 185 int i, sz = dynarr_size(rman->res);
nuclear@5 186
nuclear@5 187 for(i=0; i<sz; i++) {
nuclear@11 188 if(strcmp(rman->res[i]->name, fname) == 0) {
nuclear@5 189 return i;
nuclear@5 190 }
nuclear@5 191 }
nuclear@5 192 return -1;
nuclear@5 193 }
nuclear@5 194
nuclear@5 195 static int add_resource(struct resman *rman, const char *fname, void *data)
nuclear@5 196 {
nuclear@5 197 int idx = dynarr_size(rman->res);
nuclear@11 198 struct resource *res;
nuclear@11 199 struct resource **tmparr;
nuclear@5 200
nuclear@11 201 if(!(res = malloc(sizeof *res))) {
nuclear@5 202 return -1;
nuclear@5 203 }
nuclear@11 204 res->id = idx;
nuclear@11 205 res->name = strdup(fname);
nuclear@11 206 assert(res->name);
nuclear@11 207 res->data = data;
nuclear@5 208
nuclear@12 209 pthread_mutex_init(&res->done_lock, 0);
nuclear@12 210
nuclear@11 211 if(!(tmparr = dynarr_push(rman->res, &res))) {
nuclear@11 212 free(res);
nuclear@11 213 return -1;
nuclear@11 214 }
nuclear@11 215 rman->res = tmparr;
nuclear@5 216
nuclear@10 217 /* start a loading job ... */
nuclear@11 218 tpool_add_work(rman->tpool, rman->res[idx]);
nuclear@5 219 return idx;
nuclear@5 220 }
nuclear@10 221
nuclear@10 222 /* this is the background work function which handles all the
nuclear@10 223 * first-stage resource loading...
nuclear@10 224 */
nuclear@10 225 static void work_func(void *data, void *cls)
nuclear@10 226 {
nuclear@10 227 struct resource *res = data;
nuclear@10 228 struct resman *rman = cls;
nuclear@10 229
nuclear@11 230 res->result = rman->load_func(res->name, res->id, rman->load_func_cls);
nuclear@12 231
nuclear@12 232 printf("locking mutex %d\n", res->id);
nuclear@10 233 pthread_mutex_lock(&res->done_lock);
nuclear@10 234 res->done_pending = 1;
nuclear@12 235 printf(" unlocking mutex %d\n", res->id);
nuclear@10 236 pthread_mutex_unlock(&res->done_lock);
nuclear@10 237 }