]>
Dogcows Code - chaz/yoink/blob - src/moof/resource.cc
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
10 **************************************************************************/
17 #include <sys/inotify.h>
18 #include <sys/ioctl.h>
21 #include <boost/algorithm/string.hpp>
22 #include <boost/weak_ptr.hpp>
23 #include <stlplus/portability/file_system.hpp>
26 #include "resource.hh"
37 /*] Filesystem searching
38 *************************************************************************/
40 static std::vector
<std::string
> search_paths_
;
42 void resource::set_search_paths(const std::string
& paths
)
44 boost::split(search_paths_
, paths
, boost::is_any_of(":"));
48 std::string
resource::find_file(const std::string
& name
)
50 std::string ext
= stlplus::extension_part(name
);
55 call_registry(ext
, loader
, lookup
);
56 if (loader
) prefix
= loader
->prefix();
58 std::vector
<std::string
>::iterator it
;
59 for (it
= search_paths_
.begin(); it
!= search_paths_
.end(); ++it
)
63 // try it with the prefix first
64 path
= stlplus::filespec_to_path(*it
, prefix
);
65 path
= stlplus::filespec_to_path(path
, name
);
66 log_info("looking for", name
, "at", path
);
67 if (stlplus::file_exists(path
)) return path
;
70 path
= stlplus::filespec_to_path(*it
, name
);
71 log_info("looking for", name
, "at", path
);
72 if (stlplus::file_exists(path
)) return path
;
75 log_error("cannot find resource file:", name
);
79 std::string
resource::find_file(const std::string
& name
,
80 const std::string
& ext
)
82 std::string actual_ext
= stlplus::extension_part(name
);
83 if (actual_ext
!= ext
)
85 // try the explicit extension first
86 return find_file(stlplus::create_filename(name
, ext
));
88 return find_file(name
);
93 *************************************************************************/
95 typedef boost::weak_ptr
<resource
> resource_weakptr
;
96 static struct rsrc_list
98 // this table holds weak references to any and all loaded resources
99 hash
<std::string
,resource_weakptr
,hash_function
> table
;
102 // this destructor will let us know if the program exits while
103 // resources are still being held
106 hash
<std::string
,resource_weakptr
,hash_function
>::iterator it
;
107 for (it
= table
.begin(); it
!= table
.end(); ++it
)
109 log_warning("leaked resource:", (*it
).first
);
115 #ifdef USE_HOTLOADING
116 static struct watch_list
118 // this table associates a watch descriptor with a loaded resource
119 hash
<int,resource_weakptr
,hash_function
> table
;
121 int fd
; // the inotify file descriptor
124 fd(inotify_init1(IN_NONBLOCK
)) {}
131 int add(resource_ptr rsrc
)
133 int wd
= inotify_add_watch(fd
, rsrc
->path().c_str(),
134 IN_DELETE_SELF
| IN_MODIFY
);
140 if (wd
!= -1) inotify_rm_watch(fd
, wd
);
146 resource_ptr
resource::load(const std::string
& name
)
148 std::string ext
= stlplus::extension_part(name
);
149 return load_with_path(find_file(name
, ext
), ext
);
152 resource_ptr
resource::load(const std::string
& name
,
153 const std::string
& ext
)
155 return load_with_path(find_file(name
, ext
), ext
);
159 resource_ptr
resource::load_with_path(const std::string
& path
,
160 const std::string
& ext
)
162 if (path
.empty()) return resource_ptr();
164 // first try to lookup the resource
165 hash
<std::string
,resource_weakptr
,hash_function
>::iterator it
;
166 it
= rsrc_list
.table
.find(path
);
167 if (it
!= rsrc_list
.table
.end())
169 resource_ptr rsrc
= (*it
).second
.lock();
170 if (rsrc
) return rsrc
;
173 // then proceed to use the registered loader to get the resource
175 call_registry(ext
, loader
, lookup
);
178 resource_ptr
rsrc(loader
->load(path
));
179 rsrc_list
.table
[path
] = rsrc
;
182 #ifdef USE_HOTLOADING
183 rsrc
->wd_
= watch_list
.add(rsrc
);
188 log_warning("cannot load resource of unregistered type:", path
);
189 return resource_ptr();
194 *************************************************************************/
196 int resource::reload_as_needed()
200 #ifdef USE_HOTLOADING
201 char bytes
[BUF_SIZE
];
203 // an inotify file descriptor lets your read inotify_event structures
204 if (0 < (num_bytes
= read(watch_list
.fd
, bytes
, sizeof(bytes
))))
206 char* end
= bytes
+ num_bytes
;
211 struct inotify_event
* event
= (struct inotify_event
*)byte
;
212 byte
+= sizeof(*event
) + event
->len
;
214 hash
<int,resource_weakptr
,hash_function
>::iterator it
;
215 it
= watch_list
.table
.find(event
->wd
);
216 if (it
!= watch_list
.table
.end())
218 resource_ptr rsrc
= (*it
).second
.lock();
224 if (event
->mask
& IN_IGNORED
)
226 watch_list
.table
.erase(event
->wd
);
227 rsrc
->wd_
= watch_list
.add(rsrc
);
232 // if we can't lock the resource, it was unloaded so we
233 // don't need to watch it anymore
234 watch_list
.table
.erase(event
->wd
);
244 void resource::reload()
247 call_registry(type_
, loader
, lookup
);
249 resource_ptr
resource(loader
->load(path_
));
250 resource_
= resource
->resource_
;
251 typeinfo_
= resource
->typeinfo_
;
252 unloader_
= resource
->unloader_
;
255 resource::~resource()
257 rsrc_list
.table
.erase(path_
);
258 #ifdef USE_HOTLOADING
259 watch_list
.remove(wd_
);
264 /*] Resource registration
265 *************************************************************************/
267 bool resource::call_registry(const std::string
& ext
,
269 registry_action action
)
271 static std::map
<std::string
,loader_ptr
> table
;
277 if (loader
) table
[ext
] = loader
;
278 else table
.erase(ext
);
284 std::map
<std::string
,loader_ptr
>::iterator it
;
285 it
= table
.find(ext
);
286 if (it
!= table
.end()) loader
= (*it
).second
;
This page took 0.047401 seconds and 5 git commands to generate.