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