ardour
pool.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 1998-99 Paul Barton-Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18  $Id$
19 */
20 
21 #include <cstdlib>
22 #include <vector>
23 #include <cstdlib>
24 #include <cassert>
25 
26 #include "pbd/pool.h"
27 #include "pbd/pthread_utils.h"
28 #include "pbd/error.h"
29 #include "pbd/debug.h"
30 #include "pbd/compose.h"
31 
32 using namespace std;
33 using namespace PBD;
34 
35 Pool::Pool (string n, unsigned long item_size, unsigned long nitems)
36  : free_list (nitems)
37  , _name (n)
38 {
39  _name = n;
40 
41  /* since some overloaded ::operator new() might use this,
42  its important that we use a "lower level" allocator to
43  get more space.
44  */
45 
46  block = malloc (nitems * item_size);
47 
48  void **ptrlist = (void **) malloc (sizeof (void *) * nitems);
49 
50  for (unsigned long i = 0; i < nitems; i++) {
51  ptrlist[i] = static_cast<void *> (static_cast<char*>(block) + (i * item_size));
52  }
53 
54  free_list.write (ptrlist, nitems);
55  free (ptrlist);
56 }
57 
59 {
60  free (block);
61 }
62 
66 void *
68 {
69  void *ptr;
70 
71  if (free_list.read (&ptr, 1) < 1) {
72  fatal << "CRITICAL: " << _name << " POOL OUT OF MEMORY - RECOMPILE WITH LARGER SIZE!!" << endmsg;
73  abort(); /*NOTREACHED*/
74  return 0;
75  } else {
76  return ptr;
77  }
78 }
79 
81 void
82 Pool::release (void *ptr)
83 {
84  free_list.write (&ptr, 1);
85 }
86 
87 /*---------------------------------------------*/
88 
89 MultiAllocSingleReleasePool::MultiAllocSingleReleasePool (string n, unsigned long isize, unsigned long nitems)
90  : Pool (n, isize, nitems)
91 {
92 }
93 
95 {
96 }
97 
98 SingleAllocMultiReleasePool::SingleAllocMultiReleasePool (string n, unsigned long isize, unsigned long nitems)
99  : Pool (n, isize, nitems)
100 {
101 }
102 
104 {
105 }
106 
107 void*
109 {
110  void *ptr;
112  ptr = Pool::alloc ();
113  return ptr;
114 }
115 
116 void
118 {
119  Pool::release (ptr);
120 }
121 
122 void*
124 {
125  return Pool::alloc ();
126 }
127 
128 void
130 {
132  Pool::release (ptr);
133 }
134 
135 /*-------------------------------------------------------*/
136 
137 static void
139 {
140  /* Rather than deleting the CrossThreadPool now, we add it to our trash buffer.
141  * This prevents problems if other threads still require access to this CrossThreadPool.
142  * We assume that some other agent will clean out the trash buffer as required.
143  */
144  CrossThreadPool* cp = static_cast<CrossThreadPool*> (ptr);
145  assert (cp);
146 
147  if (cp->empty()) {
148  /* This CrossThreadPool is already empty, and the thread is finishing so nothing
149  * more can be added to it. We can just delete the pool.
150  */
151  delete cp;
152  } else {
153  /* This CrossThreadPool is not empty, meaning that there's some Events in it
154  * which another thread may yet read, so we can't delete the pool just yet.
155  * Put it in the trash and hope someone deals with it at some stage.
156  */
157  cp->parent()->add_to_trash (cp);
158  }
159 }
160 
162  : _key (free_per_thread_pool)
163  , _trash (0)
164 {
165 }
166 
172 void
173 PerThreadPool::create_per_thread_pool (string n, unsigned long isize, unsigned long nitems)
174 {
175  _key.set (new CrossThreadPool (n, isize, nitems, this));
176 }
177 
183 {
184  CrossThreadPool* p = _key.get();
185  if (!p && must_exist) {
186  fatal << "programming error: no per-thread pool \"" << _name << "\" for thread " << pthread_name() << endmsg;
187  abort(); /*NOTREACHED*/
188  }
189  return p;
190 }
191 
192 void
194 {
196  _trash = t;
197 }
198 
200 void
202 {
204 
205  if (!_trash) {
206  warning << "Pool " << p->name() << " has no trash collector; a memory leak has therefore occurred" << endmsg;
207  return;
208  }
209 
210  /* we have a lock here so that multiple threads can safely call add_to_trash (even though there
211  can only be one writer to the _trash RingBuffer)
212  */
213 
214  _trash->write (&p, 1);
215 }
216 
217 CrossThreadPool::CrossThreadPool (string n, unsigned long isize, unsigned long nitems, PerThreadPool* p)
218  : Pool (n, isize, nitems)
219  , pending (nitems)
220  , _parent (p)
221 {
222 
223 }
224 
225 void
227 {
228  push (ptr);
229  flush_pending ();
230 }
231 
232 void
234 {
235  void* ptr;
236  bool did_release = false;
237 
238  DEBUG_TRACE (DEBUG::Pool, string_compose ("%1 %2 has %3 pending free entries waiting, status size %4 free %5 used %6\n", pthread_name(), name(), pending.read_space(),
239  total(), available(), used()));
240 
241  while (pending.read (&ptr, 1) == 1) {
242  DEBUG_TRACE (DEBUG::Pool, string_compose ("%1 %2 pushes back a pending free list entry before allocating\n", pthread_name(), name()));
243  free_list.write (&ptr, 1);
244  did_release = true;
245  }
246 
247  if (did_release) {
248  DEBUG_TRACE (DEBUG::Pool, string_compose ("Pool size: %1 free %2 used %3 pending now %4\n", total(), available(), used(), pending_size()));
249  }
250 }
251 
252 void*
254 {
255  /* process anything waiting to be deleted (i.e. moved back to the free list) */
256  flush_pending ();
257  /* now allocate from the potentially larger free list */
258  return Pool::alloc ();
259 }
260 
261 void
263 {
264  pending.write (&t, 1);
265 }
266 
268 bool
270 {
271  return (free_list.write_space() == pending.read_space());
272 }
273 
LIBPBD_API uint64_t Pool
Definition: debug.cc:49
LIBPBD_API const char * pthread_name()
LIBPBD_API Transmitter fatal
guint used() const
Definition: pool.h:45
RingBuffer< void * > free_list
a list of pointers to free items within block
Definition: pool.h:49
std::string _name
Definition: pool.h:50
guint read_space() const
Definition: ringbuffer.h:97
void push(void *)
Definition: pool.cc:262
std::string _name
Definition: pool.h:138
virtual void * alloc()
Definition: pool.cc:123
void * block
data storage area
Definition: pool.h:53
Glib::Threads::Mutex m_lock
Definition: pool.h:80
Definition: Beats.hpp:239
LIBPBD_API Transmitter warning
guint write_space() const
Definition: ringbuffer.h:82
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
guint read(T *dest, guint cnt)
Definition: ringbuffer.h:124
guint pending_size() const
Definition: pool.h:110
virtual void release(void *)
Definition: pool.cc:117
virtual void release(void *)
Definition: pool.cc:82
static void free_per_thread_pool(void *ptr)
Definition: pool.cc:138
CrossThreadPool * per_thread_pool(bool must_exist=true)
Definition: pool.cc:182
Pool(std::string name, unsigned long item_size, unsigned long nitems)
Definition: pool.cc:35
RingBuffer< void * > pending
Definition: pool.h:116
Definition: pool.h:34
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
PerThreadPool * parent() const
Definition: pool.h:105
SingleAllocMultiReleasePool(std::string name, unsigned long item_size, unsigned long nitems)
Definition: pool.cc:98
virtual ~Pool()
Definition: pool.cc:58
guint write(T const *src, guint cnt)
Definition: ringbuffer.h:163
RingBuffer< CrossThreadPool * > * _trash
Definition: pool.h:142
MultiAllocSingleReleasePool(std::string name, unsigned long item_size, unsigned long nitems)
Definition: pool.cc:89
bool empty()
Definition: pool.cc:269
void * alloc()
Definition: pool.cc:253
void create_per_thread_pool(std::string name, unsigned long item_size, unsigned long nitems)
Definition: pool.cc:173
void flush_pending()
Definition: pool.cc:233
void set_trash(RingBuffer< CrossThreadPool * > *t)
Definition: pool.cc:193
std::string name() const
Definition: pool.h:43
guint available() const
Definition: pool.h:44
Definition: debug.h:30
Glib::Threads::Private< CrossThreadPool > _key
Definition: pool.h:137
PerThreadPool()
Definition: pool.cc:161
Glib::Threads::Mutex _trash_mutex
Definition: pool.h:141
virtual void release(void *)
Definition: pool.cc:129
Glib::Threads::Mutex m_lock
Definition: pool.h:66
guint total() const
Definition: pool.h:46
virtual void * alloc()
Definition: pool.cc:108
void flush_pending_with_ev(void *)
Definition: pool.cc:226
virtual void * alloc()
Definition: pool.cc:67
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
CrossThreadPool(std::string n, unsigned long isize, unsigned long nitems, PerThreadPool *)
Definition: pool.cc:217
void add_to_trash(CrossThreadPool *)
Definition: pool.cc:201