libresman

view 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
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 pthread_mutex_t done_lock;
18 };
20 struct resman {
21 struct resource **res;
22 struct thread_pool *tpool;
24 resman_load_func load_func;
25 resman_done_func done_func;
26 resman_destroy_func destroy_func;
28 void *load_func_cls;
29 void *done_func_cls;
30 void *destroy_func_cls;
31 };
34 static int find_resource(struct resman *rman, const char *fname);
35 static int add_resource(struct resman *rman, const char *fname, void *data);
36 static void work_func(void *data, void *cls);
38 struct resman *resman_create(void)
39 {
40 struct resman *rman = malloc(sizeof *rman);
41 if(resman_init(rman) == -1) {
42 free(rman);
43 return 0;
44 }
45 return rman;
46 }
48 void resman_free(struct resman *rman)
49 {
50 resman_destroy(rman);
51 free(rman);
52 }
54 int resman_init(struct resman *rman)
55 {
56 memset(rman, 0, sizeof *rman);
58 if(!(rman->tpool = tpool_create(TPOOL_AUTO))) {
59 return -1;
60 }
61 tpool_set_work_func(rman->tpool, work_func, rman);
63 if(!(rman->res = dynarr_alloc(0, sizeof *rman->res))) {
64 tpool_free(rman->tpool);
65 return -1;
66 }
68 return 0;
69 }
71 void resman_destroy(struct resman *rman)
72 {
73 int i;
74 if(!rman) return;
76 for(i=0; i<dynarr_size(rman->res); i++) {
77 if(rman->destroy_func) {
78 rman->destroy_func(i, rman->destroy_func_cls);
79 }
80 free(rman->res[i]);
81 }
82 dynarr_free(rman->res);
84 tpool_free(rman->tpool);
85 }
88 void resman_set_load_func(struct resman *rman, resman_load_func func, void *cls)
89 {
90 rman->load_func = func;
91 rman->load_func_cls = cls;
92 }
94 void resman_set_done_func(struct resman *rman, resman_done_func func, void *cls)
95 {
96 rman->done_func = func;
97 rman->done_func_cls = cls;
98 }
100 void resman_set_destroy_func(struct resman *rman, resman_destroy_func func, void *cls)
101 {
102 rman->destroy_func = func;
103 rman->destroy_func_cls = cls;
104 }
106 int resman_lookup(struct resman *rman, const char *fname, void *data)
107 {
108 int ridx;
110 if((ridx = find_resource(rman, fname)) != -1) {
111 return ridx;
112 }
114 /* resource not found, create a new one and start a loading job */
115 return add_resource(rman, fname, data);
116 }
118 void resman_wait(struct resman *rman, int id)
119 {
120 /* TODO */
121 }
123 int resman_poll(struct resman *rman)
124 {
125 int i, num_res;
127 if(!rman->done_func) {
128 return 0; /* no done callback; there's no point in checking anything */
129 }
131 num_res = dynarr_size(rman->res);
132 for(i=0; i<num_res; i++) {
133 struct resource *res = rman->res[i];
135 printf("locking mutex %d\n", res->id);
136 pthread_mutex_lock(&res->done_lock);
137 if(!res->done_pending) {
138 printf(" unlocking mutex %d\n", res->id);
139 pthread_mutex_unlock(&res->done_lock);
140 continue;
141 }
143 /* so a done callback *is* pending... */
144 res->done_pending = 0;
145 rman->done_func(i, rman->done_func_cls);
146 printf(" unlocking mutex %d\n", res->id);
147 pthread_mutex_unlock(&res->done_lock);
148 }
149 return 0;
150 }
152 const char *resman_get_res_name(struct resman *rman, int res_id)
153 {
154 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
155 return rman->res[res_id]->name;
156 }
157 return 0;
158 }
160 void resman_set_res_data(struct resman *rman, int res_id, void *data)
161 {
162 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
163 rman->res[res_id]->data = data;
164 }
165 }
167 void *resman_get_res_data(struct resman *rman, int res_id)
168 {
169 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
170 return rman->res[res_id]->data;
171 }
172 return 0;
173 }
175 int resman_get_res_result(struct resman *rman, int res_id)
176 {
177 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
178 return rman->res[res_id]->result;
179 }
180 return -1;
181 }
183 static int find_resource(struct resman *rman, const char *fname)
184 {
185 int i, sz = dynarr_size(rman->res);
187 for(i=0; i<sz; i++) {
188 if(strcmp(rman->res[i]->name, fname) == 0) {
189 return i;
190 }
191 }
192 return -1;
193 }
195 static int add_resource(struct resman *rman, const char *fname, void *data)
196 {
197 int idx = dynarr_size(rman->res);
198 struct resource *res;
199 struct resource **tmparr;
201 if(!(res = malloc(sizeof *res))) {
202 return -1;
203 }
204 res->id = idx;
205 res->name = strdup(fname);
206 assert(res->name);
207 res->data = data;
209 pthread_mutex_init(&res->done_lock, 0);
211 if(!(tmparr = dynarr_push(rman->res, &res))) {
212 free(res);
213 return -1;
214 }
215 rman->res = tmparr;
217 /* start a loading job ... */
218 tpool_add_work(rman->tpool, rman->res[idx]);
219 return idx;
220 }
222 /* this is the background work function which handles all the
223 * first-stage resource loading...
224 */
225 static void work_func(void *data, void *cls)
226 {
227 struct resource *res = data;
228 struct resman *rman = cls;
230 res->result = rman->load_func(res->name, res->id, rman->load_func_cls);
232 printf("locking mutex %d\n", res->id);
233 pthread_mutex_lock(&res->done_lock);
234 res->done_pending = 1;
235 printf(" unlocking mutex %d\n", res->id);
236 pthread_mutex_unlock(&res->done_lock);
237 }