libresman

changeset 13:a42888d26839

bit more progress...
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 08 Feb 2014 07:41:39 +0200
parents 84f55eab27cb
children 2fcd1fbb0d18 0a789208498d
files examples/imgthumbs/src/thumbs.c examples/imgthumbs/src/thumbs.h src/resman.c
diffstat 3 files changed, 93 insertions(+), 20 deletions(-) [+]
line diff
     1.1 --- a/examples/imgthumbs/src/thumbs.c	Sat Feb 08 04:21:08 2014 +0200
     1.2 +++ b/examples/imgthumbs/src/thumbs.c	Sat Feb 08 07:41:39 2014 +0200
     1.3 @@ -24,7 +24,8 @@
     1.4  {
     1.5  	DIR *dir;
     1.6  	struct dirent *dent;
     1.7 -	struct thumbnail *list = 0;
     1.8 +	/* allocate dummy head node */
     1.9 +	struct thumbnail *list = calloc(1, sizeof *list);
    1.10  
    1.11  	/*unsigned int intfmt = GL_COMPRESSED_RGB;
    1.12  	if(!strstr((char*)glGetString(GL_EXTENSIONS), "GL_ARB_texture_compression")) {
    1.13 @@ -85,8 +86,8 @@
    1.14  		img_free_pixels(pixels);
    1.15  		*/
    1.16  
    1.17 -		node->next = list;
    1.18 -		list = node;
    1.19 +		node->next = list->next;
    1.20 +		node->prev = list;
    1.21  	}
    1.22  	closedir(dir);
    1.23  
    1.24 @@ -130,6 +131,7 @@
    1.25  
    1.26  	glMatrixMode(GL_MODELVIEW);
    1.27  
    1.28 +	thumbs = thumbs->next;	/* skip dummy node */
    1.29  	while(thumbs) {
    1.30  		glPushMatrix();
    1.31  		glTranslatef(x, y, 0);
    1.32 @@ -204,6 +206,7 @@
    1.33  
    1.34  	if(img_load(rdata->img, fname) == -1) {
    1.35  		img_free(rdata->img);
    1.36 +		rdata->img = 0;
    1.37  		return -1;
    1.38  	}
    1.39  	rdata->aspect = (float)rdata->img->width / (float)rdata->img->height;
    1.40 @@ -216,9 +219,16 @@
    1.41  
    1.42  static int done_res_texture(int id, void *cls)
    1.43  {
    1.44 -	struct thumbnail *rdata;
    1.45 +	struct thumbnail *rdata = resman_get_res_data(texman, id);
    1.46 +	int load_result = resman_get_res_result(texman, id);
    1.47  
    1.48 -	rdata = resman_get_res_data(texman, id);
    1.49 +	if(load_result == -1) {
    1.50 +		/* returning -1 will remove this resource, the free_res_texture
    1.51 +		 * destroy handler will be called, which will remove the node
    1.52 +		 * from the list
    1.53 +		 */
    1.54 +		return -1;
    1.55 +	}
    1.56  
    1.57  	if(resman_get_res_result(texman, id) != 0 || !rdata) {
    1.58  		fprintf(stderr, "failed to load resource %d (%s)\n", id, resman_get_res_name(texman, id));
    1.59 @@ -240,14 +250,23 @@
    1.60  
    1.61  static void free_res_texture(int id, void *cls)
    1.62  {
    1.63 -	struct thumbnail *rdata = resman_get_res_data(texman, id);
    1.64 +	struct thumbnail *thumb = resman_get_res_data(texman, id);
    1.65  
    1.66 -	if(rdata) {
    1.67 -		if(rdata->tex) {
    1.68 -			glDeleteTextures(1, &rdata->tex);
    1.69 +	if(thumb) {
    1.70 +		if(thumb->tex) {
    1.71 +			glDeleteTextures(1, &thumb->tex);
    1.72  		}
    1.73 -		if(rdata->img) {
    1.74 -			img_free(rdata->img);
    1.75 +		if(thumb->img) {
    1.76 +			img_free(thumb->img);
    1.77  		}
    1.78  	}
    1.79 +
    1.80 +	/* remove from the list */
    1.81 +	if(thumb->prev) {
    1.82 +		thumb->prev->next = thumb->next;
    1.83 +	}
    1.84 +	if(thumb->next) {
    1.85 +		thumb->next->prev = thumb->prev;
    1.86 +	}
    1.87 +	free(thumb);
    1.88  }
     2.1 --- a/examples/imgthumbs/src/thumbs.h	Sat Feb 08 04:21:08 2014 +0200
     2.2 +++ b/examples/imgthumbs/src/thumbs.h	Sat Feb 08 07:41:39 2014 +0200
     2.3 @@ -13,7 +13,7 @@
     2.4  
     2.5  	struct img_pixmap *img;
     2.6  
     2.7 -	struct thumbnail *next;
     2.8 +	struct thumbnail *next, *prev;
     2.9  };
    2.10  
    2.11  struct thumbnail *create_thumbs(const char *dirpath);
     3.1 --- a/src/resman.c	Sat Feb 08 04:21:08 2014 +0200
     3.2 +++ b/src/resman.c	Sat Feb 08 07:41:39 2014 +0200
     3.3 @@ -21,6 +21,8 @@
     3.4  	struct resource **res;
     3.5  	struct thread_pool *tpool;
     3.6  
     3.7 +	pthread_mutex_t lock;	/* global resman lock (for res array changes) */
     3.8 +
     3.9  	resman_load_func load_func;
    3.10  	resman_done_func done_func;
    3.11  	resman_destroy_func destroy_func;
    3.12 @@ -33,6 +35,7 @@
    3.13  
    3.14  static int find_resource(struct resman *rman, const char *fname);
    3.15  static int add_resource(struct resman *rman, const char *fname, void *data);
    3.16 +static void remove_resource(struct resman *rman, int idx);
    3.17  static void work_func(void *data, void *cls);
    3.18  
    3.19  struct resman *resman_create(void)
    3.20 @@ -65,6 +68,8 @@
    3.21  		return -1;
    3.22  	}
    3.23  
    3.24 +	pthread_mutex_init(&rman->lock, 0);
    3.25 +
    3.26  	return 0;
    3.27  }
    3.28  
    3.29 @@ -82,6 +87,8 @@
    3.30  	dynarr_free(rman->res);
    3.31  
    3.32  	tpool_free(rman->tpool);
    3.33 +
    3.34 +	pthread_mutex_destroy(&rman->lock);
    3.35  }
    3.36  
    3.37  
    3.38 @@ -131,6 +138,9 @@
    3.39  	num_res = dynarr_size(rman->res);
    3.40  	for(i=0; i<num_res; i++) {
    3.41  		struct resource *res = rman->res[i];
    3.42 +		if(!res) {
    3.43 +			continue;
    3.44 +		}
    3.45  
    3.46  		printf("locking mutex %d\n", res->id);
    3.47  		pthread_mutex_lock(&res->done_lock);
    3.48 @@ -142,7 +152,13 @@
    3.49  
    3.50  		/* so a done callback *is* pending... */
    3.51  		res->done_pending = 0;
    3.52 -		rman->done_func(i, rman->done_func_cls);
    3.53 +		if(rman->done_func(i, rman->done_func_cls) == -1) {
    3.54 +			/* done-func returned -1, so let's remove the resource */
    3.55 +			printf("  unlocking mutex %d\n", res->id);
    3.56 +			pthread_mutex_unlock(&res->done_lock);
    3.57 +			remove_resource(rman, i);
    3.58 +			continue;
    3.59 +		}
    3.60  		printf("  unlocking mutex %d\n", res->id);
    3.61  		pthread_mutex_unlock(&res->done_lock);
    3.62  	}
    3.63 @@ -194,31 +210,64 @@
    3.64  
    3.65  static int add_resource(struct resman *rman, const char *fname, void *data)
    3.66  {
    3.67 -	int idx = dynarr_size(rman->res);
    3.68 +	int i, idx = -1, size = dynarr_size(rman->res);
    3.69  	struct resource *res;
    3.70  	struct resource **tmparr;
    3.71  
    3.72 +	/* allocate a new resource */
    3.73  	if(!(res = malloc(sizeof *res))) {
    3.74  		return -1;
    3.75  	}
    3.76 -	res->id = idx;
    3.77 +	memset(res, 0, sizeof *res);
    3.78 +
    3.79  	res->name = strdup(fname);
    3.80  	assert(res->name);
    3.81  	res->data = data;
    3.82 -
    3.83  	pthread_mutex_init(&res->done_lock, 0);
    3.84  
    3.85 -	if(!(tmparr = dynarr_push(rman->res, &res))) {
    3.86 -		free(res);
    3.87 -		return -1;
    3.88 +
    3.89 +	/* check to see if there's an emtpy (previously erased) slot */
    3.90 +	for(i=0; i<size; i++) {
    3.91 +		if(!rman->res[i]) {
    3.92 +			idx = i;
    3.93 +			break;
    3.94 +		}
    3.95  	}
    3.96 -	rman->res = tmparr;
    3.97 +
    3.98 +	if(idx == -1) {
    3.99 +		/* free slot not found, append a new one */
   3.100 +		idx = size;
   3.101 +
   3.102 +		if(!(tmparr = dynarr_push(rman->res, &res))) {
   3.103 +			free(res);
   3.104 +			return -1;
   3.105 +		}
   3.106 +		rman->res = tmparr;
   3.107 +	} else {
   3.108 +		/* free slot found, just use it */
   3.109 +		res = rman->res[idx];
   3.110 +	}
   3.111 +
   3.112 +	res->id = idx;	/* set the resource id */
   3.113  
   3.114  	/* start a loading job ... */
   3.115  	tpool_add_work(rman->tpool, rman->res[idx]);
   3.116  	return idx;
   3.117  }
   3.118  
   3.119 +/* remove a resource and leave the pointer null to reuse the slot */
   3.120 +static void remove_resource(struct resman *rman, int idx)
   3.121 +{
   3.122 +	if(rman->destroy_func) {
   3.123 +		rman->destroy_func(idx, rman->destroy_func_cls);
   3.124 +	}
   3.125 +
   3.126 +	pthread_mutex_destroy(&rman->res[idx]->done_lock);
   3.127 +
   3.128 +	free(rman->res[idx]);
   3.129 +	rman->res[idx] = 0;
   3.130 +}
   3.131 +
   3.132  /* this is the background work function which handles all the
   3.133   * first-stage resource loading...
   3.134   */
   3.135 @@ -228,6 +277,11 @@
   3.136  	struct resman *rman = cls;
   3.137  
   3.138  	res->result = rman->load_func(res->name, res->id, rman->load_func_cls);
   3.139 +	if(res->result == -1 && !rman->done_func) {
   3.140 +		/* if there's no done function and we got an error, remove the resource now */
   3.141 +		remove_resource(rman, res->id);
   3.142 +		return;
   3.143 +	}
   3.144  
   3.145  	printf("locking mutex %d\n", res->id);
   3.146  	pthread_mutex_lock(&res->done_lock);