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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 946 by schoenebeck, Sat Oct 21 14:50:32 2006 UTC revision 947 by schoenebeck, Mon Nov 27 21:34:55 2006 UTC
# Line 26  Line 26 
26    
27  #include <set>  #include <set>
28  #include <map>  #include <map>
29    #include <vector>
30    
31  /**  #include "Exception.h"
32    
33    namespace LinuxSampler {
34    
35    /** @brief Interface class for Resource Consumers.
36     *
37   * Interface class for consumer classes which use a resource managed   * Interface class for consumer classes which use a resource managed
38   * by the ResourceManager class.   * by the ResourceManager class. All classes which use the ResourceManager
39     * to aquire resources have to derive from this interface class and
40     * implement the abstract methods.
41   */   */
42  template<class T_res>  template<class T_res>
43  class ResourceConsumer {  class ResourceConsumer {
# Line 74  class ResourceConsumer { Line 82  class ResourceConsumer {
82          virtual void OnResourceProgress(float fProgress) = 0;          virtual void OnResourceProgress(float fProgress) = 0;
83  };  };
84    
85  /**  /** @brief Manager for sharing resources.
86     *
87   * Abstract base class for sharing resources between multiple consumers.   * Abstract base class for sharing resources between multiple consumers.
88   * A consumer can borrow a resource from the ResourceManager, if the   * A consumer can borrow a resource from the ResourceManager, if the
89   * resource doesn't exist yet it will be created. Other consumers will   * resource doesn't exist yet it will be created. Other consumers will
90   * just be given the same pointer to the resource then. When all consumers   * just be given the same pointer to the resource then. When all consumers
91   * gave back their pointer to the resource, the resource will be destroyed.   * gave back their pointer to the resource, the resource will (by default)
92     * be destroyed.
93     *
94   * Descendants of this base class have to implement the (protected)   * Descendants of this base class have to implement the (protected)
95   * Create() and Destroy() methods to create and destroy a resource.   * Create() and Destroy() methods to create and destroy a resource.
96   */   */
97  template<class T_key, class T_res>  template<class T_key, class T_res>
98  class ResourceManager {  class ResourceManager {
99        public:
100            /**
101             * Defines life-time strategy for resources.
102             */
103            enum mode_t {
104                ON_DEMAND      = 0, ///< Create resource when needed, free it once not needed anymore (default behavior).
105                ON_DEMAND_HOLD = 1, ///< Create resource when needed and keep it even if not needed anymore.
106                PERSISTENT     = 2  ///< Immediately create resource and keep it.
107            };
108    
109      private:      private:
110          typedef std::set<ResourceConsumer<T_res>*> ConsumerSet;          typedef std::set<ResourceConsumer<T_res>*> ConsumerSet;
111          struct resource_entry_t {          struct resource_entry_t {
112              T_key       key;              T_key       key;
113              T_res*      resource;  ///< pointer to the resource              T_res*      resource;  ///< pointer to the resource
114                mode_t      mode;      ///< When should the resource be created? When should it be destroyed?
115              ConsumerSet consumers; ///< list of all consumers who currently use the resource              ConsumerSet consumers; ///< list of all consumers who currently use the resource
116              void*       arg;       ///< optional pointer the descendant might use to store informations about the resource              void*       lifearg;   ///< optional pointer the descendant might use to store informations about a created resource
117                void*       entryarg;  ///< optional pointer the descendant might use to store informations about an entry
118          };          };
119          typedef std::map<T_key, resource_entry_t> ResourceMap;          typedef std::map<T_key, resource_entry_t> ResourceMap;
120          ResourceMap ResourceEntries;          ResourceMap ResourceEntries;
121    
122      public:      public:
123                  virtual ~ResourceManager() {}          /**
124             * Returns (the keys of) all current entries of this
125             * ResourceManager instance.
126             */
127            std::vector<T_key> Entries() {
128                std::vector<T_key> result;
129                for (typename ResourceMap::iterator iter = ResourceEntries.begin();
130                     iter != ResourceEntries.end(); iter++)
131                {
132                    result.push_back(iter->first);
133                }
134                return result;
135            }
136    
137          /**          /**
138           * Borrow a resource identified by \a Key. The ResourceManager will           * Borrow a resource identified by \a Key. The ResourceManager will
139           * mark the resource as in usage by the consumer given with           * mark the resource as in usage by the consumer given with
# Line 109  class ResourceManager { Line 145  class ResourceManager {
145           * @returns  pointer to resource           * @returns  pointer to resource
146           */           */
147          T_res* Borrow(T_key Key, ResourceConsumer<T_res>* pConsumer) {          T_res* Borrow(T_key Key, ResourceConsumer<T_res>* pConsumer) {
148                // search for an entry for this resource
149              typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);              typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
150              if (iterEntry == ResourceEntries.end()) {              if (iterEntry == ResourceEntries.end()) { // entry doesn't exist yet
151                  // already create an entry for the resource                  // already create an entry for the resource
152                  resource_entry_t entry;                  resource_entry_t entry;
153                  entry.key      = Key;                  entry.key      = Key;
154                  entry.resource = NULL;                  entry.resource = NULL;
155                    entry.mode     = ON_DEMAND; // default mode
156                    entry.lifearg  = NULL;
157                    entry.entryarg = NULL;
158                  entry.consumers.insert(pConsumer);                  entry.consumers.insert(pConsumer);
159                  ResourceEntries[Key] = entry;                  ResourceEntries[Key] = entry;
160                  try {                  try {
161                      // actually create the resource                      // actually create the resource
162                      entry.resource = Create(Key, pConsumer, entry.arg);                      entry.resource = Create(Key, pConsumer, entry.lifearg);
163                  } catch (...) {                  } catch (...) {
164                      // creating the resource failed, so remove the entry                      // creating the resource failed, so remove the entry
165                      ResourceEntries.erase(Key);                      ResourceEntries.erase(Key);
# Line 128  class ResourceManager { Line 168  class ResourceManager {
168                  }                  }
169                  // now update the entry with the created resource                  // now update the entry with the created resource
170                  ResourceEntries[Key] = entry;                  ResourceEntries[Key] = entry;
171                  OnBorrow(entry.resource, pConsumer, entry.arg);                  OnBorrow(entry.resource, pConsumer, entry.lifearg);
172                    return entry.resource;
173                } else { // entry already exists
174                    resource_entry_t& entry = iterEntry->second;
175                    if (!entry.resource) { // create resource if not created already
176                        try {
177                            entry.resource = Create(Key, pConsumer, entry.lifearg);
178                        } catch (...) {
179                            entry.resource = NULL;
180                            throw; // rethrow the same exception
181                        }
182                    }
183                    entry.consumers.insert(pConsumer);
184                    OnBorrow(entry.resource, pConsumer, entry.lifearg);
185                  return entry.resource;                  return entry.resource;
186              }              }
             resource_entry_t& entry = iterEntry->second;  
             entry.consumers.insert(pConsumer);  
             OnBorrow(entry.resource, pConsumer, entry.arg);  
             return entry.resource;  
187          }          }
188    
189          /**          /**
190           * Give back a resource. This tells the ResourceManager that the           * Give back a resource. This tells the ResourceManager that the
191           * consumer given by \a pConsumer doesn't need the resource anymore.           * consumer given by \a pConsumer doesn't need the resource anymore.
192           * If the resource is not needed by any consumer anymore then the           * If the resource is not needed by any consumer anymore and the
193           * resource will be destroyed.           * resource has a life-time strategy of ON_DEMAND (which is the
194             * default setting) then the resource will be destroyed.
195           *           *
196           * @param pResource - pointer to resource           * @param pResource - pointer to resource
197           * @param pConsumer - identifier of the consumer who borrowed the           * @param pConsumer - identifier of the consumer who borrowed the
198           *                    resource           *                    resource
199           */           */
200          void HandBack(T_res* pResource, ResourceConsumer<T_res>* pConsumer) {          void HandBack(T_res* pResource, ResourceConsumer<T_res>* pConsumer) {
201                // search for the entry associated with the given resource
202              typename ResourceMap::iterator iter = ResourceEntries.begin();              typename ResourceMap::iterator iter = ResourceEntries.begin();
203              typename ResourceMap::iterator end  = ResourceEntries.end();              typename ResourceMap::iterator end  = ResourceEntries.end();
204              for (; iter != end; iter++) {              for (; iter != end; iter++) {
205                  if (iter->second.resource == pResource) {                  if (iter->second.resource == pResource) { // found entry for resource
206                      resource_entry_t& entry = iter->second;                      resource_entry_t& entry = iter->second;
207                      entry.consumers.erase(pConsumer);                      entry.consumers.erase(pConsumer);
208                      if (entry.consumers.empty()) {                      // remove entry if necessary
209                        if (entry.mode == ON_DEMAND && !entry.entryarg && entry.consumers.empty()) {
210                          T_res* resource = entry.resource;                          T_res* resource = entry.resource;
211                          void* arg = entry.arg;                          void* arg       = entry.lifearg;
212                          ResourceEntries.erase(iter);                          ResourceEntries.erase(iter);
213                          Destroy(resource, arg);                          // destroy resource if necessary
214                            if (resource) Destroy(resource, arg);
215                      }                      }
216                      return;                      return;
217                  }                  }
# Line 166  class ResourceManager { Line 219  class ResourceManager {
219          }          }
220    
221          /**          /**
222           * Request update of a resource.           * Request update of a resource. All consumers will be informed
223             * about the pending update of the resource so they can safely react
224             * by stopping its usage first, then the resource will be recreated
225             * and finally the consumers will be informed once the update was
226             * completed, so they can continue to use the resource.
227           *           *
228           * @param pResource - resource to be updated           * @param pResource - resource to be updated
229           * @param pConsumer - consumer who requested the update           * @param pConsumer - consumer who requested the update
# Line 189  class ResourceManager { Line 246  class ResourceManager {
246                      }                      }
247                      // update resource                      // update resource
248                      T_res* pOldResource = entry.resource;                      T_res* pOldResource = entry.resource;
249                      Destroy(entry.resource, entry.arg);                      Destroy(entry.resource, entry.lifearg);
250                      entry.resource = Create(entry.key, pConsumer, entry.arg);                      entry.resource = Create(entry.key, pConsumer, entry.lifearg);
251                      // inform all consumers about update completed                      // inform all consumers about update completed
252                      iterCons = entry.consumers.begin();                      iterCons = entry.consumers.begin();
253                      endCons  = entry.consumers.end();                      endCons  = entry.consumers.end();
# Line 205  class ResourceManager { Line 262  class ResourceManager {
262              }              }
263          }          }
264    
265            /**
266             * Returns the life-time strategy of the given resource.
267             *
268             * @param Key - ID of the resource
269             */
270            mode_t AvailabilityMode(T_key Key) {
271                typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
272                if (iterEntry == ResourceEntries.end())
273                    return ON_DEMAND; // resource entry doesn't exist, so we return the default mode
274                resource_entry_t& entry = iterEntry->second;
275                return entry.mode;
276            }
277    
278            /**
279             * Change life-time strategy of the given resource. If a life-time
280             * strategy of PERSISTENT was given and the resource was not created
281             * yet, it will immediately be created and this method will block
282             * until the resource creation was completed.
283             *
284             * @param Key - ID of the resource
285             * @param Mode - life-time strategy of resource to be set
286             * @throws Exception in case an invalid Mode was given
287             */
288            void SetAvailabilityMode(T_key Key, mode_t Mode) throw (Exception) {
289                if (Mode != ON_DEMAND && Mode != ON_DEMAND_HOLD && Mode != PERSISTENT)
290                    throw Exception("ResourceManager::SetAvailabilityMode(): invalid mode");
291    
292                // search for an entry for this resource
293                typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
294                resource_entry_t* pEntry = NULL;
295                if (iterEntry == ResourceEntries.end()) { // resource entry doesn't exist
296                    if (Mode == ON_DEMAND) return; // we don't create an entry for the default value
297                    // create an entry for the resource
298                    pEntry = &ResourceEntries[Key];
299                    pEntry->key      = Key;
300                    pEntry->resource = NULL;
301                    pEntry->mode     = Mode;
302                    pEntry->lifearg  = NULL;
303                    pEntry->entryarg = NULL;
304                } else { // resource entry exists
305                    pEntry = &iterEntry->second;
306                    // remove entry if necessary
307                    if (Mode == ON_DEMAND && !pEntry->entryarg && pEntry->consumers.empty()) {
308                        T_res* resource = pEntry->resource;
309                        void* arg       = pEntry->lifearg;
310                        ResourceEntries.erase(iterEntry);
311                        // destroy resource if necessary
312                        if (resource) Destroy(resource, arg);
313                        return; // done
314                    }
315                    pEntry->mode = Mode; // apply new mode
316                }
317    
318                // already create the resource if necessary
319                if (pEntry->mode == PERSISTENT && !pEntry->resource) {
320                    try {
321                        // actually create the resource
322                        pEntry->resource = Create(Key, NULL /*no consumer yet*/, pEntry->lifearg);
323                    } catch (...) {
324                        // creating the resource failed, so skip it for now
325                        pEntry->resource = NULL;
326                        // rethrow the same exception
327                        throw;
328                    }
329                }
330            }
331    
332            /**
333             * Returns custom data sticked to the given resource previously by
334             * a SetCustomData() call.
335             *
336             * @param Key - ID of resource
337             */
338            void* CustomData(T_key Key) {
339                typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
340                if (iterEntry == ResourceEntries.end()) return NULL; // resource entry doesn't exist, so we return the default mode
341                resource_entry_t& entry = iterEntry->second;
342                return entry.entryarg;
343            }
344    
345            /**
346             * This method can be used to stick custom data to an resource
347             * entry. In case the custom data is not needed anymore, you should
348             * call this method again and set \a pData to NULL, so the
349             * ResourceManager might safe space by removing the respective
350             * entry if not needed anymore.
351             *
352             * @param Key - ID of resource
353             * @param pData - pointer to custom data, or NULL if not needed anymore
354             */
355            void SetCustomData(T_key Key, void* pData) {
356                typename ResourceMap::iterator iterEntry = ResourceEntries.find(Key);
357                if (pData) {
358                    if (iterEntry == ResourceEntries.end()) { // entry doesnt exist, so create one
359                        resource_entry_t* pEntry = &ResourceEntries[Key];
360                        pEntry->key      = Key;
361                        pEntry->resource = NULL;
362                        pEntry->mode     = ON_DEMAND;
363                        pEntry->lifearg  = NULL;
364                        pEntry->entryarg = pData; // set custom data
365                    } else { // entry exists, so just update its custom data
366                        iterEntry->second.entryarg = pData;
367                    }
368                } else { // !pData
369                    if (iterEntry == ResourceEntries.end()) return; // entry doesnt exist, so nothing to do
370                    // entry exists, remove it if necessary
371                    resource_entry_t* pEntry = &iterEntry->second;
372                    if (pEntry->mode == ON_DEMAND && pEntry->consumers.empty()) {
373                        ResourceEntries.erase(iterEntry);
374                    } else iterEntry->second.entryarg = NULL;
375                }
376            }
377    
378            virtual ~ResourceManager() {} // due to C++'s nature we cannot destroy created resources here
379    
380      protected:      protected:
381          /**          /**
382           * Has to be implemented by the descendant to create (allocate) a           * Has to be implemented by the descendant to create (allocate) a
# Line 272  class ResourceManager { Line 444  class ResourceManager {
444          }          }
445  };  };
446    
447    } // namespace LinuxSampler
448    
449  #endif // __RESOURCE_MANAGER__  #endif // __RESOURCE_MANAGER__

Legend:
Removed from v.946  
changed lines
  Added in v.947

  ViewVC Help
Powered by ViewVC