Roc Toolkit internal modules
Roc Toolkit: real-time audio streaming
Loading...
Searching...
No Matches
pool.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015 Roc authors
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
8
9//! @file roc_core/pool.h
10//! @brief Pool.
11
12#ifndef ROC_CORE_POOL_H_
13#define ROC_CORE_POOL_H_
14
15#include "roc_core/alignment.h"
16#include "roc_core/iallocator.h"
17#include "roc_core/list.h"
18#include "roc_core/log.h"
19#include "roc_core/mutex.h"
21#include "roc_core/panic.h"
22#include "roc_core/stddefs.h"
23
24namespace roc {
25namespace core {
26
27//! Pool.
28//!
29//! @tparam T defines object type.
30//!
31//! Allocates chunks from given allocator containing a fixed number of fixed
32//! sized objects. Maintains a list of free objects.
33//!
34//! The memory is always maximum aligned. Thread-safe.
35template <class T> class Pool : public NonCopyable<> {
36public:
37 //! Initialization.
38 //!
39 //! @b Parameters
40 //! - @p allocator is used to allocate chunks
41 //! - @p object_size defines object size in bytes
42 //! - @p poison enables memory poisoning for debugging
43 Pool(IAllocator& allocator, size_t object_size, bool poison)
44 : allocator_(allocator)
45 , used_elems_(0)
46 , elem_size_(max_align(std::max(sizeof(Elem), object_size)))
47 , chunk_hdr_size_(max_align(sizeof(Chunk)))
48 , chunk_n_elems_(1)
49 , poison_(poison) {
50 roc_log(LogDebug, "pool: initializing: object_size=%lu poison=%d",
51 (unsigned long)elem_size_, (int)poison);
52 }
53
54 ~Pool() {
55 deallocate_all_();
56 }
57
58 //! Allocate new object.
59 //! @returns
60 //! pointer to a maximum aligned uninitialized memory for a new object
61 //! or NULL if memory can't be allocated.
62 void* allocate() {
63 Elem* elem = get_elem_();
64 if (elem == NULL) {
65 return NULL;
66 }
67
68 elem->~Elem();
69
70 void* memory = elem;
71
72 if (poison_) {
73 memset(memory, PoisonAllocated, elem_size_);
74 } else {
75 memset(memory, 0, elem_size_);
76 }
77
78 return memory;
79 }
80
81 //! Free previously allocated memory.
82 void deallocate(void* memory) {
83 if (memory == NULL) {
84 roc_panic("pool: deallocating null pointer");
85 }
86
87 if (poison_) {
88 memset(memory, PoisonDeallocated, elem_size_);
89 }
90
91 Elem* elem = new (memory) Elem;
92 put_elem_(elem);
93 }
94
95 //! Destroy object and deallocate its memory.
96 void destroy(T& object) {
97 object.~T();
98 deallocate(&object);
99 }
100
101private:
102 enum { PoisonAllocated = 0x7a, PoisonDeallocated = 0x7d };
103
104 struct Chunk : ListNode {};
105 struct Elem : ListNode {};
106
107 Elem* get_elem_() {
108 Mutex::Lock lock(mutex_);
109
110 if (free_elems_.size() == 0) {
111 allocate_chunk_();
112 }
113
114 Elem* elem = free_elems_.front();
115 if (elem != NULL) {
116 free_elems_.remove(*elem);
117 used_elems_++;
118 }
119
120 return elem;
121 }
122
123 void put_elem_(Elem* elem) {
124 Mutex::Lock lock(mutex_);
125
126 if (used_elems_ == 0) {
127 roc_panic("pool: unpaired deallocation");
128 }
129
130 used_elems_--;
131 free_elems_.push_front(*elem);
132 }
133
134 void allocate_chunk_() {
135 void* memory = allocator_.allocate(chunk_offset_(chunk_n_elems_));
136 if (memory == NULL) {
137 return;
138 }
139
140 Chunk* chunk = new (memory) Chunk;
141 chunks_.push_back(*chunk);
142
143 for (size_t n = 0; n < chunk_n_elems_; n++) {
144 Elem* elem = new ((char*)chunk + chunk_offset_(n)) Elem;
145 free_elems_.push_back(*elem);
146 }
147
148 chunk_n_elems_ *= 2;
149 }
150
151 void deallocate_all_() {
152 if (used_elems_ != 0) {
153 roc_panic("pool: detected leak: used=%lu free=%lu",
154 (unsigned long)used_elems_, (unsigned long)free_elems_.size());
155 }
156
157 while (Elem* elem = free_elems_.front()) {
158 free_elems_.remove(*elem);
159 }
160
161 while (Chunk* chunk = chunks_.front()) {
162 chunks_.remove(*chunk);
163 allocator_.deallocate(chunk);
164 }
165 }
166
167 size_t chunk_offset_(size_t n) const {
168 return chunk_hdr_size_ + n * elem_size_;
169 }
170
171 Mutex mutex_;
172
173 IAllocator& allocator_;
174
175 List<Chunk, NoOwnership> chunks_;
176 List<Elem, NoOwnership> free_elems_;
177 size_t used_elems_;
178
179 const size_t elem_size_;
180 const size_t chunk_hdr_size_;
181 size_t chunk_n_elems_;
182
183 const bool poison_;
184};
185
186} // namespace core
187} // namespace roc
188
189//! Placement new for core::Pool<T>.
190//! @note
191//! nothrow forces compiler to check for NULL return value before calling ctor.
192template <class T>
193inline void* operator new(size_t size, roc::core::Pool<T>& pool) ROC_ATTR_NOTHROW {
194 roc_panic_if(size != sizeof(T));
195 return pool.allocate();
196}
197
198//! Placement delete for core::Pool<T>.
199//! @note
200//! Compiler calls this if ctor throws in a placement new expression.
201template <class T>
202inline void operator delete(void* ptr, roc::core::Pool<T>& pool)ROC_ATTR_NOTHROW {
203 pool.deallocate(ptr);
204}
205
206#endif // ROC_CORE_POOL_H_
Alignment.
#define ROC_ATTR_NOTHROW
Function never throws.
Definition: attributes.h:16
Memory allocator interface.
Definition: iallocator.h:23
virtual void deallocate(void *)=0
Deallocate previously allocated memory.
virtual void * allocate(size_t size)=0
Allocate memory.
ScopedLock< Mutex > Lock
RAII lock.
Definition: mutex.h:30
Base class for non-copyable objects.
Definition: noncopyable.h:23
Pool.
Definition: pool.h:35
void destroy(T &object)
Destroy object and deallocate its memory.
Definition: pool.h:96
Pool(IAllocator &allocator, size_t object_size, bool poison)
Initialization.
Definition: pool.h:43
void * allocate()
Allocate new object.
Definition: pool.h:62
void deallocate(void *memory)
Free previously allocated memory.
Definition: pool.h:82
Memory allocator interface.
Intrusive doubly-linked list.
Logging.
#define roc_log(...)
Print message to log.
Definition: log.h:25
Mutex.
size_t max_align(size_t sz)
Adjust the given size to be maximum aligned.
Definition: alignment.h:27
Root namespace.
@ LogDebug
Debug message.
Definition: log.h:35
Non-copyable object.
Panic function.
#define roc_panic_if(x)
Panic if condition is true.
Definition: panic.h:26
#define roc_panic(...)
Print error message and terminate program gracefully.
Definition: panic.h:42
Commonly used types and functions.