annotate base/Scavenger.h @ 1248:58dd6a6fe414 piper

Update to use listargs variant of Piper stuff (so that the plugin winnowing feature from the penultimate commit actually works)
author Chris Cannam
date Thu, 03 Nov 2016 15:38:17 +0000
parents 6b847a59d908
children 48e9f538e6e9
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@178 29 #include <QMutex>
Chris@158 30 #include <iostream>
Chris@0 31
Chris@0 32 /**
Chris@0 33 * A very simple class that facilitates running things like plugins
Chris@0 34 * without locking, by collecting unwanted objects and deleting them
Chris@0 35 * after a delay so as to be sure nobody's in the middle of using
Chris@0 36 * them. Requires scavenge() to be called regularly from a non-RT
Chris@0 37 * thread.
Chris@0 38 *
Chris@0 39 * This is currently not at all suitable for large numbers of objects
Chris@0 40 * -- it's just a quick hack for use with things like plugins.
Chris@0 41 */
Chris@0 42
Chris@0 43 template <typename T>
Chris@0 44 class Scavenger
Chris@0 45 {
Chris@0 46 public:
Chris@0 47 Scavenger(int sec = 2, int defaultObjectListSize = 200);
Chris@158 48 ~Scavenger();
Chris@0 49
Chris@0 50 /**
Chris@0 51 * Call from an RT thread etc., to pass ownership of t to us.
Chris@0 52 * Only one thread should be calling this on any given scavenger.
Chris@0 53 */
Chris@0 54 void claim(T *t);
Chris@0 55
Chris@0 56 /**
Chris@0 57 * Call from a non-RT thread.
Chris@0 58 * Only one thread should be calling this on any given scavenger.
Chris@0 59 */
Chris@14 60 void scavenge(bool clearNow = false);
Chris@0 61
Chris@0 62 protected:
Chris@1039 63 typedef std::pair<T *, time_t> ObjectTimePair;
Chris@0 64 typedef std::vector<ObjectTimePair> ObjectTimeList;
Chris@0 65 ObjectTimeList m_objects;
Chris@1039 66 time_t m_sec;
Chris@0 67
Chris@158 68 typedef std::list<T *> ObjectList;
Chris@158 69 ObjectList m_excess;
Chris@1039 70 time_t m_lastExcess;
Chris@178 71 QMutex m_excessMutex;
Chris@158 72 void pushExcess(T *);
Chris@1039 73 void clearExcess(time_t);
Chris@158 74
Chris@0 75 unsigned int m_claimed;
Chris@0 76 unsigned int m_scavenged;
Chris@0 77 };
Chris@0 78
Chris@0 79 /**
Chris@0 80 * A wrapper to permit arrays to be scavenged.
Chris@0 81 */
Chris@0 82
Chris@0 83 template <typename T>
Chris@0 84 class ScavengerArrayWrapper
Chris@0 85 {
Chris@0 86 public:
Chris@0 87 ScavengerArrayWrapper(T *array) : m_array(array) { }
Chris@0 88 ~ScavengerArrayWrapper() { delete[] m_array; }
Chris@0 89
Chris@0 90 private:
Chris@0 91 T *m_array;
Chris@0 92 };
Chris@0 93
Chris@0 94
Chris@0 95 template <typename T>
Chris@0 96 Scavenger<T>::Scavenger(int sec, int defaultObjectListSize) :
Chris@0 97 m_objects(ObjectTimeList(defaultObjectListSize)),
Chris@0 98 m_sec(sec),
Chris@252 99 m_lastExcess(0),
Chris@0 100 m_claimed(0),
Chris@0 101 m_scavenged(0)
Chris@0 102 {
Chris@158 103 }
Chris@158 104
Chris@158 105 template <typename T>
Chris@158 106 Scavenger<T>::~Scavenger()
Chris@158 107 {
Chris@158 108 if (m_scavenged < m_claimed) {
Chris@158 109 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@158 110 ObjectTimePair &pair = m_objects[i];
Chris@158 111 if (pair.first != 0) {
Chris@158 112 T *ot = pair.first;
Chris@158 113 pair.first = 0;
Chris@158 114 delete ot;
Chris@158 115 ++m_scavenged;
Chris@158 116 }
Chris@158 117 }
Chris@158 118 }
Chris@158 119
Chris@158 120 clearExcess(0);
Chris@0 121 }
Chris@0 122
Chris@0 123 template <typename T>
Chris@0 124 void
Chris@0 125 Scavenger<T>::claim(T *t)
Chris@0 126 {
Chris@0 127 // std::cerr << "Scavenger::claim(" << t << ")" << std::endl;
Chris@0 128
Chris@0 129 struct timeval tv;
Chris@0 130 (void)gettimeofday(&tv, 0);
Chris@1039 131 time_t sec = tv.tv_sec;
Chris@0 132
Chris@0 133 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@0 134 ObjectTimePair &pair = m_objects[i];
Chris@0 135 if (pair.first == 0) {
Chris@0 136 pair.second = sec;
Chris@0 137 pair.first = t;
Chris@0 138 ++m_claimed;
Chris@0 139 return;
Chris@0 140 }
Chris@0 141 }
Chris@0 142
Chris@158 143 std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
Chris@158 144 << "using non-RT-safe method" << std::endl;
Chris@158 145 pushExcess(t);
Chris@0 146 }
Chris@0 147
Chris@0 148 template <typename T>
Chris@0 149 void
Chris@14 150 Scavenger<T>::scavenge(bool clearNow)
Chris@0 151 {
Chris@0 152 // std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl;
Chris@0 153
Chris@0 154 if (m_scavenged >= m_claimed) return;
Chris@0 155
Chris@0 156 struct timeval tv;
Chris@0 157 (void)gettimeofday(&tv, 0);
Chris@1039 158 time_t sec = tv.tv_sec;
Chris@0 159
Chris@0 160 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@0 161 ObjectTimePair &pair = m_objects[i];
Chris@14 162 if (clearNow ||
Chris@14 163 (pair.first != 0 && pair.second + m_sec < sec)) {
Chris@0 164 T *ot = pair.first;
Chris@0 165 pair.first = 0;
Chris@0 166 delete ot;
Chris@0 167 ++m_scavenged;
Chris@0 168 }
Chris@0 169 }
Chris@158 170
Chris@158 171 if (sec > m_lastExcess + m_sec) {
Chris@158 172 clearExcess(sec);
Chris@158 173 }
Chris@158 174 }
Chris@158 175
Chris@158 176 template <typename T>
Chris@158 177 void
Chris@158 178 Scavenger<T>::pushExcess(T *t)
Chris@158 179 {
Chris@178 180 m_excessMutex.lock();
Chris@158 181 m_excess.push_back(t);
Chris@158 182 struct timeval tv;
Chris@158 183 (void)gettimeofday(&tv, 0);
Chris@158 184 m_lastExcess = tv.tv_sec;
Chris@178 185 m_excessMutex.unlock();
Chris@158 186 }
Chris@158 187
Chris@158 188 template <typename T>
Chris@158 189 void
Chris@1039 190 Scavenger<T>::clearExcess(time_t sec)
Chris@158 191 {
Chris@178 192 m_excessMutex.lock();
Chris@158 193 for (typename ObjectList::iterator i = m_excess.begin();
Chris@158 194 i != m_excess.end(); ++i) {
Chris@158 195 delete *i;
Chris@158 196 }
Chris@158 197 m_excess.clear();
Chris@158 198 m_lastExcess = sec;
Chris@178 199 m_excessMutex.unlock();
Chris@0 200 }
Chris@0 201
Chris@0 202 #endif