]> git.tdb.fi Git - libs/gl.git/blobdiff - source/resourcemanager.cpp
Make ResourceManager thread-safe
[libs/gl.git] / source / resourcemanager.cpp
index c6e3f357b9ce67b6f72fef04f30b5ff5e96483ab..52e5866a6aa887ce536d704f528dfbc5051f06cf 100644 (file)
@@ -4,6 +4,7 @@
 #include <msp/strings/format.h>
 #include <msp/time/utils.h>
 #include "resourcemanager.h"
+#include "resources.h"
 #include "resourcewatcher.h"
 
 using namespace std;
@@ -11,6 +12,10 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
+resource_load_error::resource_load_error(const string &name, const string &err):
+       runtime_error(format("%s: %s", name, err))
+{ }
+
 resource_load_error::resource_load_error(const string &name, const exception &exc):
        runtime_error(format("%s: %s: %s", name, Debug::demangle(typeid(exc).name()), exc.what()))
 { }
@@ -61,28 +66,49 @@ void ResourceManager::set_max_retain_frames(unsigned f)
 
 void ResourceManager::add_resource(Resource &r)
 {
+       MutexLock lock(map_mutex);
        insert_unique(resources, &r, ManagedResource(r));
 }
 
-void *ResourceManager::get_data_for_resource(const Resource &r)
+const ResourceManager::ManagedResource &ResourceManager::get_managed_resource(const Resource &r) const
+{
+       MutexLock lock(map_mutex);
+       return get_item(resources, &r);
+}
+
+ResourceManager::ManagedResource &ResourceManager::get_managed_resource(const Resource &r)
 {
-       return &get_item(resources, &r);
+       MutexLock lock(map_mutex);
+       return get_item(resources, &r);
 }
 
 void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
 {
-       ManagedResource &managed = get_item(resources, &r);
-       managed.collection = &c;
-       managed.name = n;
+       set_resource_location(r, ResourceLocation(c, n));
+}
+
+void ResourceManager::set_resource_location(Resource &r, const ResourceLocation &l)
+{
+       {
+               MutexLock lock(map_mutex);
+               ManagedResource &managed = get_item(resources, &r);
+               managed.location = l;
+       }
 
        if(policy==LOAD_IMMEDIATELY)
                load_resource(r);
 }
 
+const ResourceManager::ResourceLocation *ResourceManager::get_resource_location(const Resource &r) const
+{
+       const ManagedResource &managed = get_managed_resource(r);
+       return managed.location.collection ? &managed.location : 0;
+}
+
 void ResourceManager::load_resource(Resource &r)
 {
-       ManagedResource &managed = get_item(resources, &r);
-       if(!managed.collection)
+       ManagedResource &managed = get_managed_resource(r);
+       if(!managed.location.collection)
                throw runtime_error("no location");
 
        if(managed.state!=ManagedResource::NOT_LOADED)
@@ -91,7 +117,9 @@ void ResourceManager::load_resource(Resource &r)
        if(async_loads)
        {
                managed.state = ManagedResource::LOAD_QUEUED;
-               queue.push_back(&managed);
+               LoadQueue::iterator i;
+               for(i=queue.begin(); (i!=queue.end() && (*i)->load_priority>=managed.load_priority); ++i) ;
+               queue.insert(i, &managed);
        }
        else
        {
@@ -101,9 +129,17 @@ void ResourceManager::load_resource(Resource &r)
        }
 }
 
