]>
Dogcows Code - chaz/yoink/blob - src/moof/resource.cc
7a60d0e304e6e4c444dbeb5d920c3a5215c4e478
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
8 *****************************************************************************/
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"
36 /*] Filesystem searching
37 *************************************************************************/
39 static std::vector
<std::string
> search_paths_
;
41 void resource::set_search_paths(const std::string
& paths
)
43 boost::split(search_paths_
, paths
, boost::is_any_of(":"));
46 std::string
resource::find_file(const std::string
& name
)
48 std::string ext
= stlplus::extension_part(name
);
53 call_registry(ext
, loader
, lookup
);
54 if (loader
) prefix
= loader
->prefix();
56 std::vector
<std::string
>::iterator it
;
57 for (it
= search_paths_
.begin(); it
!= search_paths_
.end(); ++it
)
61 // try it with the prefix first
62 path
= stlplus::filespec_to_path(*it
, prefix
);
63 path
= stlplus::filespec_to_path(path
, name
);
64 log_debug("looking for", name
, "at", path
);
65 if (stlplus::file_exists(path
)) return path
;
68 path
= stlplus::filespec_to_path(*it
, name
);
69 log_debug("looking for", name
, "at", path
);
70 if (stlplus::file_exists(path
)) return path
;
73 log_error("cannot find resource file:", name
);
78 resource::find_file(const std::string
& name
, const std::string
& ext
)
80 std::string actual_ext
= stlplus::extension_part(name
);
81 if (actual_ext
!= ext
)
83 // try the explicit extension first
84 return find_file(stlplus::create_filename(name
, ext
));
86 return find_file(name
);
91 *************************************************************************/
93 typedef boost::weak_ptr
<resource
> resource_weakptr
;
94 static struct rsrc_list
96 // this table holds weak references to any and all loaded resources
97 hash
<std::string
,resource_weakptr
,hash_function
> table
;
100 // this destructor will let us know if the program exits while
101 // resources are still being held
104 hash
<std::string
,resource_weakptr
,hash_function
>::iterator it
;
105 for (it
= table
.begin(); it
!= table
.end(); ++it
)
106 log_warning("leaked resource:", (*it
).first
);
111 #if ENABLE_HOTLOADING
112 static struct watch_list
114 // this table associates a watch descriptor with a loaded resource
115 hash
<int,resource_weakptr
,hash_function
> table
;
117 int fd
; // the inotify file descriptor
120 fd(inotify_init1(IN_NONBLOCK
)) {}
127 int add(resource_ptr rsrc
)
129 int wd
= inotify_add_watch(fd
, rsrc
->path().c_str(),
130 IN_DELETE_SELF
| IN_MODIFY
);
136 if (wd
!= -1) inotify_rm_watch(fd
, wd
);
141 resource_ptr
resource::load(const std::string
& name
)
143 std::string ext
= stlplus::extension_part(name
);
144 return load_with_path(find_file(name
, ext
), ext
);
147 resource_ptr
resource::load(const std::string
& name
, const std::string
& ext
)
149 return load_with_path(find_file(name
, ext
), ext
);
153 resource::load_with_path(const std::string
& path
, const std::string
& ext
)
155 if (path
.empty()) return resource_ptr();
157 // first try to lookup the resource
158 hash
<std::string
,resource_weakptr
,hash_function
>::iterator it
;
159 it
= rsrc_list
.table
.find(path
);
160 if (it
!= rsrc_list
.table
.end())
162 resource_ptr rsrc
= (*it
).second
.lock();
163 if (rsrc
) return rsrc
;
166 // then proceed to use the registered loader to get the resource
168 call_registry(ext
, loader
, lookup
);
171 resource_ptr
rsrc(loader
->load(path
));
172 rsrc_list
.table
[path
] = rsrc
;
175 #if ENABLE_HOTLOADING
176 rsrc
->wd_
= watch_list
.add(rsrc
);
181 log_warning("cannot load resource of unregistered type:", path
);
182 return resource_ptr();
186 *************************************************************************/
188 int resource::reload_as_needed()
192 #if ENABLE_HOTLOADING
193 char bytes
[BUF_SIZE
];
195 // an inotify file descriptor lets your read inotify_event structures
196 if (0 < (num_bytes
= read(watch_list
.fd
, bytes
, sizeof(bytes
))))
198 char* end
= bytes
+ num_bytes
;
203 struct inotify_event
* event
= (struct inotify_event
*)byte
;
204 byte
+= sizeof(*event
) + event
->len
;
206 hash
<int,resource_weakptr
,hash_function
>::iterator it
;
207 it
= watch_list
.table
.find(event
->wd
);
208 if (it
!= watch_list
.table
.end())
210 resource_ptr rsrc
= (*it
).second
.lock();
216 if (event
->mask
& IN_IGNORED
)
218 watch_list
.table
.erase(event
->wd
);
219 rsrc
->wd_
= watch_list
.add(rsrc
);
224 // if we can't lock the resource, it was unloaded so we
225 // don't need to watch it anymore
226 watch_list
.table
.erase(event
->wd
);
235 void resource::reload()
238 call_registry(type_
, loader
, lookup
);
240 resource_ptr
resource(loader
->load(path_
));
241 resource_
= resource
->resource_
;
242 typeinfo_
= resource
->typeinfo_
;
243 unloader_
= resource
->unloader_
;
246 resource::~resource()
248 rsrc_list
.table
.erase(path_
);
249 #if ENABLE_HOTLOADING
250 watch_list
.remove(wd_
);
254 /*] Resource registration
255 *************************************************************************/
257 bool resource::call_registry(const std::string
& ext
,
258 loader_ptr
& loader
, registry_action action
)
260 static std::map
<std::string
,loader_ptr
> table
;
266 std::map
<std::string
,loader_ptr
>::iterator it
;
267 it
= table
.find(ext
);
268 if (it
!= table
.end()) loader
= (*it
).second
;
This page took 0.050939 seconds and 4 git commands to generate.