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