libresman
view src/resman.c @ 10:4d18498a0078
moved the resource manager a bit further
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 05 Feb 2014 02:01:49 +0200 |
parents | bd9b4ff19c93 |
children | bebc065a941f |
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 char *name;
12 void *data;
13 int result; /* last callback-reported success/fail code */
15 int done_pending;
16 pthread_mutex_t done_lock;
17 };
19 struct resman {
20 struct resource *res;
21 struct thread_pool *tpool;
23 resman_load_func load_func;
24 resman_done_func done_func;
25 resman_destroy_func destroy_func;
27 void *load_func_cls;
28 void *done_func_cls;
29 void *destroy_func_cls;
30 };
33 static int find_resource(struct resman *rman, const char *fname);
34 static int add_resource(struct resman *rman, const char *fname, void *data);
35 static void work_func(void *data, void *cls);
37 struct resman *resman_create(void)
38 {
39 struct resman *rman = malloc(sizeof *rman);
40 if(resman_init(rman) == -1) {
41 free(rman);
42 return 0;
43 }
44 return rman;
45 }
47 void resman_free(struct resman *rman)
48 {
49 resman_destroy(rman);
50 free(rman);
51 }
53 int resman_init(struct resman *rman)
54 {
55 memset(rman, 0, sizeof *rman);
57 if(!(rman->tpool = tpool_create(TPOOL_AUTO))) {
58 return -1;
59 }
60 tpool_set_work_func(rman->tpool, work_func, rman);
62 if(!(rman->res = dynarr_alloc(0, sizeof *rman->res))) {
63 tpool_free(rman->tpool);
64 return -1;
65 }
67 return 0;
68 }
70 void resman_destroy(struct resman *rman)
71 {
72 int i;
73 if(!rman) return;
75 for(i=0; i<dynarr_size(rman->res); i++) {
76 if(rman->destroy_func) {
77 rman->destroy_func(rman->res[i].data, rman->destroy_func_cls);
78 }
79 }
80 dynarr_free(rman->res);
82 tpool_free(rman->tpool);
83 }
86 void resman_set_load_func(struct resman *rman, resman_load_func func, void *cls)
87 {
88 rman->load_func = func;
89 rman->load_func_cls = cls;
90 }
92 void resman_set_done_func(struct resman *rman, resman_done_func func, void *cls)
93 {
94 rman->done_func = func;
95 rman->done_func_cls = cls;
96 }
98 void resman_set_destroy_func(struct resman *rman, resman_destroy_func func, void *cls)
99 {
100 rman->destroy_func = func;
101 rman->destroy_func_cls = cls;
102 }
104 int resman_lookup(struct resman *rman, const char *fname, void *data)
105 {
106 int ridx;
108 if((ridx = find_resource(rman, fname)) != -1) {
109 return ridx;
110 }
112 /* resource not found, create a new one and start a loading job */
113 return add_resource(rman, fname, data);
114 }
116 void resman_wait(struct resman *rman, int id)
117 {
118 /* TODO */
119 }
121 int resman_poll(struct resman *rman)
122 {
123 int i, num_res;
125 if(!rman->done_func) {
126 return 0; /* no done callback; there's no point in checking anything */
127 }
129 num_res = dynarr_size(rman->res);
130 for(i=0; i<num_res; i++) {
131 struct resource *res = rman->res + i;
132 int last_result;
134 pthread_mutex_lock(&res->done_lock);
135 if(!res->done_pending) {
136 pthread_mutex_unlock(&res->done_lock);
137 continue;
138 }
140 /* so a done callback *is* pending... */
141 res->done_pending = 0;
142 last_result = res->result;
143 pthread_mutex_unlock(&res->done_lock);
145 rman->done_func(last_result, res->data, rman->done_func_cls);
146 }
147 return 0;
148 }
151 void resman_set_res_data(struct resman *rman, int res_id, void *data)
152 {
153 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
154 rman->res[res_id].data = data;
155 }
156 }
158 void *resman_get_res_data(struct resman *rman, int res_id)
159 {
160 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
161 return rman->res[res_id].data;
162 }
163 return 0;
164 }
166 int resman_get_res_error(struct resman *rman, int res_id)
167 {
168 if(res_id >= 0 && res_id < dynarr_size(rman->res)) {
169 return rman->res[res_id].result;
170 }
171 return -1;
172 }
174 static int find_resource(struct resman *rman, const char *fname)
175 {
176 int i, sz = dynarr_size(rman->res);
178 for(i=0; i<sz; i++) {
179 if(strcmp(rman->res[i].name, fname) == 0) {
180 return i;
181 }
182 }
183 return -1;
184 }
186 static int add_resource(struct resman *rman, const char *fname, void *data)
187 {
188 int idx = dynarr_size(rman->res);
190 struct resource *tmp = dynarr_push(rman->res, 0);
191 if(!tmp) {
192 return -1;
193 }
194 rman->res = tmp;
196 rman->res[idx].name = strdup(fname);
197 assert(rman->res[idx].name);
199 rman->res[idx].data = data;
201 /* start a loading job ... */
202 tpool_add_work(rman->tpool, rman->res + idx);
204 return idx;
205 }
207 /* this is the background work function which handles all the
208 * first-stage resource loading...
209 */
210 static void work_func(void *data, void *cls)
211 {
212 struct resource *res = data;
213 struct resman *rman = cls;
215 res->result = rman->load_func(res->name, res->data, rman->load_func_cls);
216 pthread_mutex_lock(&res->done_lock);
217 res->done_pending = 1;
218 pthread_mutex_unlock(&res->done_lock);
219 }