annotate base/Scavenger.h @ 319:3ff8f571da09

* Hoist alignment model set/query up to Model, so any models can be aligned * Add Model::aboutToDelete and aboutToBeDeleted for management of models that are contained by or referred to by other models instead of only the document
author Chris Cannam
date Wed, 24 Oct 2007 15:21:38 +0000
parents 218605f94073
children b14064bd1f97
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 /*
Chris@0 17 This is a modified version of a source file from the
Chris@0 18 Rosegarden MIDI and audio sequencer and notation editor.
Chris@17 19 This file copyright 2000-2006 Chris Cannam.
Chris@0 20 */
Chris@0 21
Chris@0 22 #ifndef _SCAVENGER_H_
Chris@0 23 #define _SCAVENGER_H_
Chris@0 24
Chris@150 25 #include "system/System.h"
Chris@0 26
Chris@0 27 #include <vector>
Chris@158 28 #include <list>
Chris@0 29 #include <sys/time.h>
Chris@178 30 #include <QMutex>
Chris@158 31 #include <iostream>
Chris@0 32
Chris@0 33 /**
Chris@0 34 * A very simple class that facilitates running things like plugins
Chris@0 35 * without locking, by collecting unwanted objects and deleting them
Chris@0 36 * after a delay so as to be sure nobody's in the middle of using
Chris@0 37 * them. Requires scavenge() to be called regularly from a non-RT
Chris@0 38 * thread.
Chris@0 39 *
Chris@0 40 * This is currently not at all suitable for large numbers of objects
Chris@0 41 * -- it's just a quick hack for use with things like plugins.
Chris@0 42 */
Chris@0 43
Chris@0 44 template <typename T>
Chris@0 45 class Scavenger
Chris@0 46 {
Chris@0 47 public:
Chris@0 48 Scavenger(int sec = 2, int defaultObjectListSize = 200);
Chris@158 49 ~Scavenger();
Chris@0 50
Chris@0 51 /**
Chris@0 52 * Call from an RT thread etc., to pass ownership of t to us.
Chris@0 53 * Only one thread should be calling this on any given scavenger.
Chris@0 54 */
Chris@0 55 void claim(T *t);
Chris@0 56
Chris@0 57 /**
Chris@0 58 * Call from a non-RT thread.
Chris@0 59 * Only one thread should be calling this on any given scavenger.
Chris@0 60 */
Chris@14 61 void scavenge(bool clearNow = false);
Chris@0 62
Chris@0 63 protected:
Chris@0 64 typedef std::pair<T *, int> ObjectTimePair;
Chris@0 65 typedef std::vector<ObjectTimePair> ObjectTimeList;
Chris@0 66 ObjectTimeList m_objects;
Chris@0 67 int m_sec;
Chris@0 68
Chris@158 69 typedef std::list<T *> ObjectList;
Chris@158 70 ObjectList m_excess;
Chris@158 71 int m_lastExcess;
Chris@178 72 QMutex m_excessMutex;
Chris@158 73 void pushExcess(T *);
Chris@158 74 void clearExcess(int);
Chris@158 75
Chris@0 76 unsigned int m_claimed;
Chris@0 77 unsigned int m_scavenged;
Chris@0 78 };
Chris@0 79
Chris@0 80 /**
Chris@0 81 * A wrapper to permit arrays to be scavenged.
Chris@0 82 */
Chris@0 83
Chris@0 84 template <typename T>
Chris@0 85 class ScavengerArrayWrapper
Chris@0 86 {
Chris@0 87 public:
Chris@0 88 ScavengerArrayWrapper(T *array) : m_array(array) { }
Chris@0 89 ~ScavengerArrayWrapper() { delete[] m_array; }
Chris@0 90
Chris@0 91 private:
Chris@0 92 T *m_array;
Chris@0 93 };
Chris@0 94
Chris@0 95
Chris@0 96 template <typename T>
Chris@0 97 Scavenger<T>::Scavenger(int sec, int defaultObjectListSize) :
Chris@0 98 m_objects(ObjectTimeList(defaultObjectListSize)),
Chris@0 99 m_sec(sec),
Chris@252 100 m_lastExcess(0),
Chris@0 101 m_claimed(0),
Chris@0 102 m_scavenged(0)
Chris@0 103 {
Chris@158 104 }
Chris@158 105
Chris@158 106 template <typename T>
Chris@158 107 Scavenger<T>::~Scavenger()
Chris@158 108 {
Chris@158 109 if (m_scavenged < m_claimed) {
Chris@158 110 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@158 111 ObjectTimePair &pair = m_objects[i];
Chris@158 112 if (pair.first != 0) {
Chris@158 113 T *ot = pair.first;
Chris@158 114 pair.first = 0;
Chris@158 115 delete ot;
Chris@158 116 ++m_scavenged;
Chris@158 117 }
Chris@158 118 }
Chris@158 119 }
Chris@158 120
Chris@158 121 clearExcess(0);
Chris@0 122 }
Chris@0 123
Chris@0 124 template <typename T>
Chris@0 125 void
Chris@0 126 Scavenger<T>::claim(T *t)
Chris@0 127 {
Chris@0 128 // std::cerr << "Scavenger::claim(" << t << ")" << std::endl;
Chris@0 129
Chris@0 130 struct timeval tv;
Chris@0 131 (void)gettimeofday(&tv, 0);
Chris@0 132 int sec = tv.tv_sec;
Chris@0 133
Chris@0 134 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@0 135 ObjectTimePair &pair = m_objects[i];
Chris@0 136 if (pair.first == 0) {
Chris@0 137 pair.second = sec;
Chris@0 138 pair.first = t;
Chris@0 139 ++m_claimed;
Chris@0 140 return;
Chris@0 141 }
Chris@0 142 }
Chris@0 143
Chris@158 144 std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
Chris@158 145 << "using non-RT-safe method" << std::endl;
Chris@158 146 pushExcess(t);
Chris@0 147 }
Chris@0 148
Chris@0 149 template <typename T>
Chris@0 150 void
Chris@14 151 Scavenger<T>::scavenge(bool clearNow)
Chris@0 152 {
Chris@0 153 // std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl;
Chris@0 154
Chris@0 155 if (m_scavenged >= m_claimed) return;
Chris@0 156
Chris@0 157 struct timeval tv;
Chris@0 158 (void)gettimeofday(&tv, 0);
Chris@0 159 int sec = tv.tv_sec;
Chris@0 160
Chris@0 161 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@0 162 ObjectTimePair &pair = m_objects[i];
Chris@14 163 if (clearNow ||
Chris@14 164 (pair.first != 0 && pair.second + m_sec < sec)) {
Chris@0 165 T *ot = pair.first;
Chris@0 166 pair.first = 0;
Chris@0 167 delete ot;
Chris@0 168 ++m_scavenged;
Chris@0 169 }
Chris@0 170 }
Chris@158 171
Chris@158 172 if (sec > m_lastExcess + m_sec) {
Chris@158 173 clearExcess(sec);
Chris@158 174 }
Chris@158 175 }
Chris@158 176
Chris@158 177 template <typename T>
Chris@158 178 void
Chris@158 179 Scavenger<T>::pushExcess(T *t)
Chris@158 180 {
Chris@178 181 m_excessMutex.lock();
Chris@158 182 m_excess.push_back(t);
Chris@158 183 struct timeval tv;
Chris@158 184 (void)gettimeofday(&tv, 0);
Chris@158 185 m_lastExcess = tv.tv_sec;
Chris@178 186 m_excessMutex.unlock();
Chris@158 187 }
Chris@158 188
Chris@158 189 template <typename T>
Chris@158 190 void
Chris@158 191 Scavenger<T>::clearExcess(int sec)
Chris@158 192 {
Chris@178 193 m_excessMutex.lock();
Chris@158 194 for (typename ObjectList::iterator i = m_excess.begin();
Chris@158 195 i != m_excess.end(); ++i) {
Chris@158 196 delete *i;
Chris@158 197 }
Chris@158 198 m_excess.clear();
Chris@158 199 m_lastExcess = sec;
Chris@178 200 m_excessMutex.unlock();
Chris@0 201 }
Chris@0 202
Chris@0 203 #endif