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 }
|