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