update JACK backend to use new inheritance structure for AudioBackend
[ardour.git] / libs / rubberband / src / Scavenger.h
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3 /*
4     Rubber Band
5     An audio time-stretching and pitch-shifting library.
6     Copyright 2007-2008 Chris Cannam.
7     
8     This program is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License as
10     published by the Free Software Foundation; either version 2 of the
11     License, or (at your option) any later version.  See the file
12     COPYING included with this distribution for more information.
13 */
14
15 #ifndef _RUBBERBAND_SCAVENGER_H_
16 #define _RUBBERBAND_SCAVENGER_H_
17
18 #include <vector>
19 #include <list>
20 #include <iostream>
21
22 #ifndef WIN32
23 #include <sys/time.h>
24 #endif
25
26 #include "Thread.h"
27 #include "sysutils.h"
28
29 namespace RubberBand {
30
31 /**
32  * A very simple class that facilitates running things like plugins
33  * without locking, by collecting unwanted objects and deleting them
34  * after a delay so as to be sure nobody's in the middle of using
35  * them.  Requires scavenge() to be called regularly from a non-RT
36  * thread.
37  *
38  * This is currently not at all suitable for large numbers of objects
39  * -- it's just a quick hack for use with things like plugins.
40  */
41
42 template <typename T>
43 class Scavenger
44 {
45 public:
46     Scavenger(int sec = 2, int defaultObjectListSize = 200);
47     ~Scavenger();
48
49     /**
50      * Call from an RT thread etc., to pass ownership of t to us.
51      * Only one thread should be calling this on any given scavenger.
52      */
53     void claim(T *t);
54
55     /**
56      * Call from a non-RT thread.
57      * Only one thread should be calling this on any given scavenger.
58      */
59     void scavenge(bool clearNow = false);
60
61 protected:
62     typedef std::pair<T *, int> ObjectTimePair;
63     typedef std::vector<ObjectTimePair> ObjectTimeList;
64     ObjectTimeList m_objects;
65     int m_sec;
66
67     typedef std::list<T *> ObjectList;
68     ObjectList m_excess;
69     int m_lastExcess;
70     Mutex m_excessMutex;
71     void pushExcess(T *);
72     void clearExcess(int);
73
74     unsigned int m_claimed;
75     unsigned int m_scavenged;
76 };
77
78 /**
79  * A wrapper to permit arrays to be scavenged.
80  */
81
82 template <typename T>
83 class ScavengerArrayWrapper
84 {
85 public:
86     ScavengerArrayWrapper(T *array) : m_array(array) { }
87     ~ScavengerArrayWrapper() { delete[] m_array; }
88
89 private:
90     T *m_array;
91 };
92
93
94 template <typename T>
95 Scavenger<T>::Scavenger(int sec, int defaultObjectListSize) :
96     m_objects(ObjectTimeList(defaultObjectListSize)),
97     m_sec(sec),
98     m_claimed(0),
99     m_scavenged(0)
100 {
101 }
102
103 template <typename T>
104 Scavenger<T>::~Scavenger()
105 {
106     if (m_scavenged < m_claimed) {
107         for (size_t i = 0; i < m_objects.size(); ++i) {
108             ObjectTimePair &pair = m_objects[i];
109             if (pair.first != 0) {
110                 T *ot = pair.first;
111                 pair.first = 0;
112                 delete ot;
113                 ++m_scavenged;
114             }
115         }
116     }
117
118     clearExcess(0);
119 }
120
121 template <typename T>
122 void
123 Scavenger<T>::claim(T *t)
124 {
125 //    std::cerr << "Scavenger::claim(" << t << ")" << std::endl;
126
127     struct timeval tv;
128     (void)gettimeofday(&tv, 0);
129     int sec = tv.tv_sec;
130
131     for (size_t i = 0; i < m_objects.size(); ++i) {
132         ObjectTimePair &pair = m_objects[i];
133         if (pair.first == 0) {
134             pair.second = sec;
135             pair.first = t;
136             ++m_claimed;
137             return;
138         }
139     }
140
141     std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, "
142               << "using non-RT-safe method" << std::endl;
143     pushExcess(t);
144 }
145
146 template <typename T>
147 void
148 Scavenger<T>::scavenge(bool clearNow)
149 {
150 //    std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl;
151
152     if (m_scavenged >= m_claimed) return;
153     
154     struct timeval tv;
155     (void)gettimeofday(&tv, 0);
156     int sec = tv.tv_sec;
157
158     for (size_t i = 0; i < m_objects.size(); ++i) {
159         ObjectTimePair &pair = m_objects[i];
160         if (clearNow ||
161             (pair.first != 0 && pair.second + m_sec < sec)) {
162             T *ot = pair.first;
163             pair.first = 0;
164             delete ot;
165             ++m_scavenged;
166         }
167     }
168
169     if (sec > m_lastExcess + m_sec) {
170         clearExcess(sec);
171     }
172 }
173
174 template <typename T>
175 void
176 Scavenger<T>::pushExcess(T *t)
177 {
178     m_excessMutex.lock();
179     m_excess.push_back(t);
180     struct timeval tv;
181     (void)gettimeofday(&tv, 0);
182     m_lastExcess = tv.tv_sec;
183     m_excessMutex.unlock();
184 }
185
186 template <typename T>
187 void
188 Scavenger<T>::clearExcess(int sec)
189 {
190     m_excessMutex.lock();
191     for (typename ObjectList::iterator i = m_excess.begin();
192          i != m_excess.end(); ++i) {
193         delete *i;
194     }
195     m_excess.clear();
196     m_lastExcess = sec;
197     m_excessMutex.unlock();
198 }
199
200 }
201
202 #endif