libresman

annotate src/resman.c @ 10:4d18498a0078

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