2 * Copyright (C) 2006 Taybin Rutkin <taybin@taybin.com>
3 * Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
4 * Copyright (C) 2008-2011 Carl Hetherington <carl@carlh.net>
5 * Copyright (C) 1998-2015 Paul Davis <paul@linuxaudiosystems.com>
6 * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "pbd/pthread_utils.h"
30 #include "pbd/error.h"
31 #include "pbd/debug.h"
32 #include "pbd/compose.h"
37 Pool::Pool (string n, unsigned long item_size, unsigned long nitems)
46 /* since some overloaded ::operator new() might use this,
47 its important that we use a "lower level" allocator to
51 block = malloc (nitems * item_size);
53 void **ptrlist = (void **) malloc (sizeof (void *) * nitems);
55 for (unsigned long i = 0; i < nitems; i++) {
56 ptrlist[i] = static_cast<void *> (static_cast<char*>(block) + (i * item_size));
59 free_list.write (ptrlist, nitems);
66 // TODO: after collecting some stats, use DEBUG::PoolStats here
67 cerr << "Pool: '" << _name << "' max: " << max_usage << " / " << total() << endmsg;
72 /** Allocate an item's worth of memory in the Pool by taking one from the free list.
73 * @return Pointer to free item.
81 if (used () > max_usage) {
82 max_usage = used () + 1;
86 if (free_list.read (&ptr, 1) < 1) {
87 fatal << "CRITICAL: " << _name << " POOL OUT OF MEMORY - RECOMPILE WITH LARGER SIZE!!" << endmsg;
88 abort(); /*NOTREACHED*/
95 /** Release an item's memory by writing its location to the free list */
97 Pool::release (void *ptr)
99 free_list.write (&ptr, 1);
102 /*---------------------------------------------*/
104 MultiAllocSingleReleasePool::MultiAllocSingleReleasePool (string n, unsigned long isize, unsigned long nitems)
105 : Pool (n, isize, nitems)
109 MultiAllocSingleReleasePool::~MultiAllocSingleReleasePool ()
113 SingleAllocMultiReleasePool::SingleAllocMultiReleasePool (string n, unsigned long isize, unsigned long nitems)
114 : Pool (n, isize, nitems)
118 SingleAllocMultiReleasePool::~SingleAllocMultiReleasePool ()
123 MultiAllocSingleReleasePool::alloc ()
126 Glib::Threads::Mutex::Lock guard (m_lock);
127 ptr = Pool::alloc ();
132 MultiAllocSingleReleasePool::release (void* ptr)
138 SingleAllocMultiReleasePool::alloc ()
140 return Pool::alloc ();
144 SingleAllocMultiReleasePool::release (void* ptr)
146 Glib::Threads::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 ()
177 : _key (free_per_thread_pool)
182 /** Create a new CrossThreadPool and set the current thread's private _key to point to it.
184 * @param isize Size of each item in the pool.
185 * @param nitems Number of items in the pool.
188 PerThreadPool::create_per_thread_pool (string n, unsigned long isize, unsigned long nitems)
190 _key.set (new CrossThreadPool (n, isize, nitems, this));
193 /** @return True if CrossThreadPool for the current thread exists,
197 PerThreadPool::has_per_thread_pool ()
199 CrossThreadPool* p = _key.get();
207 /** @return CrossThreadPool for the current thread, which must previously have been created by
208 * calling create_per_thread_pool in the current thread.
211 PerThreadPool::per_thread_pool (bool must_exist)
213 CrossThreadPool* p = _key.get();
214 if (!p && must_exist) {
215 fatal << "programming error: no per-thread pool \"" << _name << "\" for thread " << pthread_name() << endmsg;
216 abort(); /*NOTREACHED*/
222 PerThreadPool::set_trash (RingBuffer<CrossThreadPool*>* t)
224 Glib::Threads::Mutex::Lock lm (_trash_mutex);
228 /** Add a CrossThreadPool to our trash, if we have one. If not, a warning is emitted. */
230 PerThreadPool::add_to_trash (CrossThreadPool* p)
232 Glib::Threads::Mutex::Lock lm (_trash_mutex);
235 warning << "Pool " << p->name() << " has no trash collector; a memory leak has therefore occurred" << endmsg;
239 /* we have a lock here so that multiple threads can safely call add_to_trash (even though there
240 can only be one writer to the _trash RingBuffer)
243 _trash->write (&p, 1);
246 CrossThreadPool::CrossThreadPool (string n, unsigned long isize, unsigned long nitems, PerThreadPool* p)
247 : Pool (n, isize, nitems)
255 CrossThreadPool::flush_pending_with_ev (void *ptr)
262 CrossThreadPool::flush_pending ()
265 bool did_release = false;
267 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(),
268 total(), available(), used()));
270 while (pending.read (&ptr, 1) == 1) {
271 DEBUG_TRACE (DEBUG::Pool, string_compose ("%1 %2 pushes back a pending free list entry before allocating\n", pthread_name(), name()));
272 free_list.write (&ptr, 1);
277 DEBUG_TRACE (DEBUG::Pool, string_compose ("Pool size: %1 free %2 used %3 pending now %4\n", total(), available(), used(), pending_size()));
282 CrossThreadPool::alloc ()
284 /* process anything waiting to be deleted (i.e. moved back to the free list) */
286 /* now allocate from the potentially larger free list */
287 return Pool::alloc ();
291 CrossThreadPool::push (void* t)
293 pending.write (&t, 1);
296 /** @return true if there is nothing in this pool */
298 CrossThreadPool::empty ()
300 return (free_list.write_space() == pending.read_space());