]>
Dogcows Code - chaz/yoink/blob - src/moof/resource.cc
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 *****************************************************************************/
16 #include <boost/algorithm/string.hpp>
17 #include <boost/weak_ptr.hpp>
19 #include <stlplus/portability/file_system.hpp>
22 #include <sys/inotify.h>
23 #include <sys/ioctl.h>
28 #include "resource.hh"
38 /*] Filesystem searching
39 *************************************************************************/
41 static std::vector
<std::string
> search_paths_
;
43 void resource::set_search_paths(const std::string
& paths
)
45 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_debug("looking for", name
, "at", path
);
67 if (stlplus::file_exists(path
)) return path
;
70 path
= stlplus::filespec_to_path(*it
, name
);
71 log_debug("looking for", name
, "at", path
);
72 if (stlplus::file_exists(path
)) return path
;
75 log_error("cannot find resource file:", name
);
80 resource::find_file(const std::string
& name
, 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
)
108 log_warning("leaked resource:", (*it
).first
);
113 #if ENABLE_HOTLOADING
114 static struct watch_list
116 // this table associates a watch descriptor with a loaded resource
117 hash
<int,resource_weakptr
,hash_function
> table
;
119 int fd
; // the inotify file descriptor
122 fd(inotify_init1(IN_NONBLOCK
)) {}
129 int add(resource_ptr rsrc
)
131 int wd
= inotify_add_watch(fd
, rsrc
->path().c_str(),
132 IN_DELETE_SELF
| IN_MODIFY
);
138 if (wd
!= -1) inotify_rm_watch(fd
, wd
);
143 resource_ptr
resource::load(const std::string
& name
)
145 std::string ext
= stlplus::extension_part(name
);
146 return load_with_path(find_file(name
, ext
), ext
);
149 resource_ptr
resource::load(const std::string
& name
, const std::string
& ext
)
151 return load_with_path(find_file(name
, ext
), ext
);
155 resource::load_with_path(const std::string
& path
, const std::string
& ext
)
157 if (path
.empty()) return resource_ptr();
159 // first try to lookup the resource
160 hash
<std::string
,resource_weakptr
,hash_function
>::iterator it
;
161 it
= rsrc_list
.table
.find(path
);
162 if (it
!= rsrc_list
.table
.end())
164 resource_ptr rsrc
= (*it
).second
.lock();
165 if (rsrc
) return rsrc
;
168 // then proceed to use the registered loader to get the resource
170 call_registry(ext
, loader
, lookup
);
173 resource_ptr
rsrc(loader
->load(path
));
174 rsrc_list
.table
[path
] = rsrc
;
177 #if ENABLE_HOTLOADING
178 rsrc
->wd_
= watch_list
.add(rsrc
);
183 log_warning("cannot load resource of unregistered type:", path
);
184 return resource_ptr();
188 *************************************************************************/
190 int resource::reload_as_needed()
194 #if ENABLE_HOTLOADING
195 char bytes
[BUF_SIZE
];
197 // an inotify file descriptor lets your read inotify_event structures
198 if (0 < (num_bytes
= read(watch_list
.fd
, bytes
, sizeof(bytes
))))
200 char* end
= bytes
+ num_bytes
;
205 struct inotify_event
* event
= (struct inotify_event
*)byte
;
206 byte
+= sizeof(*event
) + event
->len
;
208 hash
<int,resource_weakptr
,hash_function
>::iterator it
;
209 it
= watch_list
.table
.find(event
->wd
);
210 if (it
!= watch_list
.table
.end())
212 resource_ptr rsrc
= (*it
).second
.lock();
218 if (event
->mask
& IN_IGNORED
)
220 watch_list
.table
.erase(event
->wd
);
221 rsrc
->wd_
= watch_list
.add(rsrc
);
226 // if we can't lock the resource, it was unloaded so we
227 // don't need to watch it anymore
228 watch_list
.table
.erase(event
->wd
);
237 void resource::reload()
240 call_registry(type_
, loader
, lookup
);
242 resource_ptr
resource(loader
->load(path_
));
243 resource_
= resource
->resource_
;
244 typeinfo_
= resource
->typeinfo_
;
245 unloader_
= resource
->unloader_
;
248 resource::~resource()
250 rsrc_list
.table
.erase(path_
);
251 #if ENABLE_HOTLOADING
252 watch_list
.remove(wd_
);
256 /*] Resource registration
257 *************************************************************************/
259 bool resource::call_registry(const std::string
& ext
,
260 loader_ptr
& loader
, registry_action action
)
262 static std::map
<std::string
,loader_ptr
> table
;
268 std::map
<std::string
,loader_ptr
>::iterator it
;
269 it
= table
.find(ext
);
270 if (it
!= table
.end()) loader
= (*it
).second
;
This page took 0.042615 seconds and 4 git commands to generate.