annotate base/Scavenger.h @ 986:e8e6c4e7437b

Correct some really stupid fixed-length string stuff, including a genuine stack overflow that causes a crash on OS/X for certain colour 3d plot data.
author Chris Cannam
date Mon, 29 Sep 2014 13:27:13 +0100
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