libresman
changeset 21:fe0dbdfbe403
file modification monitoring and reload done on linux
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 12 Feb 2014 22:05:28 +0200 |
parents | c6073bf9fd38 |
children | 174ddb6bf92a |
files | examples/imgthumbs/src/thumbs.c examples/imgthumbs/src/thumbs.h resman.def src/rbtree.c src/rbtree.h src/resman.c src/resman.h src/threadpool.c |
diffstat | 8 files changed, 784 insertions(+), 33 deletions(-) [+] |
line diff
1.1 --- a/examples/imgthumbs/src/thumbs.c Wed Feb 12 16:02:12 2014 +0200 1.2 +++ b/examples/imgthumbs/src/thumbs.c Wed Feb 12 22:05:28 2014 +0200 1.3 @@ -22,6 +22,11 @@ 1.4 struct dirent *dent; 1.5 /* allocate dummy head node */ 1.6 struct thumbnail *list = calloc(1, sizeof *list); 1.7 + char *env; 1.8 + 1.9 + if((env = getenv("RESMAN_LOAD_ASYNC"))) { 1.10 + dbg_load_async = atoi(env); 1.11 + } 1.12 1.13 if(!texman) { 1.14 texman = resman_create(); 1.15 @@ -85,6 +90,7 @@ 1.16 list->next = node; 1.17 } 1.18 node->list = list; 1.19 + node->load_count = 0; 1.20 } 1.21 closedir(dir); 1.22 1.23 @@ -243,11 +249,13 @@ 1.24 thumb->img->width, thumb->img->height, 0, img_glfmt(thumb->img), 1.25 img_gltype(thumb->img), thumb->img->pixels); 1.26 1.27 - /* and add it to the list of thumbnails */ 1.28 - thumb->prev = thumb->list; 1.29 - thumb->next = thumb->list->next; 1.30 - if(thumb->list->next) thumb->list->next->prev = thumb; 1.31 - thumb->list->next = thumb; 1.32 + /* and add it to the list of thumbnails (if it's the first loading) */ 1.33 + if(resman_get_res_load_count(texman, id) == 0) { 1.34 + thumb->prev = thumb->list; 1.35 + thumb->next = thumb->list->next; 1.36 + if(thumb->list->next) thumb->list->next->prev = thumb; 1.37 + thumb->list->next = thumb; 1.38 + } 1.39 return 0; 1.40 } 1.41
2.1 --- a/examples/imgthumbs/src/thumbs.h Wed Feb 12 16:02:12 2014 +0200 2.2 +++ b/examples/imgthumbs/src/thumbs.h Wed Feb 12 22:05:28 2014 +0200 2.3 @@ -15,6 +15,8 @@ 2.4 2.5 struct thumbnail *next, *prev; 2.6 struct thumbnail *list; /* pointer to the list this thumbnail belongs to */ 2.7 + 2.8 + int load_count; 2.9 }; 2.10 2.11 struct thumbnail *create_thumbs(const char *dirpath);
3.1 --- a/resman.def Wed Feb 12 16:02:12 2014 +0200 3.2 +++ b/resman.def Wed Feb 12 22:05:28 2014 +0200 3.3 @@ -18,4 +18,5 @@ 3.4 resman_get_res_name 3.5 resman_set_res_data 3.6 resman_get_res_data 3.7 - resman_get_res_result 3.8 \ No newline at end of file 3.9 + resman_get_res_result 3.10 + resman_get_res_load_count
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/rbtree.c Wed Feb 12 22:05:28 2014 +0200 4.3 @@ -0,0 +1,494 @@ 4.4 +#include <stdio.h> 4.5 +#include <stdlib.h> 4.6 +#include <stdint.h> 4.7 +#include <string.h> 4.8 +#include "rbtree.h" 4.9 + 4.10 +#define INT2PTR(x) ((void*)(intptr_t)(x)) 4.11 +#define PTR2INT(x) ((int)(intptr_t)(x)) 4.12 + 4.13 +struct rbtree { 4.14 + struct rbnode *root; 4.15 + 4.16 + rb_alloc_func_t alloc; 4.17 + rb_free_func_t free; 4.18 + 4.19 + rb_cmp_func_t cmp; 4.20 + rb_del_func_t del; 4.21 + void *del_cls; 4.22 + 4.23 + struct rbnode *rstack, *iter; 4.24 +}; 4.25 + 4.26 +static int cmpaddr(const void *ap, const void *bp); 4.27 +static int cmpint(const void *ap, const void *bp); 4.28 + 4.29 +static int count_nodes(struct rbnode *node); 4.30 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls); 4.31 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data); 4.32 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key); 4.33 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/ 4.34 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls); 4.35 + 4.36 +struct rbtree *rb_create(rb_cmp_func_t cmp_func) 4.37 +{ 4.38 + struct rbtree *rb; 4.39 + 4.40 + if(!(rb = malloc(sizeof *rb))) { 4.41 + return 0; 4.42 + } 4.43 + if(rb_init(rb, cmp_func) == -1) { 4.44 + free(rb); 4.45 + return 0; 4.46 + } 4.47 + return rb; 4.48 +} 4.49 + 4.50 +void rb_free(struct rbtree *rb) 4.51 +{ 4.52 + rb_destroy(rb); 4.53 + free(rb); 4.54 +} 4.55 + 4.56 + 4.57 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func) 4.58 +{ 4.59 + memset(rb, 0, sizeof *rb); 4.60 + 4.61 + if(cmp_func == RB_KEY_INT) { 4.62 + rb->cmp = cmpint; 4.63 + } else if(cmp_func == RB_KEY_STRING) { 4.64 + rb->cmp = (rb_cmp_func_t)strcmp; 4.65 + } else { 4.66 + rb->cmp = cmpaddr; 4.67 + } 4.68 + 4.69 + rb->alloc = malloc; 4.70 + rb->free = free; 4.71 + return 0; 4.72 +} 4.73 + 4.74 +void rb_destroy(struct rbtree *rb) 4.75 +{ 4.76 + del_tree(rb->root, rb->del, rb->del_cls); 4.77 +} 4.78 + 4.79 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free) 4.80 +{ 4.81 + rb->alloc = alloc; 4.82 + rb->free = free; 4.83 +} 4.84 + 4.85 + 4.86 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func) 4.87 +{ 4.88 + rb->cmp = func; 4.89 +} 4.90 + 4.91 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls) 4.92 +{ 4.93 + rb->del = func; 4.94 + rb->del_cls = cls; 4.95 +} 4.96 + 4.97 + 4.98 +void rb_clear(struct rbtree *rb) 4.99 +{ 4.100 + del_tree(rb->root, rb->del, rb->del_cls); 4.101 + rb->root = 0; 4.102 +} 4.103 + 4.104 +int rb_copy(struct rbtree *dest, struct rbtree *src) 4.105 +{ 4.106 + struct rbnode *node; 4.107 + 4.108 + rb_clear(dest); 4.109 + rb_begin(src); 4.110 + while((node = rb_next(src))) { 4.111 + if(rb_insert(dest, node->key, node->data) == -1) { 4.112 + return -1; 4.113 + } 4.114 + } 4.115 + return 0; 4.116 +} 4.117 + 4.118 +int rb_size(struct rbtree *rb) 4.119 +{ 4.120 + return count_nodes(rb->root); 4.121 +} 4.122 + 4.123 +int rb_insert(struct rbtree *rb, void *key, void *data) 4.124 +{ 4.125 + rb->root = insert(rb, rb->root, key, data); 4.126 + rb->root->red = 0; 4.127 + return 0; 4.128 +} 4.129 + 4.130 +int rb_inserti(struct rbtree *rb, int key, void *data) 4.131 +{ 4.132 + rb->root = insert(rb, rb->root, INT2PTR(key), data); 4.133 + rb->root->red = 0; 4.134 + return 0; 4.135 +} 4.136 + 4.137 + 4.138 +int rb_delete(struct rbtree *rb, void *key) 4.139 +{ 4.140 + rb->root = delete(rb, rb->root, key); 4.141 + rb->root->red = 0; 4.142 + return 0; 4.143 +} 4.144 + 4.145 +int rb_deletei(struct rbtree *rb, int key) 4.146 +{ 4.147 + rb->root = delete(rb, rb->root, INT2PTR(key)); 4.148 + rb->root->red = 0; 4.149 + return 0; 4.150 +} 4.151 + 4.152 + 4.153 +void *rb_find(struct rbtree *rb, void *key) 4.154 +{ 4.155 + struct rbnode *node = rb->root; 4.156 + 4.157 + while(node) { 4.158 + int cmp = rb->cmp(key, node->key); 4.159 + if(cmp == 0) { 4.160 + return node->data; 4.161 + } 4.162 + node = cmp < 0 ? node->left : node->right; 4.163 + } 4.164 + return 0; 4.165 +} 4.166 + 4.167 +void *rb_findi(struct rbtree *rb, int key) 4.168 +{ 4.169 + return rb_find(rb, INT2PTR(key)); 4.170 +} 4.171 + 4.172 + 4.173 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls) 4.174 +{ 4.175 + traverse(rb->root, func, cls); 4.176 +} 4.177 + 4.178 + 4.179 +struct rbnode *rb_root(struct rbtree *rb) 4.180 +{ 4.181 + return rb->root; 4.182 +} 4.183 + 4.184 +void rb_begin(struct rbtree *rb) 4.185 +{ 4.186 + rb->rstack = 0; 4.187 + rb->iter = rb->root; 4.188 +} 4.189 + 4.190 +#define push(sp, x) ((x)->next = (sp), (sp) = (x)) 4.191 +#define pop(sp) ((sp) = (sp)->next) 4.192 +#define top(sp) (sp) 4.193 + 4.194 +struct rbnode *rb_next(struct rbtree *rb) 4.195 +{ 4.196 + struct rbnode *res = 0; 4.197 + 4.198 + while(rb->rstack || rb->iter) { 4.199 + if(rb->iter) { 4.200 + push(rb->rstack, rb->iter); 4.201 + rb->iter = rb->iter->left; 4.202 + } else { 4.203 + rb->iter = top(rb->rstack); 4.204 + pop(rb->rstack); 4.205 + res = rb->iter; 4.206 + rb->iter = rb->iter->right; 4.207 + break; 4.208 + } 4.209 + } 4.210 + return res; 4.211 +} 4.212 + 4.213 +void *rb_node_key(struct rbnode *node) 4.214 +{ 4.215 + return node ? node->key : 0; 4.216 +} 4.217 + 4.218 +int rb_node_keyi(struct rbnode *node) 4.219 +{ 4.220 + return node ? PTR2INT(node->key) : 0; 4.221 +} 4.222 + 4.223 +void *rb_node_data(struct rbnode *node) 4.224 +{ 4.225 + return node ? node->data : 0; 4.226 +} 4.227 + 4.228 +static int cmpaddr(const void *ap, const void *bp) 4.229 +{ 4.230 + return ap < bp ? -1 : (ap > bp ? 1 : 0); 4.231 +} 4.232 + 4.233 +static int cmpint(const void *ap, const void *bp) 4.234 +{ 4.235 + return PTR2INT(ap) - PTR2INT(bp); 4.236 +} 4.237 + 4.238 + 4.239 +/* ---- left-leaning 2-3 red-black implementation ---- */ 4.240 + 4.241 +/* helper prototypes */ 4.242 +static int is_red(struct rbnode *tree); 4.243 +static void color_flip(struct rbnode *tree); 4.244 +static struct rbnode *rot_left(struct rbnode *a); 4.245 +static struct rbnode *rot_right(struct rbnode *a); 4.246 +static struct rbnode *find_min(struct rbnode *tree); 4.247 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree); 4.248 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/ 4.249 +static struct rbnode *move_red_left(struct rbnode *tree); 4.250 +static struct rbnode *fix_up(struct rbnode *tree); 4.251 + 4.252 +static int count_nodes(struct rbnode *node) 4.253 +{ 4.254 + if(!node) 4.255 + return 0; 4.256 + 4.257 + return 1 + count_nodes(node->left) + count_nodes(node->right); 4.258 +} 4.259 + 4.260 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls) 4.261 +{ 4.262 + if(!node) 4.263 + return; 4.264 + 4.265 + del_tree(node->left, delfunc, cls); 4.266 + del_tree(node->right, delfunc, cls); 4.267 + 4.268 + if(delfunc) { 4.269 + delfunc(node, cls); 4.270 + } 4.271 + free(node); 4.272 +} 4.273 + 4.274 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data) 4.275 +{ 4.276 + int cmp; 4.277 + 4.278 + if(!tree) { 4.279 + struct rbnode *node = rb->alloc(sizeof *node); 4.280 + node->red = 1; 4.281 + node->key = key; 4.282 + node->data = data; 4.283 + node->left = node->right = 0; 4.284 + return node; 4.285 + } 4.286 + 4.287 + cmp = rb->cmp(key, tree->key); 4.288 + 4.289 + if(cmp < 0) { 4.290 + tree->left = insert(rb, tree->left, key, data); 4.291 + } else if(cmp > 0) { 4.292 + tree->right = insert(rb, tree->right, key, data); 4.293 + } else { 4.294 + tree->data = data; 4.295 + } 4.296 + 4.297 + /* fix right-leaning reds */ 4.298 + if(is_red(tree->right)) { 4.299 + tree = rot_left(tree); 4.300 + } 4.301 + /* fix two reds in a row */ 4.302 + if(is_red(tree->left) && is_red(tree->left->left)) { 4.303 + tree = rot_right(tree); 4.304 + } 4.305 + 4.306 + /* if 4-node, split it by color inversion */ 4.307 + if(is_red(tree->left) && is_red(tree->right)) { 4.308 + color_flip(tree); 4.309 + } 4.310 + 4.311 + return tree; 4.312 +} 4.313 + 4.314 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key) 4.315 +{ 4.316 + int cmp; 4.317 + 4.318 + if(!tree) { 4.319 + return 0; 4.320 + } 4.321 + 4.322 + cmp = rb->cmp(key, tree->key); 4.323 + 4.324 + if(cmp < 0) { 4.325 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 4.326 + tree = move_red_left(tree); 4.327 + } 4.328 + tree->left = delete(rb, tree->left, key); 4.329 + } else { 4.330 + /* need reds on the right */ 4.331 + if(is_red(tree->left)) { 4.332 + tree = rot_right(tree); 4.333 + } 4.334 + 4.335 + /* found it at the bottom (XXX what certifies left is null?) */ 4.336 + if(cmp == 0 && !tree->right) { 4.337 + if(rb->del) { 4.338 + rb->del(tree, rb->del_cls); 4.339 + } 4.340 + rb->free(tree); 4.341 + return 0; 4.342 + } 4.343 + 4.344 + if(!is_red(tree->right) && !is_red(tree->right->left)) { 4.345 + tree = move_red_left(tree); 4.346 + } 4.347 + 4.348 + if(key == tree->key) { 4.349 + struct rbnode *rmin = find_min(tree->right); 4.350 + tree->key = rmin->key; 4.351 + tree->data = rmin->data; 4.352 + tree->right = del_min(rb, tree->right); 4.353 + } else { 4.354 + tree->right = delete(rb, tree->right, key); 4.355 + } 4.356 + } 4.357 + 4.358 + return fix_up(tree); 4.359 +} 4.360 + 4.361 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key) 4.362 +{ 4.363 + int cmp; 4.364 + 4.365 + if(!node) 4.366 + return 0; 4.367 + 4.368 + if((cmp = rb->cmp(key, node->key)) == 0) { 4.369 + return node; 4.370 + } 4.371 + return find(rb, cmp < 0 ? node->left : node->right, key); 4.372 +}*/ 4.373 + 4.374 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls) 4.375 +{ 4.376 + if(!node) 4.377 + return; 4.378 + 4.379 + traverse(node->left, func, cls); 4.380 + func(node, cls); 4.381 + traverse(node->right, func, cls); 4.382 +} 4.383 + 4.384 +/* helpers */ 4.385 + 4.386 +static int is_red(struct rbnode *tree) 4.387 +{ 4.388 + return tree && tree->red; 4.389 +} 4.390 + 4.391 +static void color_flip(struct rbnode *tree) 4.392 +{ 4.393 + tree->red = !tree->red; 4.394 + tree->left->red = !tree->left->red; 4.395 + tree->right->red = !tree->right->red; 4.396 +} 4.397 + 4.398 +static struct rbnode *rot_left(struct rbnode *a) 4.399 +{ 4.400 + struct rbnode *b = a->right; 4.401 + a->right = b->left; 4.402 + b->left = a; 4.403 + b->red = a->red; 4.404 + a->red = 1; 4.405 + return b; 4.406 +} 4.407 + 4.408 +static struct rbnode *rot_right(struct rbnode *a) 4.409 +{ 4.410 + struct rbnode *b = a->left; 4.411 + a->left = b->right; 4.412 + b->right = a; 4.413 + b->red = a->red; 4.414 + a->red = 1; 4.415 + return b; 4.416 +} 4.417 + 4.418 +static struct rbnode *find_min(struct rbnode *tree) 4.419 +{ 4.420 + struct rbnode *node; 4.421 + 4.422 + if(!tree) 4.423 + return 0; 4.424 + 4.425 + while(node->left) { 4.426 + node = node->left; 4.427 + } 4.428 + return node; 4.429 +} 4.430 + 4.431 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree) 4.432 +{ 4.433 + if(!tree->left) { 4.434 + if(rb->del) { 4.435 + rb->del(tree->left, rb->del_cls); 4.436 + } 4.437 + rb->free(tree->left); 4.438 + return 0; 4.439 + } 4.440 + 4.441 + /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */ 4.442 + if(!is_red(tree->left) && !is_red(tree->left->left)) { 4.443 + tree = move_red_left(tree); 4.444 + } 4.445 + tree->left = del_min(rb, tree->left); 4.446 + 4.447 + /* fix right-reds, red-reds, and split 4-nodes on the way up */ 4.448 + return fix_up(tree); 4.449 +} 4.450 + 4.451 +#if 0 4.452 +/* push a red link on this node to the right */ 4.453 +static struct rbnode *move_red_right(struct rbnode *tree) 4.454 +{ 4.455 + /* flipping it makes both children go red, so we have a red to the right */ 4.456 + color_flip(tree); 4.457 + 4.458 + /* if after the flip we've got a red-red situation to the left, fix it */ 4.459 + if(is_red(tree->left->left)) { 4.460 + tree = rot_right(tree); 4.461 + color_flip(tree); 4.462 + } 4.463 + return tree; 4.464 +} 4.465 +#endif 4.466 + 4.467 +/* push a red link on this node to the left */ 4.468 +static struct rbnode *move_red_left(struct rbnode *tree) 4.469 +{ 4.470 + /* flipping it makes both children go red, so we have a red to the left */ 4.471 + color_flip(tree); 4.472 + 4.473 + /* if after the flip we've got a red-red on the right-left, fix it */ 4.474 + if(is_red(tree->right->left)) { 4.475 + tree->right = rot_right(tree->right); 4.476 + tree = rot_left(tree); 4.477 + color_flip(tree); 4.478 + } 4.479 + return tree; 4.480 +} 4.481 + 4.482 +static struct rbnode *fix_up(struct rbnode *tree) 4.483 +{ 4.484 + /* fix right-leaning */ 4.485 + if(is_red(tree->right)) { 4.486 + tree = rot_left(tree); 4.487 + } 4.488 + /* change invalid red-red pairs into a proper 4-node */ 4.489 + if(is_red(tree->left) && is_red(tree->left->left)) { 4.490 + tree = rot_right(tree); 4.491 + } 4.492 + /* split 4-nodes */ 4.493 + if(is_red(tree->left) && is_red(tree->right)) { 4.494 + color_flip(tree); 4.495 + } 4.496 + return tree; 4.497 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/rbtree.h Wed Feb 12 22:05:28 2014 +0200 5.3 @@ -0,0 +1,71 @@ 5.4 +#ifndef RBTREE_H_ 5.5 +#define RBTREE_H_ 5.6 + 5.7 +struct rbtree; 5.8 + 5.9 + 5.10 +struct rbnode { 5.11 + void *key, *data; 5.12 + int red; 5.13 + struct rbnode *left, *right; 5.14 + struct rbnode *next; /* for iterator stack */ 5.15 +}; 5.16 + 5.17 + 5.18 +typedef void *(*rb_alloc_func_t)(size_t); 5.19 +typedef void (*rb_free_func_t)(void*); 5.20 + 5.21 +typedef int (*rb_cmp_func_t)(const void*, const void*); 5.22 +typedef void (*rb_del_func_t)(struct rbnode*, void*); 5.23 + 5.24 +#define RB_KEY_ADDR (rb_cmp_func_t)(0) 5.25 +#define RB_KEY_INT (rb_cmp_func_t)(1) 5.26 +#define RB_KEY_STRING (rb_cmp_func_t)(3) 5.27 + 5.28 + 5.29 +#ifdef __cplusplus 5.30 +extern "C" { 5.31 +#endif 5.32 + 5.33 +struct rbtree *rb_create(rb_cmp_func_t cmp_func); 5.34 +void rb_free(struct rbtree *rb); 5.35 + 5.36 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func); 5.37 +void rb_destroy(struct rbtree *rb); 5.38 + 5.39 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free); 5.40 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func); 5.41 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls); 5.42 +/* TODO add user deep copy function */ 5.43 + 5.44 +void rb_clear(struct rbtree *rb); 5.45 +int rb_copy(struct rbtree *dest, struct rbtree *src); 5.46 + 5.47 +int rb_size(struct rbtree *rb); 5.48 + 5.49 +int rb_insert(struct rbtree *rb, void *key, void *data); 5.50 +int rb_inserti(struct rbtree *rb, int key, void *data); 5.51 + 5.52 +int rb_delete(struct rbtree *rb, void *key); 5.53 +int rb_deletei(struct rbtree *rb, int key); 5.54 + 5.55 +void *rb_find(struct rbtree *rb, void *key); 5.56 +void *rb_findi(struct rbtree *rb, int key); 5.57 + 5.58 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls); 5.59 + 5.60 +struct rbnode *rb_root(struct rbtree *rb); 5.61 + 5.62 +void rb_begin(struct rbtree *rb); 5.63 +struct rbnode *rb_next(struct rbtree *rb); 5.64 + 5.65 +void *rb_node_key(struct rbnode *node); 5.66 +int rb_node_keyi(struct rbnode *node); 5.67 +void *rb_node_data(struct rbnode *node); 5.68 + 5.69 +#ifdef __cplusplus 5.70 +} 5.71 +#endif 5.72 + 5.73 + 5.74 +#endif /* RBTREE_H_ */
6.1 --- a/src/resman.c Wed Feb 12 16:02:12 2014 +0200 6.2 +++ b/src/resman.c Wed Feb 12 22:05:28 2014 +0200 6.3 @@ -5,8 +5,15 @@ 6.4 #include <pthread.h> 6.5 #include "resman.h" 6.6 #include "dynarr.h" 6.7 +#include "rbtree.h" 6.8 #include "threadpool.h" 6.9 6.10 +#ifdef __linux__ 6.11 +#include <unistd.h> 6.12 +#include <fcntl.h> 6.13 +#include <sys/inotify.h> 6.14 +#endif 6.15 + 6.16 struct resource { 6.17 int id; 6.18 char *name; 6.19 @@ -15,7 +22,17 @@ 6.20 6.21 int done_pending; 6.22 int delete_pending; 6.23 - pthread_mutex_t done_lock; 6.24 + pthread_mutex_t lock; 6.25 + 6.26 + int num_loads; /* number of loads up to now */ 6.27 + 6.28 + /* file change monitoring */ 6.29 +#ifdef __WIN32__ 6.30 + HANDLE nhandle; 6.31 +#endif 6.32 +#ifdef __linux__ 6.33 + int nfd; 6.34 +#endif 6.35 }; 6.36 6.37 struct resman { 6.38 @@ -31,6 +48,13 @@ 6.39 void *load_func_cls; 6.40 void *done_func_cls; 6.41 void *destroy_func_cls; 6.42 + 6.43 + /* file change monitoring */ 6.44 + struct rbtree *nresmap; 6.45 + struct rbtree *modset; 6.46 +#ifdef __linux__ 6.47 + int inotify_fd; 6.48 +#endif 6.49 }; 6.50 6.51 6.52 @@ -39,6 +63,15 @@ 6.53 static void remove_resource(struct resman *rman, int idx); 6.54 static void work_func(void *data, void *cls); 6.55 6.56 +/* file modification watching */ 6.57 +static int init_file_monitor(struct resman *rman); 6.58 +static void destroy_file_monitor(struct resman *rman); 6.59 +static int start_watch(struct resman *rman, struct resource *res); 6.60 +static void stop_watch(struct resman *rman, struct resource *res); 6.61 +static void check_watch(struct resman *rman); 6.62 +static void reload_modified(struct rbnode *node, void *cls); 6.63 + 6.64 + 6.65 struct resman *resman_create(void) 6.66 { 6.67 struct resman *rman = malloc(sizeof *rman); 6.68 @@ -66,6 +99,10 @@ 6.69 num_threads = atoi(env); 6.70 } 6.71 6.72 + if(init_file_monitor(rman) == -1) { 6.73 + return -1; 6.74 + } 6.75 + 6.76 if(!(rman->tpool = tpool_create(num_threads))) { 6.77 return -1; 6.78 } 6.79 @@ -96,6 +133,8 @@ 6.80 6.81 tpool_free(rman->tpool); 6.82 6.83 + destroy_file_monitor(rman); 6.84 + 6.85 pthread_mutex_destroy(&rman->lock); 6.86 } 6.87 6.88 @@ -156,6 +195,10 @@ 6.89 } 6.90 6.91 6.92 + /* then check for modified files */ 6.93 + check_watch(rman); 6.94 + 6.95 + 6.96 if(!rman->done_func) { 6.97 return 0; /* no done callback; there's no point in checking anything */ 6.98 } 6.99 @@ -166,21 +209,29 @@ 6.100 continue; 6.101 } 6.102 6.103 - pthread_mutex_lock(&res->done_lock); 6.104 + pthread_mutex_lock(&res->lock); 6.105 if(!res->done_pending) { 6.106 - pthread_mutex_unlock(&res->done_lock); 6.107 + pthread_mutex_unlock(&res->lock); 6.108 continue; 6.109 } 6.110 6.111 /* so a done callback *is* pending... */ 6.112 res->done_pending = 0; 6.113 if(rman->done_func(i, rman->done_func_cls) == -1) { 6.114 - /* done-func returned -1, so let's remove the resource */ 6.115 - pthread_mutex_unlock(&res->done_lock); 6.116 - remove_resource(rman, i); 6.117 - continue; 6.118 + /* done-func returned -1, so let's remove the resource 6.119 + * but only if this was the first load. Otherwise keep it 6.120 + * around in case it gets valid again... 6.121 + */ 6.122 + if(res->num_loads == 0) { 6.123 + pthread_mutex_unlock(&res->lock); 6.124 + remove_resource(rman, i); 6.125 + continue; 6.126 + } 6.127 } 6.128 - pthread_mutex_unlock(&res->done_lock); 6.129 + res->num_loads++; 6.130 + 6.131 + start_watch(rman, res); /* start watching the file for modifications */ 6.132 + pthread_mutex_unlock(&res->lock); 6.133 } 6.134 return 0; 6.135 } 6.136 @@ -216,6 +267,14 @@ 6.137 return -1; 6.138 } 6.139 6.140 +int resman_get_res_load_count(struct resman *rman, int res_id) 6.141 +{ 6.142 + if(res_id >= 0 && res_id < dynarr_size(rman->res)) { 6.143 + return rman->res[res_id]->num_loads; 6.144 + } 6.145 + return -1; 6.146 +} 6.147 + 6.148 static int find_resource(struct resman *rman, const char *fname) 6.149 { 6.150 int i, sz = dynarr_size(rman->res); 6.151 @@ -243,8 +302,7 @@ 6.152 res->name = strdup(fname); 6.153 assert(res->name); 6.154 res->data = data; 6.155 - pthread_mutex_init(&res->done_lock, 0); 6.156 - 6.157 + pthread_mutex_init(&res->lock, 0); 6.158 6.159 /* check to see if there's an emtpy (previously erased) slot */ 6.160 for(i=0; i<size; i++) { 6.161 @@ -278,11 +336,13 @@ 6.162 /* remove a resource and leave the pointer null to reuse the slot */ 6.163 static void remove_resource(struct resman *rman, int idx) 6.164 { 6.165 + stop_watch(rman, rman->res[idx]); 6.166 + 6.167 if(rman->destroy_func) { 6.168 rman->destroy_func(idx, rman->destroy_func_cls); 6.169 } 6.170 6.171 - pthread_mutex_destroy(&rman->res[idx]->done_lock); 6.172 + pthread_mutex_destroy(&rman->res[idx]->lock); 6.173 6.174 free(rman->res[idx]); 6.175 rman->res[idx] = 0; 6.176 @@ -296,16 +356,124 @@ 6.177 struct resource *res = data; 6.178 struct resman *rman = cls; 6.179 6.180 + pthread_mutex_lock(&res->lock); 6.181 + 6.182 res->result = rman->load_func(res->name, res->id, rman->load_func_cls); 6.183 - if(res->result == -1 && !rman->done_func) { 6.184 - /* if there's no done function and we got an error, mark this 6.185 - * resource for deletion in the caller context 6.186 - */ 6.187 - res->delete_pending = 1; 6.188 + if(!rman->done_func) { 6.189 + if(res->result == -1) { 6.190 + /* if there's no done function and we got an error, mark this 6.191 + * resource for deletion in the caller context. But only if this 6.192 + * is the first load of this resource. 6.193 + */ 6.194 + if(res->num_loads == 0) { 6.195 + res->delete_pending = 1; 6.196 + } 6.197 + } else { 6.198 + /* succeded, start a watch */ 6.199 + if(res->nfd <= 0) { 6.200 + start_watch(rman, res); 6.201 + } 6.202 + } 6.203 + } else { 6.204 + /* if we have a done_func, mark this resource as done */ 6.205 + res->done_pending = 1; 6.206 + } 6.207 + pthread_mutex_unlock(&res->lock); 6.208 +} 6.209 + 6.210 +static int init_file_monitor(struct resman *rman) 6.211 +{ 6.212 + int fd; 6.213 + 6.214 + if((fd = inotify_init()) == -1) { 6.215 + return -1; 6.216 + } 6.217 + /* set non-blocking flag, to allow polling by reading */ 6.218 + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); 6.219 + rman->inotify_fd = fd; 6.220 + 6.221 + /* create the fd->resource map */ 6.222 + rman->nresmap = rb_create(RB_KEY_INT); 6.223 + /* create the modified set */ 6.224 + rman->modset = rb_create(RB_KEY_INT); 6.225 + return 0; 6.226 +} 6.227 + 6.228 +static void destroy_file_monitor(struct resman *rman) 6.229 +{ 6.230 + rb_free(rman->nresmap); 6.231 + rb_free(rman->modset); 6.232 + 6.233 + if(rman->inotify_fd >= 0) { 6.234 + close(rman->inotify_fd); 6.235 + rman->inotify_fd = -1; 6.236 + } 6.237 +} 6.238 + 6.239 +static int start_watch(struct resman *rman, struct resource *res) 6.240 +{ 6.241 + int fd; 6.242 + 6.243 + if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) { 6.244 + return -1; 6.245 + } 6.246 + printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd); 6.247 + rb_inserti(rman->nresmap, fd, res); 6.248 + 6.249 + res->nfd = fd; 6.250 + return 0; 6.251 +} 6.252 + 6.253 +static void stop_watch(struct resman *rman, struct resource *res) 6.254 +{ 6.255 + if(res->nfd > 0) { 6.256 + rb_deletei(rman->nresmap, res->nfd); 6.257 + inotify_rm_watch(rman->inotify_fd, res->nfd); 6.258 + } 6.259 +} 6.260 + 6.261 +static void check_watch(struct resman *rman) 6.262 +{ 6.263 + char buf[512]; 6.264 + struct inotify_event *ev; 6.265 + int sz, evsize; 6.266 + 6.267 + while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) { 6.268 + ev = (struct inotify_event*)buf; 6.269 + while(sz > 0) { 6.270 + if(ev->mask & IN_MODIFY) { 6.271 + /* add the file descriptor to the modified set */ 6.272 + rb_inserti(rman->modset, ev->wd, 0); 6.273 + } 6.274 + 6.275 + evsize = sizeof *ev + ev->len; 6.276 + sz -= evsize; 6.277 + ev += evsize; 6.278 + } 6.279 + } 6.280 + 6.281 + /* for each item in the modified set, start a new job to reload it */ 6.282 + rb_foreach(rman->modset, reload_modified, rman); 6.283 + rb_clear(rman->modset); 6.284 +} 6.285 + 6.286 +/* this is called for each item in the modified set (see above) */ 6.287 +static void reload_modified(struct rbnode *node, void *cls) 6.288 +{ 6.289 + int watch_fd; 6.290 + struct resource *res; 6.291 + struct resman *rman = cls; 6.292 + 6.293 + watch_fd = rb_node_keyi(node); 6.294 + 6.295 + if(!(res = rb_findi(rman->nresmap, watch_fd))) { 6.296 + fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n", 6.297 + __FUNCTION__, watch_fd); 6.298 return; 6.299 } 6.300 + assert(watch_fd == res->nfd); 6.301 6.302 - pthread_mutex_lock(&res->done_lock); 6.303 - res->done_pending = 1; 6.304 - pthread_mutex_unlock(&res->done_lock); 6.305 + printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node)); 6.306 + 6.307 + tpool_add_work(rman->tpool, res); 6.308 }
7.1 --- a/src/resman.h Wed Feb 12 16:02:12 2014 +0200 7.2 +++ b/src/resman.h Wed Feb 12 22:05:28 2014 +0200 7.3 @@ -37,6 +37,8 @@ 7.4 7.5 int resman_get_res_result(struct resman *rman, int res_id); 7.6 7.7 +int resman_get_res_load_count(struct resman *rman, int res_id); 7.8 + 7.9 #ifdef __cplusplus 7.10 } 7.11 #endif
8.1 --- a/src/threadpool.c Wed Feb 12 16:02:12 2014 +0200 8.2 +++ b/src/threadpool.c Wed Feb 12 22:05:28 2014 +0200 8.3 @@ -164,23 +164,28 @@ 8.4 } 8.5 } 8.6 8.7 - pthread_mutex_lock(&tpool->work_lock); 8.8 for(;;) { 8.9 + int job_id; 8.10 + void *data; 8.11 + 8.12 + pthread_mutex_lock(&tpool->work_lock); 8.13 /* while there aren't any work items to do go to sleep on the condvar */ 8.14 - pthread_cond_wait(&tpool->work_cond, &tpool->work_lock); 8.15 - if(!tpool->work_list) { 8.16 - continue; /* spurious wakeup, go back to sleep */ 8.17 + while(!tpool->work_list) { 8.18 + pthread_cond_wait(&tpool->work_cond, &tpool->work_lock); 8.19 } 8.20 8.21 job = tpool->work_list; 8.22 tpool->work_list = tpool->work_list->next; 8.23 8.24 - printf("TPOOL: worker %d start job: %d\n", tidx, job->id); 8.25 - tpool->work_func(job->data, tpool->cls); 8.26 - printf("TPOOL: worker %d completed job: %d\n", tidx, job->id); 8.27 + job_id = job->id; 8.28 + data = job->data; 8.29 free_node(job); 8.30 + pthread_mutex_unlock(&tpool->work_lock); 8.31 + 8.32 + printf("TPOOL: worker %d start job: %d\n", tidx, job_id); 8.33 + tpool->work_func(data, tpool->cls); 8.34 + printf("TPOOL: worker %d completed job: %d\n", tidx, job_id); 8.35 } 8.36 - pthread_mutex_unlock(&tpool->work_lock); 8.37 return 0; 8.38 } 8.39