svcore  1.9
Scavenger.h
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 /*
00017    This is a modified version of a source file from the 
00018    Rosegarden MIDI and audio sequencer and notation editor.
00019    This file copyright 2000-2006 Chris Cannam.
00020 */
00021 
00022 #ifndef _SCAVENGER_H_
00023 #define _SCAVENGER_H_
00024 
00025 #include "system/System.h"
00026 
00027 #include <vector>
00028 #include <list>
00029 #include <sys/time.h>
00030 #include <QMutex>
00031 #include <iostream>
00032 
00044 template <typename T>
00045 class Scavenger
00046 {
00047 public:
00048     Scavenger(int sec = 2, int defaultObjectListSize = 200);
00049     ~Scavenger();
00050 
00055     void claim(T *t);
00056 
00061     void scavenge(bool clearNow = false);
00062 
00063 protected:
00064     typedef std::pair<T *, int> ObjectTimePair;
00065     typedef std::vector<ObjectTimePair> ObjectTimeList;
00066     ObjectTimeList m_objects;
00067     int m_sec;
00068 
00069     typedef std::list<T *> ObjectList;
00070     ObjectList m_excess;
00071     int m_lastExcess;
00072     QMutex m_excessMutex;
00073     void pushExcess(T *);
00074     void clearExcess(int);
00075 
00076     unsigned int m_claimed;
00077     unsigned int m_scavenged;
00078 };
00079 
00084 template <typename T>
00085 class ScavengerArrayWrapper
00086 {
00087 public:
00088     ScavengerArrayWrapper(T *array) : m_array(array) { }
00089     ~ScavengerArrayWrapper() { delete[] m_array; }
00090 
00091 private:
00092     T *m_array;
00093 };
00094 
00095 
00096 template <typename T>
00097 Scavenger<T>::Scavenger(int sec, int defaultObjectListSize) :
00098     m_objects(ObjectTimeList(defaultObjectListSize)),
00099     m_sec(sec),
00100     m_lastExcess(0),
00101     m_claimed(0),
00102     m_scavenged(0)
00103 {
00104 }
00105 
00106 template <typename T>
00107 Scavenger<T>::~Scavenger()
00108 {
00109     if (m_scavenged < m_claimed) {
00110         for (size_t i = 0; i < m_objects.size(); ++i) {
00111             ObjectTimePair &pair = m_objects[i];
00112             if (pair.first != 0) {
00113                 T *ot = pair.first;
00114                 pair.first = 0;
00115                 delete ot;
00116                 ++m_scavenged;
00117             }
00118         }
00119     }
00120 
00121     clearExcess(0);
00122 }
00123 
00124 template <typename T>
00125 void
00126 Scavenger<T>::claim(T *t)
00127 {
00128 //    std::cerr << "Scavenger::claim(" << t << ")" << std::endl;
00129 
00130     struct timeval tv;
00131     (void)gettimeofday(&tv, 0);
00132     int sec = tv.tv_sec;
00133 
00134     for (size_t i = 0; i < m_objects.size(); ++i) {
00135         ObjectTimePair &pair = m_objects[i];
00136         if (pair.first == 0) {
00137             pair.second = sec;
00138             pair.first = t;
00139             ++m_claimed;
00140             return;
00141         }
00142     }
00143 
00144     std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
00145               << "using non-RT-safe method" << std::endl;
00146     pushExcess(t);
00147 }
00148 
00149 template <typename T>
00150 void
00151 Scavenger<T>::scavenge(bool clearNow)
00152 {
00153 //    std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl;
00154 
00155     if (m_scavenged >= m_claimed) return;
00156     
00157     struct timeval tv;
00158     (void)gettimeofday(&tv, 0);
00159     int sec = tv.tv_sec;
00160 
00161     for (size_t i = 0; i < m_objects.size(); ++i) {
00162         ObjectTimePair &pair = m_objects[i];
00163         if (clearNow ||
00164             (pair.first != 0 && pair.second + m_sec < sec)) {
00165             T *ot = pair.first;
00166             pair.first = 0;
00167             delete ot;
00168             ++m_scavenged;
00169         }
00170     }
00171 
00172     if (sec > m_lastExcess + m_sec) {
00173         clearExcess(sec);
00174     }
00175 }
00176 
00177 template <typename T>
00178 void
00179 Scavenger<T>::pushExcess(T *t)
00180 {
00181     m_excessMutex.lock();
00182     m_excess.push_back(t);
00183     struct timeval tv;
00184     (void)gettimeofday(&tv, 0);
00185     m_lastExcess = tv.tv_sec;
00186     m_excessMutex.unlock();
00187 }
00188 
00189 template <typename T>
00190 void
00191 Scavenger<T>::clearExcess(int sec)
00192 {
00193     m_excessMutex.lock();
00194     for (typename ObjectList::iterator i = m_excess.begin();
00195          i != m_excess.end(); ++i) {
00196         delete *i;
00197     }
00198     m_excess.clear();
00199     m_lastExcess = sec;
00200     m_excessMutex.unlock();
00201 }
00202 
00203 #endif