annotate base/Scavenger.h @ 167:665342c6ec57

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents 74abef65711b
children 0e266fa2510f
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@158 30 #include <pthread.h>
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@158 72 pthread_mutex_t 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@0 100 m_claimed(0),
Chris@0 101 m_scavenged(0)
Chris@0 102 {
Chris@158 103 pthread_mutex_init(&m_excessMutex, NULL);
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@158 122
Chris@158 123 pthread_mutex_destroy(&m_excessMutex);
Chris@0 124 }
Chris@0 125
Chris@0 126 template <typename T>
Chris@0 127 void
Chris@0 128 Scavenger<T>::claim(T *t)
Chris@0 129 {
Chris@0 130 // std::cerr << "Scavenger::claim(" << t << ")" << std::endl;
Chris@0 131
Chris@0 132 struct timeval tv;
Chris@0 133 (void)gettimeofday(&tv, 0);
Chris@0 134 int sec = tv.tv_sec;
Chris@0 135
Chris@0 136 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@0 137 ObjectTimePair &pair = m_objects[i];
Chris@0 138 if (pair.first == 0) {
Chris@0 139 pair.second = sec;
Chris@0 140 pair.first = t;
Chris@0 141 ++m_claimed;
Chris@0 142 return;
Chris@0 143 }
Chris@0 144 }
Chris@0 145
Chris@158 146 std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
Chris@158 147 << "using non-RT-safe method" << std::endl;
Chris@158 148 pushExcess(t);
Chris@0 149 }
Chris@0 150
Chris@0 151 template <typename T>
Chris@0 152 void
Chris@14 153 Scavenger<T>::scavenge(bool clearNow)
Chris@0 154 {
Chris@0 155 // std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl;
Chris@0 156
Chris@0 157 if (m_scavenged >= m_claimed) return;
Chris@0 158
Chris@0 159 struct timeval tv;
Chris@0 160 (void)gettimeofday(&tv, 0);
Chris@0 161 int sec = tv.tv_sec;
Chris@0 162
Chris@0 163 for (size_t i = 0; i < m_objects.size(); ++i) {
Chris@0 164 ObjectTimePair &pair = m_objects[i];
Chris@14 165 if (clearNow ||
Chris@14 166 (pair.first != 0 && pair.second + m_sec < sec)) {
Chris@0 167 T *ot = pair.first;
Chris@0 168 pair.first = 0;
Chris@0 169 delete ot;
Chris@0 170 ++m_scavenged;
Chris@0 171 }
Chris@0 172 }
Chris@158 173
Chris@158 174 if (sec > m_lastExcess + m_sec) {
Chris@158 175 clearExcess(sec);
Chris@158 176 }
Chris@158 177 }
Chris@158 178
Chris@158 179 template <typename T>
Chris@158 180 void
Chris@158 181 Scavenger<T>::pushExcess(T *t)
Chris@158 182 {
Chris@158 183 pthread_mutex_lock(&m_excessMutex);
Chris@158 184 m_excess.push_back(t);
Chris@158 185 struct timeval tv;
Chris@158 186 (void)gettimeofday(&tv, 0);
Chris@158 187 m_lastExcess = tv.tv_sec;
Chris@158 188 pthread_mutex_unlock(&m_excessMutex);
Chris@158 189 }
Chris@158 190
Chris@158 191 template <typename T>
Chris@158 192 void
Chris@158 193 Scavenger<T>::clearExcess(int sec)
Chris@158 194 {
Chris@158 195 pthread_mutex_lock(&m_excessMutex);
Chris@158 196 for (typename ObjectList::iterator i = m_excess.begin();
Chris@158 197 i != m_excess.end(); ++i) {
Chris@158 198 delete *i;
Chris@158 199 }
Chris@158 200 m_excess.clear();
Chris@158 201 m_lastExcess = sec;
Chris@158 202 pthread_mutex_unlock(&m_excessMutex);
Chris@0 203 }
Chris@0 204
Chris@0 205 #endif