X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fresource.cc;h=3cf901b06473ae730fccd87d556a05d973460fa6;hp=57bd99b927df9fabfdee70f22faeae208c2d823b;hb=6f1b787a10d8ab1a3117a4b8c004dd2d90599608;hpb=c143f7e806766a73cd69dc6e084e977641019ce6 diff --git a/src/moof/resource.cc b/src/moof/resource.cc index 57bd99b..3cf901b 100644 --- a/src/moof/resource.cc +++ b/src/moof/resource.cc @@ -11,13 +11,13 @@ #include "config.h" +#include + #ifdef USE_HOTLOADING #include #include #endif -#include - #include #include #include @@ -34,239 +34,261 @@ namespace moof { -bool resource::call_registry(const std::string& extension, - loader_ptr& loader, - registry_action action) +/*] Filesystem searching + *************************************************************************/ + +static std::vector search_paths_; + +void resource::set_search_paths(const std::string& paths) { - static type_lookup table; + boost::split(search_paths_, paths, boost::is_any_of(":")); +} - switch (action) + +std::string resource::find_file(const std::string& name) +{ + std::string ext = stlplus::extension_part(name); + std::string prefix; + std::string path; + + loader_ptr loader; + call_registry(ext, loader, lookup); + if (loader) prefix = loader->prefix(); + + std::vector::iterator it; + for (it = search_paths_.begin(); it != search_paths_.end(); ++it) { - case set: + if (!prefix.empty()) { - if (loader) table[extension] = loader; - else table.erase(extension); - break; + // try it with the prefix first + path = stlplus::filespec_to_path(*it, prefix); + path = stlplus::filespec_to_path(path, name); + log_info("looking for", name, "at", path); + if (stlplus::file_exists(path)) return path; } - case lookup: - { - std::map::iterator it; - it = table.find(extension); - if (it != table.end()) loader = (*it).second; - break; - } + path = stlplus::filespec_to_path(*it, name); + log_info("looking for", name, "at", path); + if (stlplus::file_exists(path)) return path; } - return loader; + log_error("cannot find resource file:", name); + return std::string(); } -static std::string search_paths_; - -typedef boost::weak_ptr resource_weakptr; -static hash resource_table_; - -static hash prefix_table_; +std::string resource::find_file(const std::string& name, + const std::string& ext) +{ + std::string actual_ext = stlplus::extension_part(name); + if (actual_ext != ext) + { + // try the explicit extension first + return find_file(stlplus::create_filename(name, ext)); + } + return find_file(name); +} -#ifdef USE_HOTLOADING -static hash monitor_lookup_; -static int monitor_fd_ = inotify_init1(IN_NONBLOCK); -#endif +/*] Resource loading + *************************************************************************/ -int resource::reload_as_needed() +typedef boost::weak_ptr resource_weakptr; +static struct rsrc_list { - int num_resources = 0; + // this table holds weak references to any and all loaded resources + hash table; -#ifdef USE_HOTLOADING - log_info("hotloading?"); - char bytes[BUF_SIZE]; - int num_bytes; - if (0 < (num_bytes = read(monitor_fd_, bytes, num_bytes))) +#ifdef DEBUG + // this destructor will let us know if the program exits while + // resources are still being held + ~rsrc_list() { - char* end = bytes + num_bytes; - char* byte = bytes; - - log_warning("num_bytes:", num_bytes); - log_error("1"); - - while (byte < end) + hash::iterator it; + for (it = table.begin(); it != table.end(); ++it) { - struct inotify_event* event = (struct inotify_event*)byte; + log_warning("leaked resource:", (*it).first); + } + } +#endif +} rsrc_list; - if (event->mask & IN_IGNORED) - { - log_warning("watch", event->wd, "removed"); - } +#ifdef USE_HOTLOADING +static struct watch_list +{ + // this table associates a watch descriptor with a loaded resource + hash table; - log_error("2"); - hash::iterator it; - it = monitor_lookup_.find(event->wd); - if (it != monitor_lookup_.end()) - { - log_error("3"); - std::string path = (*it).second; - monitor_lookup_.erase(it); - resource::reload(path); - } + int fd; // the inotify file descriptor - byte += sizeof(*event) + event->len; + watch_list() : + fd(inotify_init1(IN_NONBLOCK)) {} - ++num_resources; - } + ~watch_list() + { + close(fd); } -#endif - return num_resources; -} + int add(resource_ptr rsrc) + { + int wd = inotify_add_watch(fd, rsrc->path().c_str(), + IN_DELETE_SELF | IN_MODIFY); + table[wd] = rsrc; + return wd; + } + void remove(int wd) + { + if (wd != -1) inotify_rm_watch(fd, wd); + } +} watch_list; +#endif -resource::~resource() +resource_ptr resource::load(const std::string& name) { -#ifdef USE_HOTLOADING - inotify_rm_watch(monitor_fd_, wd_); -#endif + std::string ext = stlplus::extension_part(name); + return load_with_path(find_file(name, ext), ext); } - resource_ptr resource::load(const std::string& name, const std::string& ext) { - return load_with_path(find_file(name, ext)); -} - -resource_ptr resource::load(const std::string& name) -{ - return load_with_path(find_file(name)); + return load_with_path(find_file(name, ext), ext); } -resource_ptr resource::load_with_path(const std::string& path) +resource_ptr resource::load_with_path(const std::string& path, + const std::string& ext) { - std::string extension = stlplus::extension_part(path); + if (path.empty()) return resource_ptr(); + // first try to lookup the resource hash::iterator it; - it = resource_table_.find(path); - if (it != resource_table_.end()) + it = rsrc_list.table.find(path); + if (it != rsrc_list.table.end()) { - resource_weakptr rsrc = (*it).second; - resource_ptr locked = rsrc.lock(); - if (locked) return locked; + resource_ptr rsrc = (*it).second.lock(); + if (rsrc) return rsrc; } + // then proceed to use the registered loader to get the resource loader_ptr loader; - call_registry(extension, loader, lookup); + call_registry(ext, loader, lookup); if (loader) { resource_ptr rsrc(loader->load(path)); - rsrc->set_loader(path, loader); - resource_table_[path] = rsrc; - + rsrc_list.table[path] = rsrc; + rsrc->path_ = path; + rsrc->type_ = ext; #ifdef USE_HOTLOADING - int wd = inotify_add_watch(monitor_fd_, path.c_str(), IN_MODIFY); - rsrc->set_watch_descriptor(wd); - monitor_lookup_[wd] = path; + rsrc->wd_ = watch_list.add(rsrc); #endif - - log_info("loaded", rsrc.get()); return rsrc; } - log_warning("cannot load resource of unknown type:", path); + log_warning("cannot load resource of unregistered type:", path); return resource_ptr(); } -resource_ptr resource::reload(std::string& path) +/*] Hotloading + *************************************************************************/ + +int resource::reload_as_needed() { - log_info("reloading...", path); - hash::iterator it; - it = resource_table_.find(path); - if (it != resource_table_.end()) + int count = 0; + +#ifdef USE_HOTLOADING + char bytes[BUF_SIZE]; + int num_bytes; + // an inotify file descriptor lets your read inotify_event structures + if (0 < (num_bytes = read(watch_list.fd, bytes, sizeof(bytes)))) { - resource_weakptr rsrc = (*it).second; - resource_ptr locked = rsrc.lock(); - if (locked) + char* end = bytes + num_bytes; + char* byte = bytes; + + while (byte < end) { - locked->reload(); - return locked; + struct inotify_event* event = (struct inotify_event*)byte; + byte += sizeof(*event) + event->len; + + hash::iterator it; + it = watch_list.table.find(event->wd); + if (it != watch_list.table.end()) + { + resource_ptr rsrc = (*it).second.lock(); + if (rsrc) + { + rsrc->reload(); + ++count; + + if (event->mask & IN_IGNORED) + { + watch_list.table.erase(event->wd); + rsrc->wd_ = watch_list.add(rsrc); + } + } + else + { + // if we can't lock the resource, it was unloaded so we + // don't need to watch it anymore + watch_list.table.erase(event->wd); + } + } } } +#endif - return load(path); + return count; } void resource::reload() { - log_info("reloaded", path_); + loader_ptr loader; + call_registry(type_, loader, lookup); - resource* resource = loader_->load(path_); - //*this = *resource; + resource_ptr resource(loader->load(path_)); resource_ = resource->resource_; typeinfo_ = resource->typeinfo_; unloader_ = resource->unloader_; +} +resource::~resource() +{ + rsrc_list.table.erase(path_); #ifdef USE_HOTLOADING - int wd = inotify_add_watch(monitor_fd_, path_.c_str(), IN_MODIFY); - set_watch_descriptor(wd); - monitor_lookup_[wd] = path_; + watch_list.remove(wd_); #endif - - delete resource; } -void resource::add_search_paths(const std::string& paths) -{ - search_paths_ = paths; -} +/*] Resource registration + *************************************************************************/ - -std::string resource::find_file(const std::string& name) +bool resource::call_registry(const std::string& ext, + loader_ptr& loader, + registry_action action) { - std::vector paths; - boost::split(paths, search_paths_, boost::is_any_of(":")); - - std::string ext = stlplus::extension_part(name); - std::string prefix("hi"); - - loader_ptr loader; - call_registry(ext, loader, lookup); - if (loader) prefix = loader->prefix(); + static std::map table; - log_info("find_file:", ext, prefix); - - std::vector::iterator it; - for (it = paths.begin(); it != paths.end(); ++it) + switch (action) { - std::string path = stlplus::create_filespec(*it, name); - log_info("looking for", name, "at", path); - if (stlplus::file_exists(path)) return path; - - // try it with the prefix added - if (!prefix.empty()) + case set: { - *it = stlplus::create_filespec(*it, prefix); - path = stlplus::create_filespec(*it, name); - log_info("looking for", name, "at", path); - if (stlplus::file_exists(path)) return path; + if (loader) table[ext] = loader; + else table.erase(ext); + break; } - } - - log_error("cannot find resource file:", name); - return std::string(); -} - -std::string resource::find_file(const std::string& name, - const std::string& ext) -{ - std::string actual_ext = stlplus::extension_part(name); - if (actual_ext != ext) - { - return find_file(stlplus::create_filename(name, ext)); + case lookup: + { + std::map::iterator it; + it = table.find(ext); + if (it != table.end()) loader = (*it).second; + break; + } } - return find_file(name); + + return loader; }