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
|