lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: This is a modified version of a source file from the lbajardsilogic@0: Rosegarden MIDI and audio sequencer and notation editor. lbajardsilogic@0: This file copyright 2000-2006 Chris Cannam. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #ifndef _SCAVENGER_H_ lbajardsilogic@0: #define _SCAVENGER_H_ lbajardsilogic@0: lbajardsilogic@0: #include "system/System.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: //#include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * A very simple class that facilitates running things like plugins lbajardsilogic@0: * without locking, by collecting unwanted objects and deleting them lbajardsilogic@0: * after a delay so as to be sure nobody's in the middle of using lbajardsilogic@0: * them. Requires scavenge() to be called regularly from a non-RT lbajardsilogic@0: * thread. lbajardsilogic@0: * lbajardsilogic@0: * This is currently not at all suitable for large numbers of objects lbajardsilogic@0: * -- it's just a quick hack for use with things like plugins. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: class Scavenger lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: Scavenger(int sec = 2, int defaultObjectListSize = 200); lbajardsilogic@0: ~Scavenger(); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Call from an RT thread etc., to pass ownership of t to us. lbajardsilogic@0: * Only one thread should be calling this on any given scavenger. lbajardsilogic@0: */ lbajardsilogic@0: void claim(T *t); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Call from a non-RT thread. lbajardsilogic@0: * Only one thread should be calling this on any given scavenger. lbajardsilogic@0: */ lbajardsilogic@0: void scavenge(bool clearNow = false); lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: typedef std::pair ObjectTimePair; lbajardsilogic@0: typedef std::vector ObjectTimeList; lbajardsilogic@0: ObjectTimeList m_objects; lbajardsilogic@0: int m_sec; lbajardsilogic@0: lbajardsilogic@0: typedef std::list ObjectList; lbajardsilogic@0: ObjectList m_excess; lbajardsilogic@0: int m_lastExcess; lbajardsilogic@0: QMutex m_excessMutex; lbajardsilogic@0: void pushExcess(T *); lbajardsilogic@0: void clearExcess(int); lbajardsilogic@0: lbajardsilogic@0: unsigned int m_claimed; lbajardsilogic@0: unsigned int m_scavenged; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * A wrapper to permit arrays to be scavenged. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: class ScavengerArrayWrapper lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: ScavengerArrayWrapper(T *array) : m_array(array) { } lbajardsilogic@0: ~ScavengerArrayWrapper() { delete[] m_array; } lbajardsilogic@0: lbajardsilogic@0: private: lbajardsilogic@0: T *m_array; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: Scavenger::Scavenger(int sec, int defaultObjectListSize) : lbajardsilogic@0: m_objects(ObjectTimeList(defaultObjectListSize)), lbajardsilogic@0: m_sec(sec), lbajardsilogic@0: m_lastExcess(0), lbajardsilogic@0: m_claimed(0), lbajardsilogic@0: m_scavenged(0) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: Scavenger::~Scavenger() lbajardsilogic@0: { lbajardsilogic@0: if (m_scavenged < m_claimed) { lbajardsilogic@0: for (size_t i = 0; i < m_objects.size(); ++i) { lbajardsilogic@0: ObjectTimePair &pair = m_objects[i]; lbajardsilogic@0: if (pair.first != 0) { lbajardsilogic@0: T *ot = pair.first; lbajardsilogic@0: pair.first = 0; lbajardsilogic@0: delete ot; lbajardsilogic@0: ++m_scavenged; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: clearExcess(0); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: Scavenger::claim(T *t) lbajardsilogic@0: { lbajardsilogic@0: // std::cerr << "Scavenger::claim(" << t << ")" << std::endl; lbajardsilogic@0: lbajardsilogic@0: struct timeval tv; lbajardsilogic@0: (void)gettimeofday(&tv, 0); lbajardsilogic@0: int sec = tv.tv_sec; lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_objects.size(); ++i) { lbajardsilogic@0: ObjectTimePair &pair = m_objects[i]; lbajardsilogic@0: if (pair.first == 0) { lbajardsilogic@0: pair.second = sec; lbajardsilogic@0: pair.first = t; lbajardsilogic@0: ++m_claimed; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, " lbajardsilogic@0: << "using non-RT-safe method" << std::endl; lbajardsilogic@0: pushExcess(t); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: Scavenger::scavenge(bool clearNow) lbajardsilogic@0: { lbajardsilogic@0: // std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl; lbajardsilogic@0: lbajardsilogic@0: if (m_scavenged >= m_claimed) return; lbajardsilogic@0: lbajardsilogic@0: struct timeval tv; lbajardsilogic@0: (void)gettimeofday(&tv, 0); lbajardsilogic@0: int sec = tv.tv_sec; lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_objects.size(); ++i) { lbajardsilogic@0: ObjectTimePair &pair = m_objects[i]; lbajardsilogic@0: if (clearNow || lbajardsilogic@0: (pair.first != 0 && pair.second + m_sec < sec)) { lbajardsilogic@0: T *ot = pair.first; lbajardsilogic@0: pair.first = 0; lbajardsilogic@0: delete ot; lbajardsilogic@0: ++m_scavenged; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (sec > m_lastExcess + m_sec) { lbajardsilogic@0: clearExcess(sec); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: Scavenger::pushExcess(T *t) lbajardsilogic@0: { lbajardsilogic@0: m_excessMutex.lock(); lbajardsilogic@0: m_excess.push_back(t); lbajardsilogic@0: struct timeval tv; lbajardsilogic@0: (void)gettimeofday(&tv, 0); lbajardsilogic@0: m_lastExcess = tv.tv_sec; lbajardsilogic@0: m_excessMutex.unlock(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: Scavenger::clearExcess(int sec) lbajardsilogic@0: { lbajardsilogic@0: m_excessMutex.lock(); lbajardsilogic@0: for (typename ObjectList::iterator i = m_excess.begin(); lbajardsilogic@0: i != m_excess.end(); ++i) { lbajardsilogic@0: delete *i; lbajardsilogic@0: } lbajardsilogic@0: m_excess.clear(); lbajardsilogic@0: m_lastExcess = sec; lbajardsilogic@0: m_excessMutex.unlock(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #endif