1 /* 2 * Copyright (C) 1998-2015 Paul Davis <paul@linuxaudiosystems.com> 3 * Copyright (C) 2009-2014 David Robillard <d@drobilla.net> 4 * Copyright (C) 2010 Carl Hetherington <carl@carlh.net> 5 * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 */ 21 22 #ifndef __qm_pool_h__ 23 #define __qm_pool_h__ 24 25 #include <vector> 26 #include <string> 27 28 #include <glibmm/threads.h> 29 30 #include "pbd/libpbd_visibility.h" 31 #include "pbd/ringbuffer.h" 32 33 /** A pool of data items that can be allocated, read from and written to 34 * without system memory allocation or locking. 35 */ 36 class LIBPBD_API Pool 37 { 38 public: 39 Pool (std::string name, unsigned long item_size, unsigned long nitems); 40 virtual ~Pool (); 41 42 virtual void *alloc (); 43 virtual void release (void *); 44 name()45 std::string name() const { return _name; } available()46 guint available() const { return free_list.read_space(); } used()47 guint used() const { return free_list.bufsize() - available(); } total()48 guint total() const { return free_list.bufsize(); } 49 50 protected: 51 PBD::RingBuffer<void*> free_list; ///< a list of pointers to free items within block 52 std::string _name; 53 54 private: 55 void *block; ///< data storage area 56 #ifndef NDEBUG 57 unsigned long max_usage; 58 #endif 59 }; 60 61 class LIBPBD_API SingleAllocMultiReleasePool : public Pool 62 { 63 public: 64 SingleAllocMultiReleasePool (std::string name, unsigned long item_size, unsigned long nitems); 65 ~SingleAllocMultiReleasePool (); 66 67 virtual void *alloc (); 68 virtual void release (void *); 69 70 private: 71 Glib::Threads::Mutex m_lock; 72 }; 73 74 75 class LIBPBD_API MultiAllocSingleReleasePool : public Pool 76 { 77 public: 78 MultiAllocSingleReleasePool (std::string name, unsigned long item_size, unsigned long nitems); 79 ~MultiAllocSingleReleasePool (); 80 81 virtual void *alloc (); 82 virtual void release (void *); 83 84 private: 85 Glib::Threads::Mutex m_lock; 86 }; 87 88 class LIBPBD_API PerThreadPool; 89 90 /** Management of a per-thread pool of data that is allocated by one thread and 91 * freed by one other thread. Not safe for use when there is more than 1 92 * reader and 1 writer. 93 * 94 * This is basically a wrapper around a thread-local storage instance of a 95 * ringbuffer, made safe for use in the case where multiple threads allocate 96 * from the ringbuffer and a single thread "frees" the allocations. 97 * 98 * Rather than using locks, each thread has its own ringbuffer (and associated 99 * data), and so it calls alloc(), passes a pointer to the result of the alloc 100 * to another thread, which later calls push() to "free" it. 101 */ 102 class LIBPBD_API CrossThreadPool : public Pool 103 { 104 public: 105 CrossThreadPool (std::string n, unsigned long isize, unsigned long nitems, PerThreadPool *); 106 107 void* alloc (); 108 void push (void *); 109 parent()110 PerThreadPool* parent () const { 111 return _parent; 112 } 113 114 bool empty (); pending_size()115 guint pending_size() const { return pending.read_space(); } 116 117 void flush_pending (); 118 void flush_pending_with_ev (void*); 119 120 private: 121 PBD::RingBuffer<void*> pending; 122 PerThreadPool* _parent; 123 }; 124 125 /** A class to manage per-thread pools of memory. One object of this class is instantiated, 126 * and then it is used to create per-thread pools for 1 or more threads as required. 127 */ 128 class LIBPBD_API PerThreadPool 129 { 130 public: 131 PerThreadPool (); 132 key()133 const Glib::Threads::Private<CrossThreadPool>& key() const { return _key; } 134 135 void create_per_thread_pool (std::string name, unsigned long item_size, unsigned long nitems); 136 CrossThreadPool* per_thread_pool (bool must_exist = true); 137 bool has_per_thread_pool (); 138 void set_trash (PBD::RingBuffer<CrossThreadPool*>* t); 139 void add_to_trash (CrossThreadPool *); 140 141 private: 142 Glib::Threads::Private<CrossThreadPool> _key; 143 std::string _name; 144 145 /** mutex to protect either changes to the _trash variable, or writes to the RingBuffer */ 146 Glib::Threads::Mutex _trash_mutex; 147 PBD::RingBuffer<CrossThreadPool*>* _trash; 148 }; 149 150 #endif // __qm_pool_h__ 151