libresman

annotate src/resman.c @ 14:2fcd1fbb0d18

buggy piece of shit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 10 Feb 2014 12:11:02 +0200
parents a42888d26839
children c6073bf9fd38
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@14 17 int delete_pending;
nuclear@10 18 pthread_mutex_t done_lock;
nuclear@5 19 };
nuclear@5 20
nuclear@5 21 struct resman {
nuclear@11 22 struct resource **res;
nuclear@10 23 struct thread_pool *tpool;
nuclear@5 24
nuclear@13 25 pthread_mutex_t lock; /* global resman lock (for res array changes) */
nuclear@13 26
nuclear@5 27 resman_load_func load_func;
nuclear@10 28 resman_done_func done_func;
nuclear@5 29 resman_destroy_func destroy_func;
nuclear@5 30
nuclear@5 31 void *load_func_cls;
nuclear@10 32 void *done_func_cls;
nuclear@5 33 void *destroy_func_cls;
nuclear@5 34 };
nuclear@5 35
nuclear@5 36
nuclear@5 37 static int find_resource(struct resman *rman, const char *fname);
nuclear@5 38 static int add_resource(struct resman *rman, const char *fname, void *data);
nuclear@13 39 static void remove_resource(struct resman *rman, int idx);
nuclear@10 40 static void work_func(void *data, void *cls);
nuclear@5 41
nuclear@5 42 struct resman *resman_create(void)
nuclear@5 43 {
nuclear@5 44 struct resman *rman = malloc(sizeof *rman);
nuclear@5 45 if(resman_init(rman) == -1) {
nuclear@5 46 free(rman);
nuclear@5 47 return 0;
nuclear@5 48 }
nuclear@5 49 return rman;
nuclear@5 50 }
nuclear@5 51
nuclear@5 52 void resman_free(struct resman *rman)
nuclear@5 53 {
nuclear@5 54 resman_destroy(rman);
nuclear@5 55 free(rman);
nuclear@5 56 }
nuclear@5 57
nuclear@5 58 int resman_init(struct resman *rman)
nuclear@5 59 {
nuclear@14 60 const char *env;
nuclear@14 61 int num_threads = TPOOL_AUTO;
nuclear@14 62
nuclear@5 63 memset(rman, 0, sizeof *rman);
nuclear@5 64
nuclear@14 65 if((env = getenv("RESMAN_THREADS"))) {
nuclear@14 66 num_threads = atoi(env);
nuclear@14 67 }
nuclear@14 68
nuclear@14 69 if(!(rman->tpool = tpool_create(num_threads))) {
nuclear@10 70 return -1;
nuclear@10 71 }
nuclear@10 72 tpool_set_work_func(rman->tpool, work_func, rman);
nuclear@10 73
nuclear@5 74 if(!(rman->res = dynarr_alloc(0, sizeof *rman->res))) {
nuclear@10 75 tpool_free(rman->tpool);
nuclear@5 76 return -1;
nuclear@5 77 }
nuclear@5 78
nuclear@13 79 pthread_mutex_init(&rman->lock, 0);
nuclear@13 80
nuclear@5 81 return 0;
nuclear@5 82 }
nuclear@5 83
nuclear@5 84 void resman_destroy(struct resman *rman)
nuclear@5 85 {
nuclear@5 86 int i;
nuclear@5 87 if(!rman) return;
nuclear@5 88
nuclear@5 89 for(i=0; i<dynarr_size(rman->res); i++) {
nuclear@5 90 if(rman->destroy_func) {
nuclear@11 91 rman->destroy_func(i, rman->destroy_func_cls);
nuclear@5 92 }
nuclear@11 93 free(rman->res[i]);
nuclear@5 94 }
nuclear@5 95 dynarr_free(rman->res);
nuclear@10 96
nuclear@10 97 tpool_free(rman->tpool);
nuclear@13 98
nuclear@13 99 pthread_mutex_destroy(&rman->lock);
nuclear@5 100 }
nuclear@5 101
nuclear@5 102
nuclear@5 103 void resman_set_load_func(struct resman *rman, resman_load_func func, void *cls)
nuclear@5 104 {
nuclear@5 105 rman->load_func = func;
nuclear@5 106 rman->load_func_cls = cls;
nuclear@5 107 }
nuclear@5 108
nuclear@10 109 void resman_set_done_func(struct resman *rman, resman_done_func func, void *cls)
nuclear@5 110 {
nuclear@10 111 rman->done_func = func;
nuclear@10 112 rman->done_func_cls = cls;
nuclear@5 113 }
nuclear@5 114
nuclear@5 115 void resman_set_destroy_func(struct resman *rman, resman_destroy_func func, void *cls)
nuclear@5 116 {
nuclear@5 117 rman->destroy_func = func;
nuclear@5 118 rman->destroy_func_cls = cls;
nuclear@5 119 }
nuclear@5 120
nuclear@5 121 int resman_lookup(struct resman *rman, const char *fname, void *data)
nuclear@5 122 {
nuclear@5 123 int ridx;
nuclear@5 124
nuclear@5 125 if((ridx = find_resource(rman, fname)) != -1) {
nuclear@5 126 return ridx;
nuclear@5 127 }
nuclear@5 128
nuclear@5 129 /* resource not found, create a new one and start a loading job */
nuclear@5 130 return add_resource(rman, fname, data);
nuclear@5 131 }
nuclear@5 132
nuclear@5 133 void resman_wait(struct resman *rman, int id)
nuclear@5 134 {
nuclear@5 135 /* TODO */
nuclear@5 136 }
nuclear@5 137
nuclear@5 138 int resman_poll(struct resman *rman)
nuclear@5 139 {
nuclear@10 140 int i, num_res;
nuclear@10 141
nuclear@14 142 /* first check all the resources to see if any is pending deletion */
nuclear@14 143 num_res = dynarr_size(rman->res);
nuclear@14 144 for(i=0; i<num_res; i++) {
nuclear@14 145 struct resource *res = rman->res[i];
nuclear@14 146 if(!res) {
nuclear@14 147 continue;
nuclear@14 148 }
nuclear@14 149
nuclear@14 150 if(res->delete_pending) {
nuclear@14 151 if(rman->destroy_func) {
nuclear@14 152 rman->destroy_func(i, rman->destroy_func_cls);
nuclear@14 153 }
nuclear@14 154 remove_resource(rman, i);
nuclear@14 155 }
nuclear@14 156 }
nuclear@14 157
nuclear@14 158
nuclear@10 159 if(!rman->done_func) {
nuclear@10 160 return 0; /* no done callback; there's no point in checking anything */
nuclear@10 161 }
nuclear@10 162
nuclear@10 163 for(i=0; i<num_res; i++) {
nuclear@11 164 struct resource *res = rman->res[i];
nuclear@13 165 if(!res) {
nuclear@13 166 continue;
nuclear@13 167 }
nuclear@10 168
nuclear@12 169 printf("locking mutex %d\n", res->id);
nuclear@10 170 pthread_mutex_lock(&res->done_lock);
nuclear@10 171 if(!res->done_pending) {
nuclear@12 172 printf(" unlocking mutex %d\n", res->id);
nuclear@10 173 pthread_mutex_unlock(&res->done_lock);
nuclear@10 174 continue;
nuclear@10 175 }
nuclear@10 176
nuclear@10 177 /* so a done callback *is* pending... */
nuclear@10 178 res->done_pending = 0;
nuclear@13 179 if(rman->done_func(i, rman->done_func_cls) == -1) {
nuclear@13 180 /* done-func returned -1, so let's remove the resource */
nuclear@13 181 printf(" unlocking mutex %d\n", res->id);
nuclear@13 182 pthread_mutex_unlock(&res->done_lock);
nuclear@13 183 remove_resource(rman, i);
nuclear@13 184 continue;
nuclear@13 185 }
nuclear@12 186 printf(" unlocking mutex %d\n", res->id);
nuclear@10 187 pthread_mutex_unlock(&res->done_lock);
nuclear@10 188 }
nuclear@5 189 return 0;
nuclear@5 190 }
nuclear@5 191
nuclear@11 192 const char *resman_get_res_name(struct resman *rman, int res_id)
nuclear@11 193 {
nuclear@11 194 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 195 return rman->res[res_id]->name;
nuclear@11 196 }
nuclear@11 197 return 0;
nuclear@11 198 }
nuclear@5 199
nuclear@5 200 void resman_set_res_data(struct resman *rman, int res_id, void *data)
nuclear@5 201 {
nuclear@5 202 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 203 rman->res[res_id]->data = data;
nuclear@5 204 }
nuclear@5 205 }
nuclear@5 206
nuclear@5 207 void *resman_get_res_data(struct resman *rman, int res_id)
nuclear@5 208 {
nuclear@5 209 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 210 return rman->res[res_id]->data;
nuclear@5 211 }
nuclear@5 212 return 0;
nuclear@5 213 }
nuclear@5 214
nuclear@11 215 int resman_get_res_result(struct resman *rman, int res_id)
nuclear@10 216 {
nuclear@10 217 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
nuclear@11 218 return rman->res[res_id]->result;
nuclear@10 219 }
nuclear@10 220 return -1;
nuclear@10 221 }
nuclear@10 222
nuclear@5 223 static int find_resource(struct resman *rman, const char *fname)
nuclear@5 224 {
nuclear@5 225 int i, sz = dynarr_size(rman->res);
nuclear@5 226
nuclear@5 227 for(i=0; i<sz; i++) {
nuclear@11 228 if(strcmp(rman->res[i]->name, fname) == 0) {
nuclear@5 229 return i;
nuclear@5 230 }
nuclear@5 231 }
nuclear@5 232 return -1;
nuclear@5 233 }
nuclear@5 234
nuclear@5 235 static int add_resource(struct resman *rman, const char *fname, void *data)
nuclear@5 236 {
nuclear@13 237 int i, idx = -1, size = dynarr_size(rman->res);
nuclear@11 238 struct resource *res;
nuclear@11 239 struct resource **tmparr;
nuclear@5 240
nuclear@13 241 /* allocate a new resource */
nuclear@11 242 if(!(res = malloc(sizeof *res))) {
nuclear@5 243 return -1;
nuclear@5 244 }
nuclear@13 245 memset(res, 0, sizeof *res);
nuclear@13 246
nuclear@11 247 res->name = strdup(fname);
nuclear@11 248 assert(res->name);
nuclear@11 249 res->data = data;
nuclear@12 250 pthread_mutex_init(&res->done_lock, 0);
nuclear@12 251
nuclear@13 252
nuclear@13 253 /* check to see if there's an emtpy (previously erased) slot */
nuclear@13 254 for(i=0; i<size; i++) {
nuclear@13 255 if(!rman->res[i]) {
nuclear@13 256 idx = i;
nuclear@13 257 break;
nuclear@13 258 }
nuclear@11 259 }
nuclear@13 260
nuclear@13 261 if(idx == -1) {
nuclear@13 262 /* free slot not found, append a new one */
nuclear@13 263 idx = size;
nuclear@13 264
nuclear@13 265 if(!(tmparr = dynarr_push(rman->res, &res))) {
nuclear@13 266 free(res);
nuclear@13 267 return -1;
nuclear@13 268 }
nuclear@13 269 rman->res = tmparr;
nuclear@13 270 } else {
nuclear@13 271 /* free slot found, just use it */
nuclear@13 272 res = rman->res[idx];
nuclear@13 273 }
nuclear@13 274
nuclear@13 275 res->id = idx; /* set the resource id */
nuclear@5 276
nuclear@10 277 /* start a loading job ... */
nuclear@11 278 tpool_add_work(rman->tpool, rman->res[idx]);
nuclear@5 279 return idx;
nuclear@5 280 }
nuclear@10 281
nuclear@13 282 /* remove a resource and leave the pointer null to reuse the slot */
nuclear@13 283 static void remove_resource(struct resman *rman, int idx)
nuclear@13 284 {
nuclear@13 285 if(rman->destroy_func) {
nuclear@13 286 rman->destroy_func(idx, rman->destroy_func_cls);
nuclear@13 287 }
nuclear@13 288
nuclear@13 289 pthread_mutex_destroy(&rman->res[idx]->done_lock);
nuclear@13 290
nuclear@13 291 free(rman->res[idx]);
nuclear@13 292 rman->res[idx] = 0;
nuclear@13 293 }
nuclear@13 294
nuclear@10 295 /* this is the background work function which handles all the
nuclear@10 296 * first-stage resource loading...
nuclear@10 297 */
nuclear@10 298 static void work_func(void *data, void *cls)
nuclear@10 299 {
nuclear@10 300 struct resource *res = data;
nuclear@10 301 struct resman *rman = cls;
nuclear@10 302
nuclear@11 303 res->result = rman->load_func(res->name, res->id, rman->load_func_cls);
nuclear@13 304 if(res->result == -1 && !rman->done_func) {
nuclear@14 305 /* if there's no done function and we got an error, mark this
nuclear@14 306 * resource for deletion in the caller context
nuclear@14 307 */
nuclear@14 308 res->delete_pending = 1;
nuclear@13 309 return;
nuclear@13 310 }
nuclear@12 311
nuclear@12 312 printf("locking mutex %d\n", res->id);
nuclear@10 313 pthread_mutex_lock(&res->done_lock);
nuclear@10 314 res->done_pending = 1;
nuclear@12 315 printf(" unlocking mutex %d\n", res->id);
nuclear@10 316 pthread_mutex_unlock(&res->done_lock);
nuclear@10 317 }