/[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 1321 - (show annotations) (download) (as text)
Tue Sep 4 01:12:49 2007 UTC (16 years, 7 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 29273 byte(s)
* added highly experimental code for synchronizing instrument editors
  hosted in the sampler's process to safely edit instruments while playing
  without a crash (hopefully) by either suspending single regions wherever
  possible or - if unavoidable - whole engine(s)
* disk thread: queue sizes are now proportional to CONFIG_MAX_STREAMS
  instead of fix values
* removed legacy Makefiles in meanwhile deleted src/lib directory and its
  subdirectories
* bumped version to 0.4.0.7cvs

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2007 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 #include <vector>
30
31 #include "Exception.h"
32 #include "Mutex.h"
33
34 namespace LinuxSampler {
35
36 /** @brief Interface class for Resource Consumers.
37 *
38 * Interface class for consumer classes which use a resource managed
39 * by the ResourceManager class. All classes which use the ResourceManager
40 * to aquire resources have to derive from this interface class and
41 * implement the abstract methods.
42 */
43 template<class T_res>
44 class ResourceConsumer {
45 public:
46 /**
47 * Will be called by the ResourceManager to inform the
48 * consumer that a resource currently used by him is going
49 * to be updated. The consumer can then react by stopping
50 * usage until resource is updated. The ResourceManager will
51 * not update the resource until this method returns. This
52 * method needs to be implemented by the consumer.
53 *
54 * @param pResource - resource going to be updated
55 * @param pUpdateArg - pointer the consumer might use to store
56 * informations he might need when update
57 * process was completed
58 */
59 virtual void ResourceToBeUpdated(T_res* pResource, void*& pUpdateArg) = 0;
60
61 /**
62 * Will be called by the ResourceManager to inform the
63 * consumer that resource update was completed. This method
64 * needs to be implemented by the consumer.
65 *
66 * @param pOldResource - (now invalid) pointer to the old
67 * resource
68 * @param pNewResource - (valid) pointer to the updated
69 * resource
70 * @param pUpdateArg - pointer the consumer might have used when
71 * ResourceToBeUpdated() was called
72 */
73 virtual void ResourceUpdated(T_res* pOldResource, T_res* pNewResource, void* pUpdateArg) = 0;
74
75 /**
76 * Might be called by the ResourceManager periodically during an
77 * update / creation of a resource to inform the consumer about the
78 * current progress of that process. This method needs to be
79 * implemented by the consumer.
80 *
81 * @param fProgress - current progress as value between 0.0 and 1.0
82 */
83 virtual void OnResourceProgress(float fProgress) = 0;
84 };
85
86 /** @brief Manager for sharing resources.
87 *
88 * Abstract base class for sharing resources between multiple consumers.
89 * A consumer can borrow a resource from the ResourceManager, if the
90 * resource doesn't exist yet it will be created. Other consumers will
91 * just be given the same pointer to the resource then. When all consumers
92 * gave back their pointer to the resource, the resource will (by default)
93 * be destroyed.
94 *
95 * Descendants of this base class have to implement the (protected)
96 * Create() and Destroy() methods to create and destroy a resource.
97 *
98 * This class is thread safe (by default). Its methods should however not
99 * be called in a realtime context due to this! Alternatively one can
100 * call the respective methods with bLock = false, in that case thread
101 * safety mechanisms will be omitted - use with care !
102 */
103 template<class T_key, class T_res>
104 class ResourceManager {
105 public:
106 /**
107 * Defines life-time strategy for resources.
108 */
109 enum mode_t {
110 ON_DEMAND = 0, ///< Create resource when needed, free it once not needed anymore (default behavior).
111 ON_DEMAND_HOLD = 1, ///< Create resource when needed and keep it even if not needed anymore.
112 PERSISTENT = 2 ///< Immediately create resource and keep it.
113 };
114
115 typedef std::set<ResourceConsumer<T_res>*> ConsumerSet;
116
117 private:
118 struct resource_entry_t {
119 T_key key;
120 T_res* resource; ///< pointer to the resource
121 mode_t mode; ///< When should the resource be created? When should it be destroyed?
122 ConsumerSet consumers; ///< list of all consumers who currently use the resource
123 void* lifearg; ///< optional pointer the descendant might use to store informations about a created resource
124 void* entryarg; ///< optional pointer the descendant might use to store informations about an entry
125 };
126 typedef std::map<T_key, resource_entry_t> ResourceMap;
127 ResourceMap ResourceEntries;
128 Mutex ResourceEntriesMutex; // Mutex for protecting the ResourceEntries map
129
130 public:
131 /**
132 * Returns (the keys of) all current entries of this
133 * ResourceManager instance.
134 *
135 * @param bLock - use thread safety mechanisms
136 */
137 std::vector<T_key> Entries(bool bLock = true) {
138 std::vector<T_key> result;
139 if (bLock) ResourceEntriesMutex.Lock();
140 for (typename ResourceMap::iterator iter = ResourceEntries.begin();
141 iter != ResourceEntries.end(); iter++)
142 {
143 result.push_back(iter->first);
144 }
145 if (bLock) ResourceEntriesMutex.Unlock();
146 return result;
147 }
148
149 /**
150 * Returns a list of all consumers that use the resource given by
151 * \a Key .
152 *
153 * @e Caution: this is not thread safe! You might want to call
154 * @c Lock() and @c Unlock() respectively to avoid race conditions
155 * while using this method and its result set!
156 *
157 * @param Key - resource identifier
158 */
159 ConsumerSet ConsumersOf(T_key Key) {
160 // search for an entry for the given resource key
161 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
162 return (iterEntry == ResourceEntries.end()) ?
163 ConsumerSet() : iterEntry->second.consumers;
164 }
165
166 /**
167 * Returns a list of all consumers that use the resource given by
168 * \a pResource .
169 *
170 * @e Caution: this is not thread safe! You might want to call
171 * @c Lock() and @c Unlock() respectively to avoid race conditions
172 * while using this method and its result set!
173 *
174 * @param pResource - resource pointer
175 */
176 ConsumerSet ConsumersOf(T_res* pResource) {
177 // search for the entry associated with the given resource
178 typename ResourceMap::iterator iter = ResourceEntries.begin();
179 typename ResourceMap::iterator end = ResourceEntries.end();
180 for (; iter != end; iter++) {
181 if (iter->second.resource == pResource) { // found entry for resource
182 return iter->second.consumers;
183 }
184 }
185 // no entry found for resource ...
186 return ConsumerSet();
187 }
188
189 /**
190 * Borrow a resource identified by \a Key. The ResourceManager will
191 * mark the resource as in usage by the consumer given with
192 * \a pConsumer. If the Resource doesn't exist yet it will be
193 * created.
194 *
195 * @param Key - resource identifier
196 * @param pConsumer - identifier of the consumer who borrows it
197 * @param bLock - use thread safety mechanisms
198 * @returns pointer to resource
199 */
200 T_res* Borrow(T_key Key, ResourceConsumer<T_res>* pConsumer, bool bLock = true) {
201 if (bLock) ResourceEntriesMutex.Lock();
202 // search for an entry for this resource
203 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
204 if (iterEntry == ResourceEntries.end()) { // entry doesn't exist yet
205 // already create an entry for the resource
206 resource_entry_t entry;
207 entry.key = Key;
208 entry.resource = NULL;
209 entry.mode = ON_DEMAND; // default mode
210 entry.lifearg = NULL;
211 entry.entryarg = NULL;
212 entry.consumers.insert(pConsumer);
213 ResourceEntries[Key] = entry;
214 try {
215 // actually create the resource
216 entry.resource = Create(Key, pConsumer, entry.lifearg);
217 } catch (...) {
218 // creating the resource failed, so remove the entry
219 ResourceEntries.erase(Key);
220 if (bLock) ResourceEntriesMutex.Unlock();
221 // rethrow the same exception
222 throw;
223 }
224 // now update the entry with the created resource
225 ResourceEntries[Key] = entry;
226 OnBorrow(entry.resource, pConsumer, entry.lifearg);
227 if (bLock) ResourceEntriesMutex.Unlock();
228 return entry.resource;
229 } else { // entry already exists
230 resource_entry_t& entry = iterEntry->second;
231 if (!entry.resource) { // create resource if not created already
232 try {
233 entry.resource = Create(Key, pConsumer, entry.lifearg);
234 } catch (...) {
235 entry.resource = NULL;
236 if (bLock) ResourceEntriesMutex.Unlock();
237 throw; // rethrow the same exception
238 }
239 }
240 entry.consumers.insert(pConsumer);
241 OnBorrow(entry.resource, pConsumer, entry.lifearg);
242 if (bLock) ResourceEntriesMutex.Unlock();
243 return entry.resource;
244 }
245 }
246
247 /**
248 * Give back a resource. This tells the ResourceManager that the
249 * consumer given by \a pConsumer doesn't need the resource anymore.
250 * If the resource is not needed by any consumer anymore and the
251 * resource has a life-time strategy of ON_DEMAND (which is the
252 * default setting) then the resource will be destroyed.
253 *
254 * @param pResource - pointer to resource
255 * @param pConsumer - identifier of the consumer who borrowed the
256 * resource
257 * @param bLock - use thread safety mechanisms
258 */
259 void HandBack(T_res* pResource, ResourceConsumer<T_res>* pConsumer, bool bLock = true) {
260 if (bLock) ResourceEntriesMutex.Lock();
261 // search for the entry associated with the given resource
262 typename ResourceMap::iterator iter = ResourceEntries.begin();
263 typename ResourceMap::iterator end = ResourceEntries.end();
264 for (; iter != end; iter++) {
265 if (iter->second.resource == pResource) { // found entry for resource
266 resource_entry_t& entry = iter->second;
267 entry.consumers.erase(pConsumer);
268 // remove entry if necessary
269 if (entry.mode == ON_DEMAND && !entry.entryarg && entry.consumers.empty()) {
270 T_res* resource = entry.resource;
271 void* arg = entry.lifearg;
272 ResourceEntries.erase(iter);
273 // destroy resource if necessary
274 if (resource) Destroy(resource, arg);
275 }
276 if (bLock) ResourceEntriesMutex.Unlock();
277 return;
278 }
279 }
280 if (bLock) ResourceEntriesMutex.Unlock();
281 }
282
283 /**
284 * Request update of a resource. All consumers will be informed
285 * about the pending update of the resource so they can safely react
286 * by stopping its usage first, then the resource will be recreated
287 * and finally the consumers will be informed once the update was
288 * completed, so they can continue to use the resource.
289 *
290 * @param pResource - resource to be updated
291 * @param pConsumer - consumer who requested the update
292 * @param bLock - use thread safety mechanisms
293 */
294 void Update(T_res* pResource, ResourceConsumer<T_res>* pConsumer, bool bLock = true) {
295 if (bLock) ResourceEntriesMutex.Lock();
296 typename ResourceMap::iterator iter = ResourceEntries.begin();
297 typename ResourceMap::iterator end = ResourceEntries.end();
298 for (; iter != end; iter++) {
299 if (iter->second.resource == pResource) {
300 resource_entry_t& entry = iter->second;
301 // inform all consumers about pending update
302 std::map<ResourceConsumer<T_res>*,void*> updateargs;
303 typename ConsumerSet::iterator iterCons = entry.consumers.begin();
304 typename ConsumerSet::iterator endCons = entry.consumers.end();
305 for (; iterCons != endCons; iterCons++) {
306 if (*iterCons == pConsumer) continue;
307 void* updatearg = NULL;
308 (*iterCons)->ResourceToBeUpdated(entry.resource, updatearg);
309 if (updatearg) updateargs[*iterCons] = updatearg;
310 }
311 // update resource
312 T_res* pOldResource = entry.resource;
313 Destroy(entry.resource, entry.lifearg);
314 entry.resource = Create(entry.key, pConsumer, entry.lifearg);
315 // inform all consumers about update completed
316 iterCons = entry.consumers.begin();
317 endCons = entry.consumers.end();
318 for (; iterCons != endCons; iterCons++) {
319 if (*iterCons == pConsumer) continue;
320 typename std::map<ResourceConsumer<T_res>*,void*>::iterator iterArg = updateargs.find(*iterCons);
321 void* updatearg = (iterArg != updateargs.end()) ? iterArg->second : NULL;
322 (*iterCons)->ResourceUpdated(pOldResource, entry.resource, updatearg);
323 }
324 if (bLock) ResourceEntriesMutex.Unlock();
325 return;
326 }
327 }
328 if (bLock) ResourceEntriesMutex.Unlock();
329 }
330
331 /**
332 * Returns the life-time strategy of the given resource.
333 *
334 * @param Key - ID of the resource
335 * @param bLock - use thread safety mechanisms
336 */
337 mode_t AvailabilityMode(T_key Key, bool bLock = true) {
338 if (bLock) ResourceEntriesMutex.Lock();
339 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
340 if (iterEntry == ResourceEntries.end()) {
341 if (bLock) ResourceEntriesMutex.Unlock();
342 return ON_DEMAND; // resource entry doesn't exist, so we return the default mode
343 }
344 resource_entry_t& entry = iterEntry->second;
345 if (bLock) ResourceEntriesMutex.Unlock();
346 return entry.mode;
347 }
348
349 /**
350 * Change life-time strategy of the given resource. If a life-time
351 * strategy of PERSISTENT was given and the resource was not created
352 * yet, it will immediately be created and this method will block
353 * until the resource creation was completed.
354 *
355 * @param Key - ID of the resource
356 * @param Mode - life-time strategy of resource to be set
357 * @param bLock - use thread safety mechanisms
358 * @throws Exception in case an invalid Mode was given
359 */
360 void SetAvailabilityMode(T_key Key, mode_t Mode, bool bLock = true) {
361 if (Mode != ON_DEMAND && Mode != ON_DEMAND_HOLD && Mode != PERSISTENT)
362 throw Exception("ResourceManager::SetAvailabilityMode(): invalid mode");
363
364 if (bLock) ResourceEntriesMutex.Lock();
365 // search for an entry for this resource
366 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
367 resource_entry_t* pEntry = NULL;
368 if (iterEntry == ResourceEntries.end()) { // resource entry doesn't exist
369 if (Mode == ON_DEMAND) {
370 if (bLock) ResourceEntriesMutex.Unlock();
371 return; // we don't create an entry for the default value
372 }
373 // create an entry for the resource
374 pEntry = &ResourceEntries[Key];
375 pEntry->key = Key;
376 pEntry->resource = NULL;
377 pEntry->mode = Mode;
378 pEntry->lifearg = NULL;
379 pEntry->entryarg = NULL;
380 } else { // resource entry exists
381 pEntry = &iterEntry->second;
382 // remove entry if necessary
383 if (Mode == ON_DEMAND && !pEntry->entryarg && pEntry->consumers.empty()) {
384 T_res* resource = pEntry->resource;
385 void* arg = pEntry->lifearg;
386 ResourceEntries.erase(iterEntry);
387 // destroy resource if necessary
388 if (resource) Destroy(resource, arg);
389 // done
390 if (bLock) ResourceEntriesMutex.Unlock();
391 return;
392 }
393 pEntry->mode = Mode; // apply new mode
394 }
395
396 // already create the resource if necessary
397 if (pEntry->mode == PERSISTENT && !pEntry->resource) {
398 try {
399 // actually create the resource
400 pEntry->resource = Create(Key, NULL /*no consumer yet*/, pEntry->lifearg);
401 } catch (...) {
402 // creating the resource failed, so skip it for now
403 pEntry->resource = NULL;
404 if (bLock) ResourceEntriesMutex.Unlock();
405 // rethrow the same exception
406 throw;
407 }
408 }
409 if (bLock) ResourceEntriesMutex.Unlock();
410 }
411
412 /**
413 * Returns true in case the resource associated with \a Key is
414 * currently created / "alive".
415 *
416 * @param Key - ID of resource
417 * @param bLock - use thread safety mechanisms
418 */
419 bool IsCreated(T_key Key, bool bLock = true) {
420 return Resource(Key, bLock) != NULL;
421 }
422
423 /**
424 * Returns custom data sticked to the given resource previously by
425 * a SetCustomData() call.
426 *
427 * @param Key - ID of resource
428 * @param bLock - use thread safety mechanisms
429 */
430 void* CustomData(T_key Key, bool bLock = true) {
431 if (bLock) ResourceEntriesMutex.Lock();
432 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
433 if (iterEntry == ResourceEntries.end()) {
434 if (bLock) ResourceEntriesMutex.Unlock();
435 return NULL; // resource entry doesn't exist, so we return the default mode
436 }
437 resource_entry_t entry = iterEntry->second;
438 void* res = entry.entryarg;
439 if (bLock) ResourceEntriesMutex.Unlock();
440 return res;
441 }
442
443 /**
444 * This method can be used to stick custom data to an resource
445 * entry. In case the custom data is not needed anymore, you should
446 * call this method again and set \a pData to NULL, so the
447 * ResourceManager might safe space by removing the respective
448 * entry if not needed anymore.
449 *
450 * @param Key - ID of resource
451 * @param pData - pointer to custom data, or NULL if not needed anymore
452 * @param bLock - use thread safety mechanisms
453 */
454 void SetCustomData(T_key Key, void* pData, bool bLock = true) {
455 if (bLock) ResourceEntriesMutex.Lock();
456 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
457 if (pData) {
458 if (iterEntry == ResourceEntries.end()) { // entry doesnt exist, so create one
459 resource_entry_t* pEntry = &ResourceEntries[Key];
460 pEntry->key = Key;
461 pEntry->resource = NULL;
462 pEntry->mode = ON_DEMAND;
463 pEntry->lifearg = NULL;
464 pEntry->entryarg = pData; // set custom data
465 } else { // entry exists, so just update its custom data
466 iterEntry->second.entryarg = pData;
467 }
468 } else { // !pData
469 if (iterEntry == ResourceEntries.end()) {
470 if (bLock) ResourceEntriesMutex.Unlock();
471 return; // entry doesnt exist, so nothing to do
472 }
473 // entry exists, remove it if necessary
474 resource_entry_t* pEntry = &iterEntry->second;
475 if (pEntry->mode == ON_DEMAND && pEntry->consumers.empty()) {
476 ResourceEntries.erase(iterEntry);
477 } else iterEntry->second.entryarg = NULL;
478 }
479 if (bLock) ResourceEntriesMutex.Unlock();
480 }
481
482 /**
483 * Prevent this ResourceManager instance to be used by another
484 * thread at the same time. Most methods of this class are thread
485 * safe by default. However sometimes you might need atomicity among
486 * a sequence of method calls. In this case you would first call
487 * this Lock() method, call the respective operational methods of
488 * this class (<b>Important:</b> each one by setting bLock = false,
489 * this avoids double locking). And once the required sequence of
490 * atomic method calls is done, you have to call Unlock() to
491 * reenable accessibility of this ResourceManager instance for other
492 * threads.
493 *
494 * @see Mutex::Lock()
495 */
496 void Lock() {
497 ResourceEntriesMutex.Lock();
498 }
499
500 /**
501 * Has to be called after a Lock() call to reenable this
502 * ResourceManager instance to be accessible by another thread
503 * again.
504 *
505 * @see Mutex::Unlock()
506 */
507 void Unlock() {
508 ResourceEntriesMutex.Unlock();
509 }
510
511 virtual ~ResourceManager() {} // due to C++'s nature we cannot destroy created resources here
512
513 protected:
514 /**
515 * Has to be implemented by the descendant to create (allocate) a
516 * resource identified by \a Key.
517 *
518 * @param Key - identifier of the resource
519 * @param pConsumer - identifier of the consumer who borrows the
520 * resource
521 * @param pArg - pointer the descendant can use to store
522 * informations he might need for destruction of
523 * the resource
524 * @returns pointer to new resource
525 */
526 virtual T_res* Create(T_key Key, ResourceConsumer<T_res>* pConsumer, void*& pArg) = 0;
527
528 /**
529 * Has to be implemented by the descendant to destroy (free) a
530 * resource pointed by \a pResource.
531 *
532 * @param pResource - pointer to the resource
533 * @param pArg - pointer the descendant might have used when
534 * Create() was called to store informations
535 * about the resource
536 */
537 virtual void Destroy(T_res* pResource, void* pArg) = 0;
538
539 /**
540 * Has to be implemented by the descendant to react when a consumer
541 * borrows a resource (no matter if freshly created or an already
542 * created one). Of course reacting is optional, but the descendant
543 * at least has to provide a method with empty body.
544 *
545 * @param pResource - pointer to the resource
546 * @param pConsumer - identifier of the consumer who borrows the
547 * resource
548 * @param pArg - pointer the descendant might have used when
549 * Create() was called to store informations
550 * about the resource, this information can be
551 * updated by the descendant here
552 */
553 virtual void OnBorrow(T_res* pResource, ResourceConsumer<T_res>* pConsumer, void*& pArg) = 0;
554
555 /**
556 * Dispatcher method which should be periodically called by the
557 * descendant during update or creation of the resource associated
558 * with \a Key. This method will inform all associated consumers
559 * of the given resource about the current progress.
560 *
561 * @param Key - unique identifier of the resource which is
562 * currently creating or updating
563 * @param fProgress - current progress of that creation / update
564 * process as value between 0.0 and 1.0
565 */
566 void DispatchResourceProgressEvent(T_key Key, float fProgress) {
567 // no Mutex here, since Create() is already protected
568 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
569 if (iterEntry != ResourceEntries.end()) {
570 resource_entry_t& entry = iterEntry->second;
571 // inform all consumers of that resource about current progress
572 typename ConsumerSet::iterator iterCons = entry.consumers.begin();
573 typename ConsumerSet::iterator endCons = entry.consumers.end();
574 for (; iterCons != endCons; iterCons++) {
575 (*iterCons)->OnResourceProgress(fProgress);
576 }
577 }
578 }
579
580 /**
581 * Returns pointer to the resource associated with \a Key if
582 * currently created / "alive", NULL otherwise. This method
583 * should be taken with great care in multi-threaded scenarios,
584 * since the returned resource might be destroyed by a concurrent
585 * HandBack() call.
586 *
587 * @param Key - ID of resource
588 * @param bLock - use thread safety mechanisms
589 */
590 T_res* Resource(T_key Key, bool bLock = true) {
591 if (bLock) ResourceEntriesMutex.Lock();
592 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
593 T_res* result = (iterEntry == ResourceEntries.end()) ? NULL : iterEntry->second.resource;
594 if (bLock) ResourceEntriesMutex.Unlock();
595 return result;
596 }
597
598 /**
599 * Returns a list with all currently created / "living" resources.
600 * This method should be taken with great care in multi-threaded
601 * scenarios, since the returned resources might be destroyed by a
602 * concurrent HandBack() call.
603 *
604 * @param bLock - use thread safety mechanisms
605 */
606 std::vector<T_res*> Resources(bool bLock = true) {
607 if (bLock) ResourceEntriesMutex.Lock();
608 std::vector<T_res*> result;
609 typename ResourceMap::iterator iter = ResourceEntries.begin();
610 typename ResourceMap::iterator end = ResourceEntries.end();
611 for (; iter != end; ++iter)
612 if (iter->second.resource)
613 result.push_back(iter->second.resource);
614 if (bLock) ResourceEntriesMutex.Unlock();
615 return result;
616 }
617 };
618
619 } // namespace LinuxSampler
620
621 #endif // __RESOURCE_MANAGER__

  ViewVC Help
Powered by ViewVC