+bool ResourceManager::is_resource_loaded(const Resource &r) const
+{
+       ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
+       return managed ? managed->state==ManagedResource::LOADED : false;
+}
+
 void ResourceManager::resource_used(const Resource &r)
 {
        ManagedResource *managed = reinterpret_cast<ManagedResource *>(r.get_manager_data());
+       if(!managed)
+               return;
        if(managed->state==ManagedResource::NOT_LOADED && policy!=LOAD_MANUALLY)
                load_resource(*managed->resource);
 
@@ -114,7 +150,7 @@ void ResourceManager::resource_used(const Resource &r)
 
 void ResourceManager::remove_resource(Resource &r)
 {
-       ManagedResource &managed = get_item(resources, &r);
+       ManagedResource &managed = get_managed_resource(r);
        ManagedResource::State state = managed.state;
        if(state==ManagedResource::LOAD_QUEUED)
        {
@@ -124,17 +160,19 @@ void ResourceManager::remove_resource(Resource &r)
        }
        else if(state>ManagedResource::LOAD_QUEUED && state<ManagedResource::LOADED)
                thread.remove_resource(managed);
+
+       MutexLock lock(map_mutex);
        remove_existing(resources, &r);
 }
 
 void ResourceManager::watch_resource(const Resource &r, ResourceWatcher &w)
 {
-       get_item(resources, &r).add_watcher(w);
+       get_managed_resource(r).add_watcher(w);
 }
 
 void ResourceManager::unwatch_resource(const Resource &r, ResourceWatcher &w)
 {
-       get_item(resources, &r).remove_watcher(w);
+       get_managed_resource(r).remove_watcher(w);
 }
 
 void ResourceManager::tick()
@@ -150,6 +188,7 @@ void ResourceManager::tick()
 
        if(do_unload)
        {
+               MutexLock lock(map_mutex);
                if(max_retain_frames && frame>=next_unload)
                {
                        unload_by_age();
@@ -199,7 +238,7 @@ void ResourceManager::unload_by_size()
 {
        unsigned unload_limit = frame-min_retain_frames;
 
-       while(get_total_data_size()>size_limit)
+       while(get_total_data_size_()>size_limit)
        {
                ManagedResource *best = 0;
                UInt64 best_impact = 0;
@@ -221,7 +260,7 @@ void ResourceManager::unload_by_size()
        }
 }
 
-UInt64 ResourceManager::get_total_data_size() const
+UInt64 ResourceManager::get_total_data_size_() const
 {
        UInt64 total = 0;
        for(ResourceMap::const_iterator i=resources.begin(); i!=resources.end(); ++i)
@@ -230,15 +269,31 @@ UInt64 ResourceManager::get_total_data_size() const
        return total;
 }
 
+UInt64 ResourceManager::get_total_data_size() const
+{
+       MutexLock lock(map_mutex);
+       return get_total_data_size_();
+}
+
 bool ResourceManager::age_order(ManagedResource *mr1, ManagedResource *mr2)
 {
        return mr1->last_used>mr2->last_used;
 }
 
 
+ResourceManager::ResourceLocation::ResourceLocation():
+       collection(0)
+{ }
+
+ResourceManager::ResourceLocation::ResourceLocation(DataFile::Collection &c, const string &n):
+       collection(&c),
+       name(n)
+{ }
+
+
 ResourceManager::ManagedResource::ManagedResource(Resource &r):
        resource(&r),
-       collection(0),
+       load_priority(r.get_load_priority()),
        io(0),
        loader(0),
        state(NOT_LOADED),
@@ -248,8 +303,12 @@ ResourceManager::ManagedResource::ManagedResource(Resource &r):
 
 void ResourceManager::ManagedResource::start_loading()
 {
-       io = collection->open_raw(name);
-       loader = resource->load(*io);
+       io = location.collection->open_raw(location.name);
+       if(!io)
+               throw resource_load_error(location.name, "open failed");
+
+       const Resources *res = dynamic_cast<Resources *>(location.collection);
+       loader = resource->load(*io, res);
        if(!loader)
        {
                delete io;
@@ -344,7 +403,7 @@ void ResourceManager::LoadingThread::main()
                        catch(const exception &e)
                        {
                                MutexLock lock(queue_mutex);
-                               error_queue.push_back(resource_load_error(managed->name, e));
+                               error_queue.push_back(resource_load_error(managed->location.name, e));
                                managed->state = ManagedResource::LOAD_ERROR;
                        }
 
@@ -401,12 +460,18 @@ bool ResourceManager::LoadingThread::try_remove_resource(ManagedResource &r)
        {
                i = find(sync_queue.begin(), sync_queue.end(), &r);
                if(i!=sync_queue.end())
+               {
                        sync_queue.erase(i);
+                       --size;
+               }
        }
        else if(i==async_queue.begin())
                return false;
        else
+       {
                async_queue.erase(i);
+               --size;
+       }
 
        return true;
 }