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