annotate base/Scavenger.h @ 1563:175ef02c7864

Merge
author Chris Cannam
date Fri, 02 Nov 2018 14:41:00 +0000
parents 48e9f538e6e9
children ad5f892c0c4d
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@1429 109 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@1429 110 ObjectTimePair &pair = m_objects[i];
Chris@1429 111 if (pair.first != 0) {
Chris@1429 112 T *ot = pair.first;
Chris@1429 113 pair.first = 0;
Chris@1429 114 delete ot;
Chris@1429 115 ++m_scavenged;
Chris@1429 116 }
Chris@1429 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@1429 134 ObjectTimePair &pair = m_objects[i];
Chris@1429 135 if (pair.first == 0) {
Chris@1429 136 pair.second = sec;
Chris@1429 137 pair.first = t;
Chris@1429 138 ++m_claimed;
Chris@1429 139 return;
Chris@1429 140 }
Chris@0 141 }
Chris@0 142
Chris@158 143 std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
Chris@1429 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@1429 161 ObjectTimePair &pair = m_objects[i];
Chris@1429 162 if (clearNow ||
Chris@1429 163 (pair.first != 0 && pair.second + m_sec < sec)) {
Chris@1429 164 T *ot = pair.first;
Chris@1429 165 pair.first = 0;
Chris@1429 166 delete ot;
Chris@1429 167 ++m_scavenged;
Chris@1429 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@1429 194 i != m_excess.end(); ++i) {
Chris@1429 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