2 Copyright (C) 1998-99 Paul Barton-Davis
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.
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.
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.
28 #include "pbd/error.h"
29 #include "pbd/debug.h"
30 #include "pbd/compose.h"
35 Pool::Pool (string n
, unsigned long item_size
, unsigned long nitems
)
41 /* since some overloaded ::operator new() might use this,
42 its important that we use a "lower level" allocator to
46 block
= malloc (nitems
* item_size
);
48 void **ptrlist
= (void **) malloc (sizeof (void *) * nitems
);
50 for (unsigned long i
= 0; i
< nitems
; i
++) {
51 ptrlist
[i
] = static_cast<void *> (static_cast<char*>(block
) + (i
* item_size
));
54 free_list
.write (ptrlist
, nitems
);
63 /** Allocate an item's worth of memory in the Pool by taking one from the free list.
64 * @return Pointer to free item.
71 if (free_list
.read (&ptr
, 1) < 1) {
72 fatal
<< "CRITICAL: " << _name
<< " POOL OUT OF MEMORY - RECOMPILE WITH LARGER SIZE!!" << endmsg
;
80 /** Release an item's memory by writing its location to the free list */
82 Pool::release (void *ptr
)
84 free_list
.write (&ptr
, 1);
87 /*---------------------------------------------*/
89 MultiAllocSingleReleasePool::MultiAllocSingleReleasePool (string n
, unsigned long isize
, unsigned long nitems
)
90 : Pool (n
, isize
, nitems
)
95 MultiAllocSingleReleasePool::~MultiAllocSingleReleasePool ()
100 SingleAllocMultiReleasePool::SingleAllocMultiReleasePool (string n
, unsigned long isize
, unsigned long nitems
)
101 : Pool (n
, isize
, nitems
)
106 SingleAllocMultiReleasePool::~SingleAllocMultiReleasePool ()
112 MultiAllocSingleReleasePool::alloc ()
116 m_lock
= new Glib::Mutex();
117 // umm, I'm not sure that this doesn't also allocate memory.
118 if(!m_lock
) error
<< "cannot create Glib::Mutex in pool.cc" << endmsg
;
121 Glib::Mutex::Lock
guard(*m_lock
);
122 ptr
= Pool::alloc ();
127 MultiAllocSingleReleasePool::release (void* ptr
)
133 SingleAllocMultiReleasePool::alloc ()
135 return Pool::alloc ();
139 SingleAllocMultiReleasePool::release (void* ptr
)
142 m_lock
= new Glib::Mutex();
143 // umm, I'm not sure that this doesn't also allocate memory.
144 if(!m_lock
) error
<< "cannot create Glib::Mutex in pool.cc" << endmsg
;
146 Glib::Mutex::Lock
guard(*m_lock
);
150 /*-------------------------------------------------------*/
153 free_per_thread_pool (void* ptr
)
155 /* Rather than deleting the CrossThreadPool now, we add it to our trash buffer.
156 * This prevents problems if other threads still require access to this CrossThreadPool.
157 * We assume that some other agent will clean out the trash buffer as required.
159 CrossThreadPool
* cp
= static_cast<CrossThreadPool
*> (ptr
);
163 /* This CrossThreadPool is already empty, and the thread is finishing so nothing
164 * more can be added to it. We can just delete the pool.
168 /* This CrossThreadPool is not empty, meaning that there's some Events in it
169 * which another thread may yet read, so we can't delete the pool just yet.
170 * Put it in the trash and hope someone deals with it at some stage.
172 cp
->parent()->add_to_trash (cp
);
176 PerThreadPool::PerThreadPool ()
180 /* for some reason this appears necessary to get glib's thread private stuff to work */
182 key
= g_private_new (NULL
);
185 _key
= g_private_new (free_per_thread_pool
);
188 /** Create a new CrossThreadPool and set the current thread's private _key to point to it.
190 * @param isize Size of each item in the pool.
191 * @param nitems Number of items in the pool.
194 PerThreadPool::create_per_thread_pool (string n
, unsigned long isize
, unsigned long nitems
)
196 CrossThreadPool
* p
= new CrossThreadPool (n
, isize
, nitems
, this);
197 g_private_set (_key
, p
);
200 /** @return CrossThreadPool for the current thread, which must previously have been created by
201 * calling create_per_thread_pool in the current thread.
204 PerThreadPool::per_thread_pool ()
206 CrossThreadPool
* p
= static_cast<CrossThreadPool
*> (g_private_get (_key
));
208 fatal
<< "programming error: no per-thread pool \"" << _name
<< "\" for thread " << pthread_self() << endmsg
;
215 PerThreadPool::set_trash (RingBuffer
<CrossThreadPool
*>* t
)
217 Glib::Mutex::Lock
lm (_trash_mutex
);
221 /** Add a CrossThreadPool to our trash, if we have one. If not, a warning is emitted. */
223 PerThreadPool::add_to_trash (CrossThreadPool
* p
)
225 Glib::Mutex::Lock
lm (_trash_mutex
);
228 warning
<< "Pool " << p
->name() << " has no trash collector; a memory leak has therefore occurred" << endmsg
;
232 /* we have a lock here so that multiple threads can safely call add_to_trash (even though there
233 can only be one writer to the _trash RingBuffer)
236 _trash
->write (&p
, 1);
239 CrossThreadPool::CrossThreadPool (string n
, unsigned long isize
, unsigned long nitems
, PerThreadPool
* p
)
240 : Pool (n
, isize
, nitems
)
248 CrossThreadPool::alloc ()
252 DEBUG_TRACE (DEBUG::Pool
, string_compose ("%1 %2 has %3 pending free entries waiting\n", pthread_self(), name(), pending
.read_space()));
253 while (pending
.read (&ptr
, 1) == 1) {
254 DEBUG_TRACE (DEBUG::Pool
, string_compose ("%1 %2 pushes back a pending free list entry before allocating\n", pthread_self(), name()));
255 free_list
.write (&ptr
, 1);
257 return Pool::alloc ();
261 CrossThreadPool::push (void* t
)
263 pending
.write (&t
, 1);
266 /** @return true if there is nothing in this pool */
268 CrossThreadPool::empty ()
270 return (free_list
.write_space() == pending
.read_space());