libresman

annotate src/resman.c @ 13:a42888d26839

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