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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1321 - (hide 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 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1040 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 schoenebeck 53 * *
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 schoenebeck 947 #include <vector>
30 schoenebeck 53
31 schoenebeck 947 #include "Exception.h"
32 schoenebeck 970 #include "Mutex.h"
33 schoenebeck 947
34     namespace LinuxSampler {
35    
36     /** @brief Interface class for Resource Consumers.
37     *
38 schoenebeck 53 * Interface class for consumer classes which use a resource managed
39 schoenebeck 947 * 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 schoenebeck 53 */
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 schoenebeck 517
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 schoenebeck 53 };
85    
86 schoenebeck 947 /** @brief Manager for sharing resources.
87     *
88 schoenebeck 53 * 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 schoenebeck 947 * gave back their pointer to the resource, the resource will (by default)
93     * be destroyed.
94     *
95 schoenebeck 53 * Descendants of this base class have to implement the (protected)
96     * Create() and Destroy() methods to create and destroy a resource.
97 schoenebeck 958 *
98 schoenebeck 970 * 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 schoenebeck 53 */
103     template<class T_key, class T_res>
104     class ResourceManager {
105 schoenebeck 947 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 schoenebeck 1321 typedef std::set<ResourceConsumer<T_res>*> ConsumerSet;
116    
117 schoenebeck 53 private:
118     struct resource_entry_t {
119     T_key key;
120     T_res* resource; ///< pointer to the resource
121 schoenebeck 947 mode_t mode; ///< When should the resource be created? When should it be destroyed?
122 schoenebeck 53 ConsumerSet consumers; ///< list of all consumers who currently use the resource
123 schoenebeck 947 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 schoenebeck 53 };
126     typedef std::map<T_key, resource_entry_t> ResourceMap;
127     ResourceMap ResourceEntries;
128 schoenebeck 970 Mutex ResourceEntriesMutex; // Mutex for protecting the ResourceEntries map
129 schoenebeck 53
130     public:
131     /**
132 schoenebeck 947 * Returns (the keys of) all current entries of this
133     * ResourceManager instance.
134 schoenebeck 970 *
135     * @param bLock - use thread safety mechanisms
136 schoenebeck 947 */
137 schoenebeck 970 std::vector<T_key> Entries(bool bLock = true) {
138 schoenebeck 947 std::vector<T_key> result;
139 schoenebeck 970 if (bLock) ResourceEntriesMutex.Lock();
140 schoenebeck 947 for (typename ResourceMap::iterator iter = ResourceEntries.begin();
141     iter != ResourceEntries.end(); iter++)
142     {
143     result.push_back(iter->first);
144     }
145 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
146 schoenebeck 947 return result;
147     }
148    
149     /**
150 schoenebeck 1321 * 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 schoenebeck 53 * 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 schoenebeck 970 * @param bLock - use thread safety mechanisms
198 schoenebeck 53 * @returns pointer to resource
199     */
200 schoenebeck 970 T_res* Borrow(T_key Key, ResourceConsumer<T_res>* pConsumer, bool bLock = true) {
201     if (bLock) ResourceEntriesMutex.Lock();
202 schoenebeck 947 // search for an entry for this resource
203 schoenebeck 53 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
204 schoenebeck 947 if (iterEntry == ResourceEntries.end()) { // entry doesn't exist yet
205 schoenebeck 517 // already create an entry for the resource
206 schoenebeck 53 resource_entry_t entry;
207     entry.key = Key;
208 schoenebeck 517 entry.resource = NULL;
209 schoenebeck 947 entry.mode = ON_DEMAND; // default mode
210     entry.lifearg = NULL;
211     entry.entryarg = NULL;
212 schoenebeck 517 entry.consumers.insert(pConsumer);
213     ResourceEntries[Key] = entry;
214 schoenebeck 925 try {
215     // actually create the resource
216 schoenebeck 947 entry.resource = Create(Key, pConsumer, entry.lifearg);
217 schoenebeck 925 } catch (...) {
218     // creating the resource failed, so remove the entry
219     ResourceEntries.erase(Key);
220 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
221 schoenebeck 925 // rethrow the same exception
222     throw;
223     }
224 schoenebeck 517 // now update the entry with the created resource
225     ResourceEntries[Key] = entry;
226 schoenebeck 947 OnBorrow(entry.resource, pConsumer, entry.lifearg);
227 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
228 schoenebeck 53 return entry.resource;
229 schoenebeck 947 } 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 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
237 schoenebeck 947 throw; // rethrow the same exception
238     }
239     }
240     entry.consumers.insert(pConsumer);
241     OnBorrow(entry.resource, pConsumer, entry.lifearg);
242 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
243 schoenebeck 947 return entry.resource;
244 schoenebeck 53 }
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 schoenebeck 947 * 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 schoenebeck 53 *
254     * @param pResource - pointer to resource
255     * @param pConsumer - identifier of the consumer who borrowed the
256     * resource
257 schoenebeck 970 * @param bLock - use thread safety mechanisms
258 schoenebeck 53 */
259 schoenebeck 970 void HandBack(T_res* pResource, ResourceConsumer<T_res>* pConsumer, bool bLock = true) {
260     if (bLock) ResourceEntriesMutex.Lock();
261 schoenebeck 947 // search for the entry associated with the given resource
262 schoenebeck 53 typename ResourceMap::iterator iter = ResourceEntries.begin();
263     typename ResourceMap::iterator end = ResourceEntries.end();
264     for (; iter != end; iter++) {
265 schoenebeck 947 if (iter->second.resource == pResource) { // found entry for resource
266 schoenebeck 53 resource_entry_t& entry = iter->second;
267     entry.consumers.erase(pConsumer);
268 schoenebeck 947 // remove entry if necessary
269     if (entry.mode == ON_DEMAND && !entry.entryarg && entry.consumers.empty()) {
270 persson 835 T_res* resource = entry.resource;
271 schoenebeck 947 void* arg = entry.lifearg;
272 schoenebeck 53 ResourceEntries.erase(iter);
273 schoenebeck 947 // destroy resource if necessary
274     if (resource) Destroy(resource, arg);
275 schoenebeck 53 }
276 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
277 schoenebeck 53 return;
278     }
279     }
280 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
281 schoenebeck 53 }
282    
283     /**
284 schoenebeck 947 * 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 schoenebeck 53 *
290     * @param pResource - resource to be updated
291     * @param pConsumer - consumer who requested the update
292 schoenebeck 970 * @param bLock - use thread safety mechanisms
293 schoenebeck 53 */
294 schoenebeck 970 void Update(T_res* pResource, ResourceConsumer<T_res>* pConsumer, bool bLock = true) {
295     if (bLock) ResourceEntriesMutex.Lock();
296 schoenebeck 53 typename ResourceMap::iterator iter = ResourceEntries.begin();
297     typename ResourceMap::iterator end = ResourceEntries.end();
298     for (; iter != end; iter++) {
299 schoenebeck 351 if (iter->second.resource == pResource) {
300 schoenebeck 53 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 schoenebeck 947 Destroy(entry.resource, entry.lifearg);
314     entry.resource = Create(entry.key, pConsumer, entry.lifearg);
315 schoenebeck 53 // 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 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
325 schoenebeck 53 return;
326     }
327     }
328 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
329 schoenebeck 53 }
330    
331 schoenebeck 947 /**
332     * Returns the life-time strategy of the given resource.
333     *
334 schoenebeck 970 * @param Key - ID of the resource
335     * @param bLock - use thread safety mechanisms
336 schoenebeck 947 */
337 schoenebeck 970 mode_t AvailabilityMode(T_key Key, bool bLock = true) {
338     if (bLock) ResourceEntriesMutex.Lock();
339 schoenebeck 947 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
340 schoenebeck 970 if (iterEntry == ResourceEntries.end()) {
341     if (bLock) ResourceEntriesMutex.Unlock();
342 schoenebeck 947 return ON_DEMAND; // resource entry doesn't exist, so we return the default mode
343 schoenebeck 970 }
344 schoenebeck 947 resource_entry_t& entry = iterEntry->second;
345 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
346 schoenebeck 947 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 schoenebeck 970 * @param bLock - use thread safety mechanisms
358 schoenebeck 947 * @throws Exception in case an invalid Mode was given
359     */
360 schoenebeck 1040 void SetAvailabilityMode(T_key Key, mode_t Mode, bool bLock = true) {
361 schoenebeck 947 if (Mode != ON_DEMAND && Mode != ON_DEMAND_HOLD && Mode != PERSISTENT)
362     throw Exception("ResourceManager::SetAvailabilityMode(): invalid mode");
363    
364 schoenebeck 970 if (bLock) ResourceEntriesMutex.Lock();
365 schoenebeck 947 // 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 schoenebeck 970 if (Mode == ON_DEMAND) {
370     if (bLock) ResourceEntriesMutex.Unlock();
371     return; // we don't create an entry for the default value
372     }
373 schoenebeck 947 // 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 schoenebeck 970 // done
390     if (bLock) ResourceEntriesMutex.Unlock();
391     return;
392 schoenebeck 947 }
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 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
405 schoenebeck 947 // rethrow the same exception
406     throw;
407     }
408     }
409 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
410 schoenebeck 947 }
411    
412     /**
413 schoenebeck 958 * Returns true in case the resource associated with \a Key is
414     * currently created / "alive".
415     *
416     * @param Key - ID of resource
417 schoenebeck 970 * @param bLock - use thread safety mechanisms
418 schoenebeck 958 */
419 schoenebeck 970 bool IsCreated(T_key Key, bool bLock = true) {
420     return Resource(Key, bLock) != NULL;
421 schoenebeck 958 }
422    
423     /**
424 schoenebeck 947 * Returns custom data sticked to the given resource previously by
425     * a SetCustomData() call.
426     *
427     * @param Key - ID of resource
428 schoenebeck 970 * @param bLock - use thread safety mechanisms
429 schoenebeck 947 */
430 schoenebeck 970 void* CustomData(T_key Key, bool bLock = true) {
431     if (bLock) ResourceEntriesMutex.Lock();
432 schoenebeck 947 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
433 schoenebeck 970 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 schoenebeck 947 }
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 schoenebeck 970 * @param bLock - use thread safety mechanisms
453 schoenebeck 947 */
454 schoenebeck 970 void SetCustomData(T_key Key, void* pData, bool bLock = true) {
455     if (bLock) ResourceEntriesMutex.Lock();
456 schoenebeck 947 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 schoenebeck 970 if (iterEntry == ResourceEntries.end()) {
470     if (bLock) ResourceEntriesMutex.Unlock();
471     return; // entry doesnt exist, so nothing to do
472     }
473 schoenebeck 947 // 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 schoenebeck 970 if (bLock) ResourceEntriesMutex.Unlock();
480 schoenebeck 947 }
481    
482 schoenebeck 970 /**
483     * Prevent this ResourceManager instance to be used by another
484 schoenebeck 1321 * thread at the same time. Most methods of this class are thread
485 schoenebeck 970 * 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 schoenebeck 947 virtual ~ResourceManager() {} // due to C++'s nature we cannot destroy created resources here
512    
513 schoenebeck 53 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 schoenebeck 517
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 schoenebeck 970 // no Mutex here, since Create() is already protected
568 schoenebeck 517 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 schoenebeck 958
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 schoenebeck 970 * @param bLock - use thread safety mechanisms
589 schoenebeck 958 */
590 schoenebeck 970 T_res* Resource(T_key Key, bool bLock = true) {
591     if (bLock) ResourceEntriesMutex.Lock();
592 schoenebeck 958 typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
593 schoenebeck 970 T_res* result = (iterEntry == ResourceEntries.end()) ? NULL : iterEntry->second.resource;
594     if (bLock) ResourceEntriesMutex.Unlock();
595     return result;
596 schoenebeck 958 }
597 schoenebeck 1321
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 schoenebeck 53 };
618    
619 schoenebeck 947 } // namespace LinuxSampler
620    
621 schoenebeck 53 #endif // __RESOURCE_MANAGER__

  ViewVC Help
Powered by ViewVC