]> git.tdb.fi Git - libs/gl.git/blob - source/resourcemanager.cpp
Throw an exception if Resource::load did not create an AsyncLoader
[libs/gl.git] / source / resourcemanager.cpp
1 #include <msp/time/utils.h>
2 #include "resourcemanager.h"
3
4 using namespace std;
5
6 namespace Msp {
7 namespace GL {
8
9 ResourceManager::ResourceManager():
10         policy(LOAD_ON_DEMAND),
11         async_loads(true),
12         thread(*this)
13 { }
14
15 ResourceManager::~ResourceManager()
16 {
17         thread.terminate();
18
19         for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
20                 i->second.resource->set_manager(0);
21 }
22
23 void ResourceManager::add_resource(Resource &r)
24 {
25         insert_unique(resources, &r, ManagedResource(r));
26 }
27
28 void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
29 {
30         ManagedResource &managed = get_item(resources, &r);
31         managed.collection = &c;
32         managed.name = n;
33
34         if(policy==LOAD_IMMEDIATELY)
35                 load_resource(r);
36 }
37
38 void ResourceManager::load_resource(const Resource &r)
39 {
40         ManagedResource &managed = get_item(resources, &r);
41         if(!managed.collection)
42                 throw runtime_error("no location");
43
44         if(managed.loader)
45                 return;
46
47         managed.io = managed.collection->open_raw(managed.name);
48         managed.loader = managed.resource->load(*managed.io);
49         if(!managed.loader)
50         {
51                 delete managed.io;
52                 managed.io = 0;
53                 throw logic_error("no loader created");
54         }
55
56         queue.push_back(&managed);
57 }
58
59 void ResourceManager::remove_resource(Resource &r)
60 {
61         ManagedResource *loading = thread.get_resource();
62         if(loading && loading->resource==&r)
63                 thread.set_resource(0);
64
65         remove_existing(resources, &r);
66 }
67
68 void ResourceManager::tick()
69 {
70         LoadingThread::State thread_state = thread.get_state();
71         if(thread_state==LoadingThread::SYNC_PENDING)
72                 thread.sync();
73         else if(thread_state==LoadingThread::IDLE && !queue.empty())
74         {
75                 ManagedResource *managed = queue.front();
76                 queue.pop_front();
77                 thread.set_resource(managed);
78         }
79 }
80
81
82 ResourceManager::ManagedResource::ManagedResource(Resource &r):
83         resource(&r),
84         collection(0),
85         io(0),
86         loader(0)
87 { }
88
89
90 ResourceManager::LoadingThread::LoadingThread(ResourceManager &m):
91         manager(m),
92         sem(1),
93         resource(0),
94         state(IDLE)
95 {
96         launch();
97 }
98
99 void ResourceManager::LoadingThread::main()
100 {
101         while(state!=TERMINATING)
102         {
103                 sem.wait();
104
105                 if(state==BUSY)
106                 {
107                         Resource::AsyncLoader *ldr = resource->loader;
108                         bool finished = false;
109                         while(!finished && !ldr->needs_sync())
110                                 finished = ldr->process();
111
112                         if(finished)
113                                 state = LOAD_FINISHED;
114                         else
115                                 state = SYNC_PENDING;
116                 }
117         }
118 }
119
120 void ResourceManager::LoadingThread::set_resource(ManagedResource *r)
121 {
122         if(state!=IDLE)
123         {
124                 while(state==BUSY) ;
125                 // Force finish to clean up the loader
126                 state = LOAD_FINISHED;
127                 sync();
128         }
129
130         resource = r;
131         state = BUSY;
132         sem.signal();
133 }
134
135 void ResourceManager::LoadingThread::sync()
136 {
137         State s = state;
138         bool finished = (s==LOAD_FINISHED);
139         if(s==SYNC_PENDING)
140         {
141                 Resource::AsyncLoader *ldr = resource->loader;
142                 while(!finished && ldr->needs_sync())
143                         finished = ldr->process();
144
145                 if(!finished)
146                 {
147                         state = BUSY;
148                         sem.signal();
149                         return;
150                 }
151         }
152
153         if(finished)
154         {
155                 delete resource->loader;
156                 resource->loader = 0;
157                 delete resource->io;
158                 resource->io = 0;
159                 resource = 0;
160                 state = IDLE;
161         }
162 }
163
164 void ResourceManager::LoadingThread::terminate()
165 {
166         while(state==BUSY) ;
167         state = TERMINATING;
168         sem.signal();
169         join();
170 }
171
172 } // namespace GL
173 } // namespace Msp