]> Dogcows Code - chaz/yoink/blob - src/moof/resource.cc
fixed some resource management bugs
[chaz/yoink] / src / moof / resource.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
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.
9 *
10 **************************************************************************/
11
12 #include "config.h"
13
14 #ifdef USE_HOTLOADING
15 #include <sys/inotify.h>
16 #include <sys/ioctl.h>
17 #endif
18
19 #include <queue>
20
21 #include <boost/algorithm/string.hpp>
22 #include <boost/weak_ptr.hpp>
23 #include <stlplus/portability/file_system.hpp>
24
25 #include "hash.hh"
26 #include "resource.hh"
27
28
29 #ifndef BUF_SIZE
30 #define BUF_SIZE 4096
31 #endif
32
33
34 namespace moof {
35
36
37 bool resource::call_registry(const std::string& extension,
38 loader_ptr& loader,
39 registry_action action)
40 {
41 static type_lookup table;
42
43 switch (action)
44 {
45 case set:
46 {
47 if (loader) table[extension] = loader;
48 else table.erase(extension);
49 break;
50 }
51
52 case lookup:
53 {
54 std::map<std::string,loader_ptr>::iterator it;
55 it = table.find(extension);
56 if (it != table.end()) loader = (*it).second;
57 break;
58 }
59 }
60
61 return loader;
62 }
63
64 static std::string search_paths_;
65
66 typedef boost::weak_ptr<resource> resource_weakptr;
67 static hash<std::string,resource_weakptr,hash_function> resource_table_;
68
69 static hash<std::string,std::string,hash_function> prefix_table_;
70
71
72 #ifdef USE_HOTLOADING
73 static hash<int,std::string,hash_function> monitor_lookup_;
74 static int monitor_fd_ = inotify_init1(IN_NONBLOCK);
75 #endif
76
77 int resource::reload_as_needed()
78 {
79 int num_resources = 0;
80
81 #ifdef USE_HOTLOADING
82 log_info("hotloading?");
83 char bytes[BUF_SIZE];
84 int num_bytes;
85 if (0 < (num_bytes = read(monitor_fd_, bytes, num_bytes)))
86 {
87 char* end = bytes + num_bytes;
88 char* byte = bytes;
89
90 log_warning("num_bytes:", num_bytes);
91 log_error("1");
92
93 while (byte < end)
94 {
95 struct inotify_event* event = (struct inotify_event*)byte;
96
97 if (event->mask & IN_IGNORED)
98 {
99 log_warning("watch", event->wd, "removed");
100 }
101
102 log_error("2");
103 hash<int,std::string,hash_function>::iterator it;
104 it = monitor_lookup_.find(event->wd);
105 if (it != monitor_lookup_.end())
106 {
107 log_error("3");
108 std::string path = (*it).second;
109 monitor_lookup_.erase(it);
110 resource::reload(path);
111 }
112
113 byte += sizeof(*event) + event->len;
114
115 ++num_resources;
116 }
117 }
118 #endif
119
120 return num_resources;
121 }
122
123
124 resource::~resource()
125 {
126 #ifdef USE_HOTLOADING
127 inotify_rm_watch(monitor_fd_, wd_);
128 #endif
129 }
130
131
132 resource_ptr resource::load(const std::string& name,
133 const std::string& ext)
134 {
135 return load_with_path(find_file(name, ext));
136 }
137
138 resource_ptr resource::load(const std::string& name)
139 {
140 return load_with_path(find_file(name));
141 }
142
143
144 resource_ptr resource::load_with_path(const std::string& path)
145 {
146 std::string extension = stlplus::extension_part(path);
147
148 hash<std::string,resource_weakptr,hash_function>::iterator it;
149 it = resource_table_.find(path);
150 if (it != resource_table_.end())
151 {
152 resource_weakptr rsrc = (*it).second;
153 resource_ptr locked = rsrc.lock();
154 if (locked) return locked;
155 }
156
157 loader_ptr loader;
158 call_registry(extension, loader, lookup);
159 if (loader)
160 {
161 resource_ptr rsrc(loader->load(path));
162 rsrc->set_loader(path, loader);
163 resource_table_[path] = rsrc;
164
165 #ifdef USE_HOTLOADING
166 int wd = inotify_add_watch(monitor_fd_, path.c_str(), IN_MODIFY);
167 rsrc->set_watch_descriptor(wd);
168 monitor_lookup_[wd] = path;
169 #endif
170
171 log_info("loaded", rsrc.get());
172 return rsrc;
173 }
174
175 log_warning("cannot load resource of unknown type:", path);
176 return resource_ptr();
177 }
178
179
180 resource_ptr resource::reload(std::string& path)
181 {
182 log_info("reloading...", path);
183 hash<std::string,resource_weakptr,hash_function>::iterator it;
184 it = resource_table_.find(path);
185 if (it != resource_table_.end())
186 {
187 resource_weakptr rsrc = (*it).second;
188 resource_ptr locked = rsrc.lock();
189 if (locked)
190 {
191 locked->reload();
192 return locked;
193 }
194 }
195
196 return load(path);
197 }
198
199 void resource::reload()
200 {
201 log_info("reloaded", path_);
202
203 resource* resource = loader_->load(path_);
204 //*this = *resource;
205 resource_ = resource->resource_;
206 typeinfo_ = resource->typeinfo_;
207 unloader_ = resource->unloader_;
208
209 #ifdef USE_HOTLOADING
210 int wd = inotify_add_watch(monitor_fd_, path_.c_str(), IN_MODIFY);
211 set_watch_descriptor(wd);
212 monitor_lookup_[wd] = path_;
213 #endif
214
215 delete resource;
216 }
217
218
219 void resource::add_search_paths(const std::string& paths)
220 {
221 search_paths_ = paths;
222 }
223
224
225 bool resource::find(const std::string& path)
226 {
227 //std::string file = stlplus::lookup(path, search_paths_, ":");
228 //log_info("found file", file, "in", search_paths_);
229 //return !stlplus::lookup(path, search_paths_, ":").empty();
230 return find_file(path) != "";
231 }
232
233
234 std::string resource::find_file(const std::string& name)
235 {
236 std::vector<std::string> paths;
237 boost::split(paths, search_paths_, boost::is_any_of(":"));
238
239 std::string ext = stlplus::extension_part(name);
240 std::string prefix("hi");
241
242 loader_ptr loader;
243 call_registry(ext, loader, lookup);
244 if (loader) prefix = loader->prefix();
245
246 log_info("find_file:", ext, prefix);
247
248 std::vector<std::string>::iterator it;
249 for (it = paths.begin(); it != paths.end(); ++it)
250 {
251 std::string path = stlplus::create_filespec(*it, name);
252 log_info("looking for", name, "at", path);
253 if (stlplus::file_exists(path)) return path;
254
255 // try it with the prefix added
256 if (!prefix.empty())
257 {
258 *it = stlplus::create_filespec(*it, prefix);
259 path = stlplus::create_filespec(*it, name);
260 log_info("looking for", name, "at", path);
261 if (stlplus::file_exists(path)) return path;
262 }
263 }
264
265
266 log_error("cannot find resource file:", name);
267 return std::string();
268 }
269
270 std::string resource::find_file(const std::string& name,
271 const std::string& ext)
272 {
273 std::string actual_ext = stlplus::extension_part(name);
274 if (actual_ext != ext)
275 {
276 return find_file(stlplus::create_filename(name, ext));
277 }
278 return find_file(name);
279 }
280
281 FILE* resource::open_file(const std::string& path, const std::string& mode)
282 {
283 return fopen(find_file(path).c_str(), mode.c_str());
284 }
285
286
287 } // namespace moof
288
This page took 0.039859 seconds and 4 git commands to generate.