libresman
changeset 23:f8e5a1491275
win32 file change notification attempt1 (failed)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 13 Feb 2014 13:17:07 +0200 |
parents | 174ddb6bf92a |
children | ce04fa12afdd |
files | libresman-static.vcproj libresman.vcproj src/filewatch_linux.c src/filewatch_win32.c src/rbtree.c src/resman.c src/resman_impl.h |
diffstat | 7 files changed, 198 insertions(+), 77 deletions(-) [+] |
line diff
1.1 --- a/libresman-static.vcproj Wed Feb 12 22:32:30 2014 +0200 1.2 +++ b/libresman-static.vcproj Thu Feb 13 13:17:07 2014 +0200 1.3 @@ -21,7 +21,7 @@ 1.4 OutputDirectory="$(SolutionDir)$(ConfigurationName)" 1.5 IntermediateDirectory="$(ConfigurationName)-static" 1.6 ConfigurationType="4" 1.7 - CharacterSet="1" 1.8 + CharacterSet="2" 1.9 > 1.10 <Tool 1.11 Name="VCPreBuildEventTool" 1.12 @@ -83,7 +83,7 @@ 1.13 OutputDirectory="$(SolutionDir)$(ConfigurationName)-static" 1.14 IntermediateDirectory="$(ConfigurationName)" 1.15 ConfigurationType="4" 1.16 - CharacterSet="1" 1.17 + CharacterSet="2" 1.18 WholeProgramOptimization="1" 1.19 > 1.20 <Tool 1.21 @@ -159,6 +159,26 @@ 1.22 > 1.23 </File> 1.24 <File 1.25 + RelativePath=".\src\filewatch.h" 1.26 + > 1.27 + </File> 1.28 + <File 1.29 + RelativePath=".\src\filewatch_linux.c" 1.30 + > 1.31 + </File> 1.32 + <File 1.33 + RelativePath=".\src\filewatch_win32.c" 1.34 + > 1.35 + </File> 1.36 + <File 1.37 + RelativePath=".\src\rbtree.c" 1.38 + > 1.39 + </File> 1.40 + <File 1.41 + RelativePath=".\src\rbtree.h" 1.42 + > 1.43 + </File> 1.44 + <File 1.45 RelativePath=".\src\resman.c" 1.46 > 1.47 </File> 1.48 @@ -167,6 +187,10 @@ 1.49 > 1.50 </File> 1.51 <File 1.52 + RelativePath=".\src\resman_impl.h" 1.53 + > 1.54 + </File> 1.55 + <File 1.56 RelativePath=".\src\threadpool.c" 1.57 > 1.58 </File>
2.1 --- a/libresman.vcproj Wed Feb 12 22:32:30 2014 +0200 2.2 +++ b/libresman.vcproj Thu Feb 13 13:17:07 2014 +0200 2.3 @@ -21,7 +21,7 @@ 2.4 OutputDirectory="$(SolutionDir)$(ConfigurationName)" 2.5 IntermediateDirectory="$(ConfigurationName)" 2.6 ConfigurationType="2" 2.7 - CharacterSet="1" 2.8 + CharacterSet="2" 2.9 > 2.10 <Tool 2.11 Name="VCPreBuildEventTool" 2.12 @@ -95,7 +95,7 @@ 2.13 OutputDirectory="$(SolutionDir)$(ConfigurationName)" 2.14 IntermediateDirectory="$(ConfigurationName)" 2.15 ConfigurationType="2" 2.16 - CharacterSet="1" 2.17 + CharacterSet="2" 2.18 WholeProgramOptimization="1" 2.19 > 2.20 <Tool 2.21 @@ -185,6 +185,26 @@ 2.22 > 2.23 </File> 2.24 <File 2.25 + RelativePath=".\src\filewatch.h" 2.26 + > 2.27 + </File> 2.28 + <File 2.29 + RelativePath=".\src\filewatch_linux.c" 2.30 + > 2.31 + </File> 2.32 + <File 2.33 + RelativePath=".\src\filewatch_win32.c" 2.34 + > 2.35 + </File> 2.36 + <File 2.37 + RelativePath=".\src\rbtree.c" 2.38 + > 2.39 + </File> 2.40 + <File 2.41 + RelativePath=".\src\rbtree.h" 2.42 + > 2.43 + </File> 2.44 + <File 2.45 RelativePath=".\src\resman.c" 2.46 > 2.47 </File> 2.48 @@ -193,6 +213,10 @@ 2.49 > 2.50 </File> 2.51 <File 2.52 + RelativePath=".\src\resman_impl.h" 2.53 + > 2.54 + </File> 2.55 + <File 2.56 RelativePath=".\src\threadpool.c" 2.57 > 2.58 </File>
3.1 --- a/src/filewatch_linux.c Wed Feb 12 22:32:30 2014 +0200 3.2 +++ b/src/filewatch_linux.c Thu Feb 13 13:17:07 2014 +0200 3.3 @@ -44,6 +44,10 @@ 3.4 { 3.5 int fd; 3.6 3.7 + if(res->nfd > 0) { 3.8 + return 0; /* already started a watch for this resource */ 3.9 + } 3.10 + 3.11 if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) { 3.12 return -1; 3.13 }
4.1 --- a/src/filewatch_win32.c Wed Feb 12 22:32:30 2014 +0200 4.2 +++ b/src/filewatch_win32.c Thu Feb 13 13:17:07 2014 +0200 4.3 @@ -2,110 +2,171 @@ 4.4 #ifdef WIN32 4.5 #include <stdio.h> 4.6 #include <assert.h> 4.7 -#include <unistd.h> 4.8 -#include <fcntl.h> 4.9 -#include <sys/inotify.h> 4.10 +#include <malloc.h> 4.11 #include "filewatch.h" 4.12 #include "resman.h" 4.13 #include "resman_impl.h" 4.14 +#include "dynarr.h" 4.15 + 4.16 +struct watch_dir { 4.17 + HANDLE handle; 4.18 + int nref; 4.19 +}; 4.20 4.21 static void reload_modified(struct rbnode *node, void *cls); 4.22 4.23 int resman_init_file_monitor(struct resman *rman) 4.24 { 4.25 - int fd; 4.26 - 4.27 - if((fd = inotify_init()) == -1) { 4.28 + if(!(rman->watch_handles = dynarr_alloc(0, sizeof *rman->watch_handles))) { 4.29 return -1; 4.30 } 4.31 - /* set non-blocking flag, to allow polling by reading */ 4.32 - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); 4.33 - rman->inotify_fd = fd; 4.34 4.35 - /* create the fd->resource map */ 4.36 - rman->nresmap = rb_create(RB_KEY_INT); 4.37 - /* create the modified set */ 4.38 - rman->modset = rb_create(RB_KEY_INT); 4.39 + /* create the handle->resource map */ 4.40 + rman->nresmap = rb_create(RB_KEY_ADDR); 4.41 + /* create the watched dirs set */ 4.42 + rman->watchdirs = rb_create(RB_KEY_STRING); 4.43 return 0; 4.44 } 4.45 4.46 void resman_destroy_file_monitor(struct resman *rman) 4.47 { 4.48 + dynarr_free(rman->watch_handles); 4.49 + 4.50 rb_free(rman->nresmap); 4.51 - rb_free(rman->modset); 4.52 - 4.53 - if(rman->inotify_fd >= 0) { 4.54 - close(rman->inotify_fd); 4.55 - rman->inotify_fd = -1; 4.56 - } 4.57 + rb_free(rman->watchdirs); 4.58 } 4.59 4.60 int resman_start_watch(struct resman *rman, struct resource *res) 4.61 { 4.62 - int fd; 4.63 + char *path; 4.64 + HANDLE handle; 4.65 + struct watch_dir *wdir; 4.66 4.67 - if((fd = inotify_add_watch(rman->inotify_fd, res->name, IN_MODIFY)) == -1) { 4.68 - return -1; 4.69 + /* construct an absolute path for the directory containing this file */ 4.70 + path = res->name; 4.71 + if(path[0] != '/' && path[1] != ':') { /* not an absolute path */ 4.72 + char *src, *dest, *lastslash; 4.73 + int cwdsz = GetCurrentDirectory(0, 0); 4.74 + int pathsz = strlen(path) + cwdsz + 1; 4.75 + 4.76 + path = malloc(pathsz + 1); 4.77 + GetCurrentDirectory(pathsz, path); 4.78 + 4.79 + /* now copy the rest of the path, until the last slash, while converting path separators */ 4.80 + src = res->name; 4.81 + dest = path + strlen(path); 4.82 + 4.83 + lastslash = dest; 4.84 + *dest++ = '\\'; 4.85 + while(*src) { 4.86 + if(src[-1] == '\\') { 4.87 + /* skip any /./ parts of the path */ 4.88 + if(src[0] == '.' && (src[1] == '/' || src[1] == '\\')) { 4.89 + src += 2; 4.90 + continue; 4.91 + } 4.92 + /* normalize any /../ parts of the path */ 4.93 + if(src[0] == '.' && src[1] == '.' && (src[2] == '/' || src[2] == '\\')) { 4.94 + src += 3; 4.95 + dest = strrchr(src - 2, '\\'); 4.96 + assert(dest); 4.97 + dest++; 4.98 + continue; 4.99 + } 4.100 + } 4.101 + 4.102 + if(*src == '/' || *src == '\\') { 4.103 + lastslash = dest; 4.104 + *dest++ = '\\'; 4.105 + src++; 4.106 + } else { 4.107 + *dest++ = *src++; 4.108 + } 4.109 + } 4.110 + 4.111 + *lastslash = 0; 4.112 } 4.113 - printf("started watching file \"%s\" for modification (fd %d)\n", res->name, fd); 4.114 - rb_inserti(rman->nresmap, fd, res); 4.115 4.116 - res->nfd = fd; 4.117 + /* check to see if we already have a watch handle for this directory */ 4.118 + if((wdir = rb_find(rman->watchdirs, path))) { 4.119 + handle = wdir->handle; 4.120 + wdir->nref++; 4.121 + } else { 4.122 + if(!(wdir = malloc(sizeof *wdir))) { 4.123 + perror("failed to allocate watchdir"); 4.124 + free(path); 4.125 + return -1; 4.126 + } 4.127 + 4.128 + /* otherwise start a new notification */ 4.129 + if((handle = FindFirstChangeNotification(path, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE)) == INVALID_HANDLE_VALUE) { 4.130 + unsigned int err = GetLastError(); 4.131 + fprintf(stderr, "failed to watch %s for modification (error: %u)\n", path, err); 4.132 + free(wdir); 4.133 + free(path); 4.134 + return -1; 4.135 + } 4.136 + wdir->handle = handle; 4.137 + wdir->nref = 1; 4.138 + 4.139 + rb_insert(rman->watchdirs, path, wdir); 4.140 + dynarr_push(rman->watch_handles, &handle); 4.141 + } 4.142 + 4.143 + rb_insert(rman->nresmap, handle, res); 4.144 + res->nhandle = handle; 4.145 + res->watch_path = path; 4.146 return 0; 4.147 } 4.148 4.149 void resman_stop_watch(struct resman *rman, struct resource *res) 4.150 { 4.151 - if(res->nfd > 0) { 4.152 - rb_deletei(rman->nresmap, res->nfd); 4.153 - inotify_rm_watch(rman->inotify_fd, res->nfd); 4.154 + int i, sz; 4.155 + 4.156 + if(res->nhandle) { 4.157 + struct watch_dir *wdir = rb_find(rman->watchdirs, res->watch_path); 4.158 + if(wdir) { 4.159 + if(--wdir->nref <= 0) { 4.160 + FindCloseChangeNotification(res->nhandle); 4.161 + 4.162 + /* find the handle in the watch_handles array and remove it */ 4.163 + sz = dynarr_size(rman->watch_handles); 4.164 + for(i=0; i<sz; i++) { 4.165 + if(rman->watch_handles[i] == res->nhandle) { 4.166 + /* swap the end for it and pop */ 4.167 + rman->watch_handles[i] = rman->watch_handles[sz - 1]; 4.168 + rman->watch_handles[sz - 1] = 0; 4.169 + dynarr_pop(rman->watch_handles); 4.170 + break; 4.171 + } 4.172 + } 4.173 + } 4.174 + free(wdir); 4.175 + } 4.176 + 4.177 + rb_delete(rman->nresmap, res->nhandle); 4.178 + res->nhandle = 0; 4.179 } 4.180 } 4.181 4.182 void resman_check_watch(struct resman *rman) 4.183 { 4.184 - char buf[512]; 4.185 - struct inotify_event *ev; 4.186 - int sz, evsize; 4.187 + unsigned int num_handles = dynarr_size(rman->watch_handles); 4.188 + for(;;) { 4.189 + struct resource *res; 4.190 + unsigned int idx = WaitForMultipleObjects(num_handles, rman->watch_handles, FALSE, 0); 4.191 + if(idx < WAIT_OBJECT_0 || idx >= WAIT_OBJECT_0 + num_handles) { 4.192 + break; 4.193 + } 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 + if(!(res = rb_find(rman->nresmap, rman->watch_handles[idx]))) { 4.203 + fprintf(stderr, "got modification event from unknown resource!\n"); 4.204 + continue; 4.205 + } 4.206 4.207 - evsize = sizeof *ev + ev->len; 4.208 - sz -= evsize; 4.209 - ev += evsize; 4.210 - } 4.211 + printf("file \"%s\" modified\n", res->name); 4.212 + tpool_add_work(rman->tpool, res); 4.213 } 4.214 - 4.215 - /* for each item in the modified set, start a new job to reload it */ 4.216 - rb_foreach(rman->modset, reload_modified, rman); 4.217 - rb_clear(rman->modset); 4.218 -} 4.219 - 4.220 -/* this is called for each item in the modified set (see above) */ 4.221 -static void reload_modified(struct rbnode *node, void *cls) 4.222 -{ 4.223 - int watch_fd; 4.224 - struct resource *res; 4.225 - struct resman *rman = cls; 4.226 - 4.227 - watch_fd = rb_node_keyi(node); 4.228 - 4.229 - if(!(res = rb_findi(rman->nresmap, watch_fd))) { 4.230 - fprintf(stderr, "%s: can't find resource for watch descriptor: %d\n", 4.231 - __FUNCTION__, watch_fd); 4.232 - return; 4.233 - } 4.234 - assert(watch_fd == res->nfd); 4.235 - 4.236 - printf("file \"%s\" modified (fd %d)\n", res->name, rb_node_keyi(node)); 4.237 - 4.238 - tpool_add_work(rman->tpool, res); 4.239 } 4.240 4.241 #else
5.1 --- a/src/rbtree.c Wed Feb 12 22:32:30 2014 +0200 5.2 +++ b/src/rbtree.c Thu Feb 13 13:17:07 2014 +0200 5.3 @@ -1,6 +1,8 @@ 5.4 #include <stdio.h> 5.5 #include <stdlib.h> 5.6 +#ifndef _MSC_VER 5.7 #include <stdint.h> 5.8 +#endif 5.9 #include <string.h> 5.10 #include "rbtree.h" 5.11 5.12 @@ -414,7 +416,7 @@ 5.13 5.14 static struct rbnode *find_min(struct rbnode *tree) 5.15 { 5.16 - struct rbnode *node; 5.17 + struct rbnode *node = tree; 5.18 5.19 if(!tree) 5.20 return 0;
6.1 --- a/src/resman.c Wed Feb 12 22:32:30 2014 +0200 6.2 +++ b/src/resman.c Thu Feb 13 13:17:07 2014 +0200 6.3 @@ -313,9 +313,7 @@ 6.4 } 6.5 } else { 6.6 /* succeded, start a watch */ 6.7 - if(res->nfd <= 0) { 6.8 - resman_start_watch(rman, res); 6.9 - } 6.10 + resman_start_watch(rman, res); 6.11 } 6.12 } else { 6.13 /* if we have a done_func, mark this resource as done */
7.1 --- a/src/resman_impl.h Wed Feb 12 22:32:30 2014 +0200 7.2 +++ b/src/resman_impl.h Thu Feb 13 13:17:07 2014 +0200 7.3 @@ -10,6 +10,9 @@ 7.4 #include <fcntl.h> 7.5 #include <sys/inotify.h> 7.6 #endif 7.7 +#ifdef WIN32 7.8 +#include <windows.h> 7.9 +#endif 7.10 7.11 struct resource { 7.12 int id; 7.13 @@ -24,8 +27,9 @@ 7.14 int num_loads; /* number of loads up to now */ 7.15 7.16 /* file change monitoring */ 7.17 -#ifdef __WIN32__ 7.18 +#ifdef WIN32 7.19 HANDLE nhandle; 7.20 + char *watch_path; 7.21 #endif 7.22 #ifdef __linux__ 7.23 int nfd; 7.24 @@ -49,9 +53,13 @@ 7.25 7.26 /* file change monitoring */ 7.27 struct rbtree *nresmap; 7.28 - struct rbtree *modset; 7.29 #ifdef __linux__ 7.30 int inotify_fd; 7.31 + struct rbtree *modset; 7.32 +#endif 7.33 +#ifdef WIN32 7.34 + struct rbtree *watchdirs; 7.35 + HANDLE *watch_handles; /* dynamic array of all the watch handles */ 7.36 #endif 7.37 }; 7.38