libresman

changeset 22:174ddb6bf92a

separated platform-specific filewatch code
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 12 Feb 2014 22:32:30 +0200
parents fe0dbdfbe403
children f8e5a1491275
files src/filewatch.h src/filewatch_linux.c src/filewatch_win32.c src/resman.c src/resman_impl.h
diffstat 5 files changed, 308 insertions(+), 162 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/filewatch.h	Wed Feb 12 22:32:30 2014 +0200
     1.3 @@ -0,0 +1,15 @@
     1.4 +#ifndef FILEWATCH_H_
     1.5 +#define FILEWATCH_H_
     1.6 +
     1.7 +struct resman;
     1.8 +struct resource;
     1.9 +
    1.10 +int resman_init_file_monitor(struct resman *rman);
    1.11 +void resman_destroy_file_monitor(struct resman *rman);
    1.12 +
    1.13 +int resman_start_watch(struct resman *rman, struct resource *res);
    1.14 +void resman_stop_watch(struct resman *rman, struct resource *res);
    1.15 +
    1.16 +void resman_check_watch(struct resman *rman);
    1.17 +
    1.18 +#endif	/* FILEWATCH_H_ */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/filewatch_linux.c	Wed Feb 12 22:32:30 2014 +0200
     2.3 @@ -0,0 +1,113 @@
     2.4 +/* file modification monitoring with inotify */
     2.5 +#ifdef __linux__
     2.6 +#include <stdio.h>
     2.7 +#include <assert.h>
     2.8 +#include <unistd.h>
     2.9 +#include <fcntl.h>
    2.10 +#include <sys/inotify.h>
    2.11 +#include "filewatch.h"
    2.12 +#include "resman.h"
    2.13 +#include "resman_impl.h"
    2.14 +
    2.15 +static void reload_modified(struct rbnode *node, void *cls);
    2.16 +
    2.17 +int resman_init_file_monitor(struct resman *rman)
    2.18 +{
    2.19 +	int fd;
    2.20 +
    2.21 +	if((fd = inotify_init()) == -1) {
    2.22 +		return -1;
    2.23 +	}
    2.24 +	/* set non-blocking flag, to allow polling by reading */
    2.25 +	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
    2.26 +	rman->inotify_fd = fd;
    2.27 +
    2.28 +	/* create the fd->resource map */
    2.29 +	rman->nresmap = rb_create(RB_KEY_INT);
    2.30 +	/* create the modified set */
    2.31 +	rman->modset = rb_create(RB_KEY_INT);
    2.32 +	return 0;
    2.33 +}
    2.34 +
    2.35 +void resman_destroy_file_monitor(struct resman *rman)
    2.36 +{
    2.37 +	rb_free(rman->nresmap);
    2.38 +	rb_free(rman->modset);
    2.39 +
    2.40 +	if(rman->inotify_fd >= 0) {
    2.41 +		close(rman->inotify_fd);
    2.42 +		rman->inotify_fd = -1;
    2.43 +	}
    2.44 +}
    2.45 +
    2.46 +int resman_start_watch(struct resman *rman, struct resource *res)
    2.47 +{
    2.48 +	int fd;
    2.49 +
    2.50 +	if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) {
    2.51 +		return -1;
    2.52 +	}
    2.53 +	printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd);
    2.54 +	rb_inserti(rman->nresmap, fd, res);
    2.55 +
    2.56 +	res->nfd = fd;
    2.57 +	return 0;
    2.58 +}
    2.59 +
    2.60 +void resman_stop_watch(struct resman *rman, struct resource *res)
    2.61 +{
    2.62 +	if(res->nfd > 0) {
    2.63 +		rb_deletei(rman->nresmap, res->nfd);
    2.64 +		inotify_rm_watch(rman->inotify_fd, res->nfd);
    2.65 +	}
    2.66 +}
    2.67 +
    2.68 +void resman_check_watch(struct resman *rman)
    2.69 +{
    2.70 +	char buf[512];
    2.71 +	struct inotify_event *ev;
    2.72 +	int sz, evsize;
    2.73 +
    2.74 +	while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) {
    2.75 +		ev = (struct inotify_event*)buf;
    2.76 +		while(sz > 0) {
    2.77 +			if(ev->mask & IN_MODIFY) {
    2.78 +				/* add the file descriptor to the modified set */
    2.79 +				rb_inserti(rman->modset, ev->wd, 0);
    2.80 +			}
    2.81 +
    2.82 +			evsize = sizeof *ev + ev->len;
    2.83 +			sz -= evsize;
    2.84 +			ev += evsize;
    2.85 +		}
    2.86 +	}
    2.87 +
    2.88 +	/* for each item in the modified set, start a new job to reload it */
    2.89 +	rb_foreach(rman->modset, reload_modified, rman);
    2.90 +	rb_clear(rman->modset);
    2.91 +}
    2.92 +
    2.93 +/* this is called for each item in the modified set (see above) */
    2.94 +static void reload_modified(struct rbnode *node, void *cls)
    2.95 +{
    2.96 +	int watch_fd;
    2.97 +	struct resource *res;
    2.98 +	struct resman *rman = cls;
    2.99 +
   2.100 +	watch_fd = rb_node_keyi(node);
   2.101 +
   2.102 +	if(!(res = rb_findi(rman->nresmap, watch_fd))) {
   2.103 +		fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n",
   2.104 +				__FUNCTION__, watch_fd);
   2.105 +		return;
   2.106 +	}
   2.107 +	assert(watch_fd == res->nfd);
   2.108 +
   2.109 +	printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node));
   2.110 +
   2.111 +	tpool_add_work(rman->tpool, res);
   2.112 +}
   2.113 +
   2.114 +#else
   2.115 +int resman_filewatch_linux_silence_empty_file_warning;
   2.116 +#endif	/* __linux__ */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/filewatch_win32.c	Wed Feb 12 22:32:30 2014 +0200
     3.3 @@ -0,0 +1,113 @@
     3.4 +/* file modification monitoring for windows */
     3.5 +#ifdef WIN32
     3.6 +#include <stdio.h>
     3.7 +#include <assert.h>
     3.8 +#include <unistd.h>
     3.9 +#include <fcntl.h>
    3.10 +#include <sys/inotify.h>
    3.11 +#include "filewatch.h"
    3.12 +#include "resman.h"
    3.13 +#include "resman_impl.h"
    3.14 +
    3.15 +static void reload_modified(struct rbnode *node, void *cls);
    3.16 +
    3.17 +int resman_init_file_monitor(struct resman *rman)
    3.18 +{
    3.19 +	int fd;
    3.20 +
    3.21 +	if((fd = inotify_init()) == -1) {
    3.22 +		return -1;
    3.23 +	}
    3.24 +	/* set non-blocking flag, to allow polling by reading */
    3.25 +	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
    3.26 +	rman->inotify_fd = fd;
    3.27 +
    3.28 +	/* create the fd->resource map */
    3.29 +	rman->nresmap = rb_create(RB_KEY_INT);
    3.30 +	/* create the modified set */
    3.31 +	rman->modset = rb_create(RB_KEY_INT);
    3.32 +	return 0;
    3.33 +}
    3.34 +
    3.35 +void resman_destroy_file_monitor(struct resman *rman)
    3.36 +{
    3.37 +	rb_free(rman->nresmap);
    3.38 +	rb_free(rman->modset);
    3.39 +
    3.40 +	if(rman->inotify_fd >= 0) {
    3.41 +		close(rman->inotify_fd);
    3.42 +		rman->inotify_fd = -1;
    3.43 +	}
    3.44 +}
    3.45 +
    3.46 +int resman_start_watch(struct resman *rman, struct resource *res)
    3.47 +{
    3.48 +	int fd;
    3.49 +
    3.50 +	if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) {
    3.51 +		return -1;
    3.52 +	}
    3.53 +	printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd);
    3.54 +	rb_inserti(rman->nresmap, fd, res);
    3.55 +
    3.56 +	res->nfd = fd;
    3.57 +	return 0;
    3.58 +}
    3.59 +
    3.60 +void resman_stop_watch(struct resman *rman, struct resource *res)
    3.61 +{
    3.62 +	if(res->nfd > 0) {
    3.63 +		rb_deletei(rman->nresmap, res->nfd);
    3.64 +		inotify_rm_watch(rman->inotify_fd, res->nfd);
    3.65 +	}
    3.66 +}
    3.67 +
    3.68 +void resman_check_watch(struct resman *rman)
    3.69 +{
    3.70 +	char buf[512];
    3.71 +	struct inotify_event *ev;
    3.72 +	int sz, evsize;
    3.73 +
    3.74 +	while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) {
    3.75 +		ev = (struct inotify_event*)buf;
    3.76 +		while(sz > 0) {
    3.77 +			if(ev->mask & IN_MODIFY) {
    3.78 +				/* add the file descriptor to the modified set */
    3.79 +				rb_inserti(rman->modset, ev->wd, 0);
    3.80 +			}
    3.81 +
    3.82 +			evsize = sizeof *ev + ev->len;
    3.83 +			sz -= evsize;
    3.84 +			ev += evsize;
    3.85 +		}
    3.86 +	}
    3.87 +
    3.88 +	/* for each item in the modified set, start a new job to reload it */
    3.89 +	rb_foreach(rman->modset, reload_modified, rman);
    3.90 +	rb_clear(rman->modset);
    3.91 +}
    3.92 +
    3.93 +/* this is called for each item in the modified set (see above) */
    3.94 +static void reload_modified(struct rbnode *node, void *cls)
    3.95 +{
    3.96 +	int watch_fd;
    3.97 +	struct resource *res;
    3.98 +	struct resman *rman = cls;
    3.99 +
   3.100 +	watch_fd = rb_node_keyi(node);
   3.101 +
   3.102 +	if(!(res = rb_findi(rman->nresmap, watch_fd))) {
   3.103 +		fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n",
   3.104 +				__FUNCTION__, watch_fd);
   3.105 +		return;
   3.106 +	}
   3.107 +	assert(watch_fd == res->nfd);
   3.108 +
   3.109 +	printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node));
   3.110 +
   3.111 +	tpool_add_work(rman->tpool, res);
   3.112 +}
   3.113 +
   3.114 +#else
   3.115 +int resman_filewatch_win32_silence_empty_file_warning;
   3.116 +#endif	/* WIN32 */
     4.1 --- a/src/resman.c	Wed Feb 12 22:05:28 2014 +0200
     4.2 +++ b/src/resman.c	Wed Feb 12 22:32:30 2014 +0200
     4.3 @@ -4,58 +4,9 @@
     4.4  #include <assert.h>
     4.5  #include <pthread.h>
     4.6  #include "resman.h"
     4.7 +#include "resman_impl.h"
     4.8  #include "dynarr.h"
     4.9 -#include "rbtree.h"
    4.10 -#include "threadpool.h"
    4.11 -
    4.12 -#ifdef __linux__
    4.13 -#include <unistd.h>
    4.14 -#include <fcntl.h>
    4.15 -#include <sys/inotify.h>
    4.16 -#endif
    4.17 -
    4.18 -struct resource {
    4.19 -	int id;
    4.20 -	char *name;
    4.21 -	void *data;
    4.22 -	int result;	/* last callback-reported success/fail code */
    4.23 -
    4.24 -	int done_pending;
    4.25 -	int delete_pending;
    4.26 -	pthread_mutex_t lock;
    4.27 -
    4.28 -	int num_loads;		/* number of loads up to now */
    4.29 -
    4.30 -	/* file change monitoring */
    4.31 -#ifdef __WIN32__
    4.32 -	HANDLE nhandle;
    4.33 -#endif
    4.34 -#ifdef __linux__
    4.35 -	int nfd;
    4.36 -#endif
    4.37 -};
    4.38 -
    4.39 -struct resman {
    4.40 -	struct resource **res;
    4.41 -	struct thread_pool *tpool;
    4.42 -
    4.43 -	pthread_mutex_t lock;	/* global resman lock (for res array changes) */
    4.44 -
    4.45 -	resman_load_func load_func;
    4.46 -	resman_done_func done_func;
    4.47 -	resman_destroy_func destroy_func;
    4.48 -
    4.49 -	void *load_func_cls;
    4.50 -	void *done_func_cls;
    4.51 -	void *destroy_func_cls;
    4.52 -
    4.53 -	/* file change monitoring */
    4.54 -	struct rbtree *nresmap;
    4.55 -	struct rbtree *modset;
    4.56 -#ifdef __linux__
    4.57 -	int inotify_fd;
    4.58 -#endif
    4.59 -};
    4.60 +#include "filewatch.h"
    4.61  
    4.62  
    4.63  static int find_resource(struct resman *rman, const char *fname);
    4.64 @@ -63,14 +14,6 @@
    4.65  static void remove_resource(struct resman *rman, int idx);
    4.66  static void work_func(void *data, void *cls);
    4.67  
    4.68 -/* file modification watching */
    4.69 -static int init_file_monitor(struct resman *rman);
    4.70 -static void destroy_file_monitor(struct resman *rman);
    4.71 -static int start_watch(struct resman *rman, struct resource *res);
    4.72 -static void stop_watch(struct resman *rman, struct resource *res);
    4.73 -static void check_watch(struct resman *rman);
    4.74 -static void reload_modified(struct rbnode *node, void *cls);
    4.75 -
    4.76  
    4.77  struct resman *resman_create(void)
    4.78  {
    4.79 @@ -99,7 +42,7 @@
    4.80  		num_threads = atoi(env);
    4.81  	}
    4.82  
    4.83 -	if(init_file_monitor(rman) == -1) {
    4.84 +	if(resman_init_file_monitor(rman) == -1) {
    4.85  		return -1;
    4.86  	}
    4.87  
    4.88 @@ -133,7 +76,7 @@
    4.89  
    4.90  	tpool_free(rman->tpool);
    4.91  
    4.92 -	destroy_file_monitor(rman);
    4.93 +	resman_destroy_file_monitor(rman);
    4.94  
    4.95  	pthread_mutex_destroy(&rman->lock);
    4.96  }
    4.97 @@ -196,7 +139,7 @@
    4.98  
    4.99  
   4.100  	/* then check for modified files */
   4.101 -	check_watch(rman);
   4.102 +	resman_check_watch(rman);
   4.103  
   4.104  
   4.105  	if(!rman->done_func) {
   4.106 @@ -230,7 +173,7 @@
   4.107  		}
   4.108  		res->num_loads++;
   4.109  
   4.110 -		start_watch(rman, res);	/* start watching the file for modifications */
   4.111 +		resman_start_watch(rman, res);	/* start watching the file for modifications */
   4.112  		pthread_mutex_unlock(&res->lock);
   4.113  	}
   4.114  	return 0;
   4.115 @@ -336,7 +279,7 @@
   4.116  /* remove a resource and leave the pointer null to reuse the slot */
   4.117  static void remove_resource(struct resman *rman, int idx)
   4.118  {
   4.119 -	stop_watch(rman, rman->res[idx]);
   4.120 +	resman_stop_watch(rman, rman->res[idx]);
   4.121  
   4.122  	if(rman->destroy_func) {
   4.123  		rman->destroy_func(idx, rman->destroy_func_cls);
   4.124 @@ -371,7 +314,7 @@
   4.125  		} else {
   4.126  			/* succeded, start a watch */
   4.127  			if(res->nfd <= 0) {
   4.128 -				start_watch(rman, res);
   4.129 +				resman_start_watch(rman, res);
   4.130  			}
   4.131  		}
   4.132  	} else {
   4.133 @@ -380,100 +323,3 @@
   4.134  	}
   4.135  	pthread_mutex_unlock(&res->lock);
   4.136  }
   4.137 -
   4.138 -static int init_file_monitor(struct resman *rman)
   4.139 -{
   4.140 -	int fd;
   4.141 -
   4.142 -	if((fd = inotify_init()) == -1) {
   4.143 -		return -1;
   4.144 -	}
   4.145 -	/* set non-blocking flag, to allow polling by reading */
   4.146 -	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
   4.147 -	rman->inotify_fd = fd;
   4.148 -
   4.149 -	/* create the fd->resource map */
   4.150 -	rman->nresmap = rb_create(RB_KEY_INT);
   4.151 -	/* create the modified set */
   4.152 -	rman->modset = rb_create(RB_KEY_INT);
   4.153 -	return 0;
   4.154 -}
   4.155 -
   4.156 -static void destroy_file_monitor(struct resman *rman)
   4.157 -{
   4.158 -	rb_free(rman->nresmap);
   4.159 -	rb_free(rman->modset);
   4.160 -
   4.161 -	if(rman->inotify_fd >= 0) {
   4.162 -		close(rman->inotify_fd);
   4.163 -		rman->inotify_fd = -1;
   4.164 -	}
   4.165 -}
   4.166 -
   4.167 -static int start_watch(struct resman *rman, struct resource *res)
   4.168 -{
   4.169 -	int fd;
   4.170 -
   4.171 -	if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) {
   4.172 -		return -1;
   4.173 -	}
   4.174 -	printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd);
   4.175 -	rb_inserti(rman->nresmap, fd, res);
   4.176 -
   4.177 -	res->nfd = fd;
   4.178 -	return 0;
   4.179 -}
   4.180 -
   4.181 -static void stop_watch(struct resman *rman, struct resource *res)
   4.182 -{
   4.183 -	if(res->nfd > 0) {
   4.184 -		rb_deletei(rman->nresmap, res->nfd);
   4.185 -		inotify_rm_watch(rman->inotify_fd, res->nfd);
   4.186 -	}
   4.187 -}
   4.188 -
   4.189 -static void check_watch(struct resman *rman)
   4.190 -{
   4.191 -	char buf[512];
   4.192 -	struct inotify_event *ev;
   4.193 -	int sz, evsize;
   4.194 -
   4.195 -	while((sz = read(rman->inotify_fd, buf, sizeof buf)) > 0) {
   4.196 -		ev = (struct inotify_event*)buf;
   4.197 -		while(sz > 0) {
   4.198 -			if(ev->mask & IN_MODIFY) {
   4.199 -				/* add the file descriptor to the modified set */
   4.200 -				rb_inserti(rman->modset, ev->wd, 0);
   4.201 -			}
   4.202 -
   4.203 -			evsize = sizeof *ev + ev->len;
   4.204 -			sz -= evsize;
   4.205 -			ev += evsize;
   4.206 -		}
   4.207 -	}
   4.208 -
   4.209 -	/* for each item in the modified set, start a new job to reload it */
   4.210 -	rb_foreach(rman->modset, reload_modified, rman);
   4.211 -	rb_clear(rman->modset);
   4.212 -}
   4.213 -
   4.214 -/* this is called for each item in the modified set (see above) */
   4.215 -static void reload_modified(struct rbnode *node, void *cls)
   4.216 -{
   4.217 -	int watch_fd;
   4.218 -	struct resource *res;
   4.219 -	struct resman *rman = cls;
   4.220 -
   4.221 -	watch_fd = rb_node_keyi(node);
   4.222 -
   4.223 -	if(!(res = rb_findi(rman->nresmap, watch_fd))) {
   4.224 -		fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n",
   4.225 -				__FUNCTION__, watch_fd);
   4.226 -		return;
   4.227 -	}
   4.228 -	assert(watch_fd == res->nfd);
   4.229 -
   4.230 -	printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node));
   4.231 -
   4.232 -	tpool_add_work(rman->tpool, res);
   4.233 -}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/resman_impl.h	Wed Feb 12 22:32:30 2014 +0200
     5.3 @@ -0,0 +1,59 @@
     5.4 +#ifndef RESMAN_IMPL_H_
     5.5 +#define RESMAN_IMPL_H_
     5.6 +
     5.7 +#include <pthread.h>
     5.8 +#include "rbtree.h"
     5.9 +#include "threadpool.h"
    5.10 +
    5.11 +#ifdef __linux__
    5.12 +#include <unistd.h>
    5.13 +#include <fcntl.h>
    5.14 +#include <sys/inotify.h>
    5.15 +#endif
    5.16 +
    5.17 +struct resource {
    5.18 +	int id;
    5.19 +	char *name;
    5.20 +	void *data;
    5.21 +	int result;	/* last callback-reported success/fail code */
    5.22 +
    5.23 +	int done_pending;
    5.24 +	int delete_pending;
    5.25 +	pthread_mutex_t lock;
    5.26 +
    5.27 +	int num_loads;		/* number of loads up to now */
    5.28 +
    5.29 +	/* file change monitoring */
    5.30 +#ifdef __WIN32__
    5.31 +	HANDLE nhandle;
    5.32 +#endif
    5.33 +#ifdef __linux__
    5.34 +	int nfd;
    5.35 +#endif
    5.36 +};
    5.37 +
    5.38 +
    5.39 +struct resman {
    5.40 +	struct resource **res;
    5.41 +	struct thread_pool *tpool;
    5.42 +
    5.43 +	pthread_mutex_t lock;	/* global resman lock (for res array changes) */
    5.44 +
    5.45 +	resman_load_func load_func;
    5.46 +	resman_done_func done_func;
    5.47 +	resman_destroy_func destroy_func;
    5.48 +
    5.49 +	void *load_func_cls;
    5.50 +	void *done_func_cls;
    5.51 +	void *destroy_func_cls;
    5.52 +
    5.53 +	/* file change monitoring */
    5.54 +	struct rbtree *nresmap;
    5.55 +	struct rbtree *modset;
    5.56 +#ifdef __linux__
    5.57 +	int inotify_fd;
    5.58 +#endif
    5.59 +};
    5.60 +
    5.61 +
    5.62 +#endif	/* RESMAN_IMPL_H_ */