/[svn]/linuxsampler/trunk/src/common/ResourceManager.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/ResourceManager.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 925 - (show annotations) (download) (as text)
Sat Oct 21 14:50:32 2006 UTC (17 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13455 byte(s)
* fixed crash when instrument loading failed previously on the same
  sampler channel (fixes bug #36)

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005, 2006 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #ifndef __RESOURCE_MANAGER__
25 #define __RESOURCE_MANAGER__
26
27 #include <set>
28 #include <map>
29
30 /**
31 * Interface class for consumer classes which use a resource managed
32 * by the ResourceManager class.
33 */
34 template<class T_res>
35 class ResourceConsumer {
36 public:
37 /**
38 * Will be called by the ResourceManager to inform the
39 * consumer that a resource currently used by him is going
40 * to be updated. The consumer can then react by stopping
41 * usage until resource is updated. The ResourceManager will
42 * not update the resource until this method returns. This
43 * method needs to be implemented by the consumer.
44 *
45 * @param pResource - resource going to be updated
46 * @param pUpdateArg - pointer the consumer might use to store
47 * informations he might need when update
48 * process was completed
49 */
50 virtual void ResourceToBeUpdated(T_res* pResource, void*& pUpdateArg) = 0;
51
52 /**
53 * Will be called by the ResourceManager to inform the
54 * consumer that resource update was completed. This method
55 * needs to be implemented by the consumer.
56 *
57 * @param pOldResource - (now invalid) pointer to the old
58 * resource
59 * @param pNewResource - (valid) pointer to the updated
60 * resource
61 * @param pUpdateArg - pointer the consumer might have used when
62 * ResourceToBeUpdated() was called
63 */
64 virtual void ResourceUpdated(T_res* pOldResource, T_res* pNewResource, void* pUpdateArg) = 0;
65
66 /**
67 * Might be called by the ResourceManager periodically during an
68 * update / creation of a resource to inform the consumer about the
69 * current progress of that process. This method needs to be
70 * implemented by the consumer.
71 *
72 * @param fProgress - current progress as value between 0.0 and 1.0
73 */
74 virtual void OnResourceProgress(float fProgress) = 0;
75 };
76
77 /**
78 * Abstract base class for sharing resources between multiple consumers.
79 * A consumer can borrow a resource from the ResourceManager, if the
80 * resource doesn't exist yet it will be created. Other consumers will
81 * just be given the same pointer to the resource then. When all consumers
82 * gave back their pointer to the resource, the resource will be destroyed.
83 * Descendants of this base class have to implement the (protected)
84 * Create() and Destroy() methods to create and destroy a resource.
85 */
86 template<class T_key, class T_res>
87 class ResourceManager {
88 private:
89 typedef std::set<ResourceConsumer<T_res>*> ConsumerSet;
90 struct resource_entry_t {
91 T_key key;
92 T_res* resource; ///< pointer to the resource
93 ConsumerSet consumers; ///< list of all consumers who currently use the resource
94 void* arg; ///< optional pointer the descendant might use to store informations about the resource
95 };
96 typedef std::map<T_key, resource_entry_t> ResourceMap;
97 ResourceMap ResourceEntries;
98
99 public:
100 virtual ~ResourceManager() {}
101 /**
102 * Borrow a resource identified by \a Key. The ResourceManager will
103 * mark the resource as in usage by the consumer given with
104 * \a pConsumer. If the Resource doesn't exist yet it will be
105 * created.
106 *
107 * @param Key - resource identifier
108 * @param pConsumer - identifier of the consumer who borrows it
109 * @returns pointer to resource
110 */
111 T_res* Borrow(T_key Key, ResourceConsumer<T_res>* pConsumer) {
112 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
113 if (iterEntry == ResourceEntries.end()) {
114 // already create an entry for the resource
115 resource_entry_t entry;
116 entry.key = Key;
117 entry.resource = NULL;
118 entry.consumers.insert(pConsumer);
119 ResourceEntries[Key] = entry;
120 try {
121 // actually create the resource
122 entry.resource = Create(Key, pConsumer, entry.arg);
123 } catch (...) {
124 // creating the resource failed, so remove the entry
125 ResourceEntries.erase(Key);
126 // rethrow the same exception
127 throw;
128 }
129 // now update the entry with the created resource
130 ResourceEntries[Key] = entry;
131 OnBorrow(entry.resource, pConsumer, entry.arg);
132 return entry.resource;
133 }
134 resource_entry_t& entry = iterEntry->second;
135 entry.consumers.insert(pConsumer);
136 OnBorrow(entry.resource, pConsumer, entry.arg);
137 return entry.resource;
138 }
139
140 /**
141 * Give back a resource. This tells the ResourceManager that the
142 * consumer given by \a pConsumer doesn't need the resource anymore.
143 * If the resource is not needed by any consumer anymore then the
144 * resource will be destroyed.
145 *
146 * @param pResource - pointer to resource
147 * @param pConsumer - identifier of the consumer who borrowed the
148 * resource
149 */
150 void HandBack(T_res* pResource, ResourceConsumer<T_res>* pConsumer) {
151 typename ResourceMap::iterator iter = ResourceEntries.begin();
152 typename ResourceMap::iterator end = ResourceEntries.end();
153 for (; iter != end; iter++) {
154 if (iter->second.resource == pResource) {
155 resource_entry_t& entry = iter->second;
156 entry.consumers.erase(pConsumer);
157 if (entry.consumers.empty()) {
158 T_res* resource = entry.resource;
159 void* arg = entry.arg;
160 ResourceEntries.erase(iter);
161 Destroy(resource, arg);
162 }
163 return;
164 }
165 }
166 }
167
168 /**
169 * Request update of a resource.
170 *
171 * @param pResource - resource to be updated
172 * @param pConsumer - consumer who requested the update
173 */
174 void Update(T_res* pResource, ResourceConsumer<T_res>* pConsumer) {
175 typename ResourceMap::iterator iter = ResourceEntries.begin();
176 typename ResourceMap::iterator end = ResourceEntries.end();
177 for (; iter != end; iter++) {
178 if (iter->second.resource == pResource) {
179 resource_entry_t& entry = iter->second;
180 // inform all consumers about pending update
181 std::map<ResourceConsumer<T_res>*,void*> updateargs;
182 typename ConsumerSet::iterator iterCons = entry.consumers.begin();
183 typename ConsumerSet::iterator endCons = entry.consumers.end();
184 for (; iterCons != endCons; iterCons++) {
185 if (*iterCons == pConsumer) continue;
186 void* updatearg = NULL;
187 (*iterCons)->ResourceToBeUpdated(entry.resource, updatearg);
188 if (updatearg) updateargs[*iterCons] = updatearg;
189 }
190 // update resource
191 T_res* pOldResource = entry.resource;
192 Destroy(entry.resource, entry.arg);
193 entry.resource = Create(entry.key, pConsumer, entry.arg);
194 // inform all consumers about update completed
195 iterCons = entry.consumers.begin();
196 endCons = entry.consumers.end();
197 for (; iterCons != endCons; iterCons++) {
198 if (*iterCons == pConsumer) continue;
199 typename std::map<ResourceConsumer<T_res>*,void*>::iterator iterArg = updateargs.find(*iterCons);
200 void* updatearg = (iterArg != updateargs.end()) ? iterArg->second : NULL;
201 (*iterCons)->ResourceUpdated(pOldResource, entry.resource, updatearg);
202 }
203 return;
204 }
205 }
206 }
207
208 protected:
209 /**
210 * Has to be implemented by the descendant to create (allocate) a
211 * resource identified by \a Key.
212 *
213 * @param Key - identifier of the resource
214 * @param pConsumer - identifier of the consumer who borrows the
215 * resource
216 * @param pArg - pointer the descendant can use to store
217 * informations he might need for destruction of
218 * the resource
219 * @returns pointer to new resource
220 */
221 virtual T_res* Create(T_key Key, ResourceConsumer<T_res>* pConsumer, void*& pArg) = 0;
222
223 /**
224 * Has to be implemented by the descendant to destroy (free) a
225 * resource pointed by \a pResource.
226 *
227 * @param pResource - pointer to the resource
228 * @param pArg - pointer the descendant might have used when
229 * Create() was called to store informations
230 * about the resource
231 */
232 virtual void Destroy(T_res* pResource, void* pArg) = 0;
233
234 /**
235 * Has to be implemented by the descendant to react when a consumer
236 * borrows a resource (no matter if freshly created or an already
237 * created one). Of course reacting is optional, but the descendant
238 * at least has to provide a method with empty body.
239 *
240 * @param pResource - pointer to the resource
241 * @param pConsumer - identifier of the consumer who borrows the
242 * resource
243 * @param pArg - pointer the descendant might have used when
244 * Create() was called to store informations
245 * about the resource, this information can be
246 * updated by the descendant here
247 */
248 virtual void OnBorrow(T_res* pResource, ResourceConsumer<T_res>* pConsumer, void*& pArg) = 0;
249
250 /**
251 * Dispatcher method which should be periodically called by the
252 * descendant during update or creation of the resource associated
253 * with \a Key. This method will inform all associated consumers
254 * of the given resource about the current progress.
255 *
256 * @param Key - unique identifier of the resource which is
257 * currently creating or updating
258 * @param fProgress - current progress of that creation / update
259 * process as value between 0.0 and 1.0
260 */
261 void DispatchResourceProgressEvent(T_key Key, float fProgress) {
262 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
263 if (iterEntry != ResourceEntries.end()) {
264 resource_entry_t& entry = iterEntry->second;
265 // inform all consumers of that resource about current progress
266 typename ConsumerSet::iterator iterCons = entry.consumers.begin();
267 typename ConsumerSet::iterator endCons = entry.consumers.end();
268 for (; iterCons != endCons; iterCons++) {
269 (*iterCons)->OnResourceProgress(fProgress);
270 }
271 }
272 }
273 };
274
275 #endif // __RESOURCE_MANAGER__

  ViewVC Help
Powered by ViewVC