|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qmallocpool_p.h" |
|
43 #include <qglobal.h> |
|
44 |
|
45 struct malloc_state; |
|
46 |
|
47 QTM_BEGIN_NAMESPACE |
|
48 |
|
49 static void* qmallocpool_sbrk(intptr_t increment); |
|
50 |
|
51 #define USE_DL_PREFIX |
|
52 #define MORECORE QTM_NAMESPACE::qmallocpool_sbrk |
|
53 #define HAVE_MMAP 0 |
|
54 #define __STD_C 1 |
|
55 #ifdef Q_OS_WINCE |
|
56 #define WIN32 |
|
57 #define LACKS_ERRNO_H |
|
58 #define MALLOC_FAILURE_ACTION |
|
59 #endif |
|
60 |
|
61 static QMallocPoolPrivate * qmallocpool_instance = 0; |
|
62 static struct malloc_state * qmallocpool_state(QMallocPoolPrivate *); |
|
63 #define get_malloc_state() (QTM_NAMESPACE::qmallocpool_state(QTM_NAMESPACE::qmallocpool_instance)) |
|
64 |
|
65 QTM_END_NAMESPACE |
|
66 |
|
67 #include "dlmalloc.c" |
|
68 |
|
69 QTM_BEGIN_NAMESPACE |
|
70 |
|
71 class QMallocPoolPrivate |
|
72 { |
|
73 public: |
|
74 QMallocPoolPrivate(void * _pool, unsigned int _poolLen, |
|
75 QMallocPool::PoolType type, const QString &_name) |
|
76 : name(_name), pool((char *)_pool), poolLength(_poolLen), poolPtr(0) |
|
77 { |
|
78 Q_ASSERT(pool); |
|
79 Q_ASSERT(poolLength > 0); |
|
80 |
|
81 if(QMallocPool::Owned == type) { |
|
82 qMemSet(&owned_mstate, 0, sizeof(struct malloc_state)); |
|
83 mstate = &owned_mstate; |
|
84 } else if(QMallocPool::NewShared == type) { |
|
85 Q_ASSERT(poolLength >= sizeof(struct malloc_state)); |
|
86 qMemSet(pool, 0, sizeof(struct malloc_state)); |
|
87 mstate = (struct malloc_state *)pool; |
|
88 pool += sizeof(struct malloc_state); |
|
89 poolLength -= sizeof(struct malloc_state); |
|
90 } else if(QMallocPool::Shared == type) { |
|
91 Q_ASSERT(poolLength >= sizeof(struct malloc_state)); |
|
92 mstate = (struct malloc_state *)pool; |
|
93 pool += sizeof(struct malloc_state); |
|
94 poolLength -= sizeof(struct malloc_state); |
|
95 } |
|
96 } |
|
97 |
|
98 QString name; |
|
99 char * pool; |
|
100 unsigned int poolLength; |
|
101 unsigned int poolPtr; |
|
102 struct malloc_state *mstate; |
|
103 struct malloc_state owned_mstate; |
|
104 }; |
|
105 |
|
106 static struct malloc_state * qmallocpool_state(QMallocPoolPrivate *d) |
|
107 { |
|
108 Q_ASSERT(d); |
|
109 return d->mstate; |
|
110 } |
|
111 |
|
112 static void* qmallocpool_sbrk(intptr_t increment) |
|
113 { |
|
114 Q_ASSERT(qmallocpool_instance); |
|
115 QMallocPoolPrivate * const d = qmallocpool_instance; |
|
116 |
|
117 if(increment > 0) { |
|
118 if((unsigned)increment > d->poolLength || |
|
119 (d->poolLength - increment) < d->poolPtr) |
|
120 // Failure |
|
121 return (void *)MORECORE_FAILURE; |
|
122 |
|
123 void * rv = (void *)(d->pool + d->poolPtr); |
|
124 d->poolPtr += increment; |
|
125 return rv; |
|
126 |
|
127 } else /* increment <= 0 */ { |
|
128 Q_ASSERT(d->poolPtr >= (unsigned)(-1 * increment)); |
|
129 d->poolPtr += increment; |
|
130 return (void *)(d->pool + d->poolPtr); |
|
131 } |
|
132 } |
|
133 |
|
134 struct QMallocPtr |
|
135 { |
|
136 QMallocPtr(QMallocPoolPrivate * d) |
|
137 { |
|
138 Q_ASSERT(!qmallocpool_instance); |
|
139 qmallocpool_instance = d; |
|
140 } |
|
141 ~QMallocPtr() |
|
142 { |
|
143 Q_ASSERT(qmallocpool_instance); |
|
144 qmallocpool_instance = 0; |
|
145 } |
|
146 }; |
|
147 |
|
148 /*! |
|
149 \class QMallocPool |
|
150 \internal |
|
151 \ingroup publishsubscribe |
|
152 |
|
153 \brief The QMallocPool class allows management of allocations within a |
|
154 designated memory region. |
|
155 |
|
156 QMallocPool provides heap management capabilities into a fixed region of |
|
157 memory. Primarily this is useful for managing allocations in a shared |
|
158 memory region, but could be used in other scenarios. |
|
159 |
|
160 The QMallocPool class provides equivalents for most standard memory management |
|
161 functions, such as \c {malloc}, \c {calloc}, \c {realloc} and \c {free}. |
|
162 However, unlike these standard functions which acquire their memory from the |
|
163 system kernel, QMallocPool operators on a region of memory provided to it |
|
164 during construction. |
|
165 |
|
166 QMallocPool is based on dlmalloc, a public domain malloc implementation |
|
167 written by Doug Lea. dlmalloc is used as the default allocator in many |
|
168 projects, including several versions of Linux libc. |
|
169 |
|
170 QMallocPool is not thread safe. |
|
171 */ |
|
172 |
|
173 /*! |
|
174 \enum QMallocPool::PoolType |
|
175 |
|
176 Controls the type of pool to be created. In order to manage memory, a small |
|
177 amount of book keeping information is maintained. While this information is |
|
178 not required for reading from the managed pool, it is required for |
|
179 allocations. The PoolType controls where this bookkeeping data is stored. |
|
180 |
|
181 \value Owned |
|
182 The bookkeeping data is maintained in the QMallocPool instance. Allocation to |
|
183 the pool is only possible via this instance. |
|
184 \value NewShared |
|
185 The bookkeeping data is maintained in the managed region itself. This allows |
|
186 multiple QMallocPool instances, possibly in separate processes, to allocate |
|
187 from the pool. |
|
188 |
|
189 The NewShared PoolType also initializes this bookkeeping data to its default |
|
190 state. Thus, while the bookkeeping data is shared, only one of the sharing |
|
191 instances should use a NewShared type. All other instances should use the |
|
192 Shared pool type. |
|
193 |
|
194 The malloc pool bookkeeping data contains absolute pointers. As such, if |
|
195 multiple processes intend to allocate into the malloc pool, is is essential |
|
196 that they map the memory region to the same virtual address location. |
|
197 \value Shared |
|
198 The bookkeeping data is stored in the managed region, and has previously been |
|
199 initialized by another QMallocPool instance constructed using the NewShared |
|
200 pool type. |
|
201 |
|
202 The malloc pool bookkeeping data contains absolute pointers. As such, if |
|
203 multiple processes intend to allocate into the malloc pool, is is essential |
|
204 that they map the memory region to the same virtual address location. |
|
205 */ |
|
206 |
|
207 /*! |
|
208 Creates an invalid QMallocPool. |
|
209 */ |
|
210 QMallocPool::QMallocPool() |
|
211 : d(0) |
|
212 { |
|
213 } |
|
214 |
|
215 /*! |
|
216 Creates a QMallocPool on the memory region \a poolBase of length |
|
217 \a poolLength. The pool will be constructed with the passed \a type and |
|
218 \a name. The \a name is used for diagnostics purposes only. |
|
219 */ |
|
220 QMallocPool::QMallocPool(void * poolBase, unsigned int poolLength, |
|
221 PoolType type, const QString& name) |
|
222 : d(0) |
|
223 { |
|
224 if((type == NewShared || Shared == type) && |
|
225 poolLength < sizeof(struct malloc_state)) |
|
226 return; |
|
227 |
|
228 d = new QMallocPoolPrivate(poolBase, poolLength, type, name); |
|
229 } |
|
230 |
|
231 /*! |
|
232 Destroys the malloc pool. |
|
233 */ |
|
234 QMallocPool::~QMallocPool() |
|
235 { |
|
236 if(d) |
|
237 delete d; |
|
238 d = 0; |
|
239 } |
|
240 |
|
241 /*! |
|
242 Returns the allocated size of \a mem, assuming \a mem was previously returned |
|
243 by malloc(), calloc() or realloc(). |
|
244 */ |
|
245 size_t QMallocPool::size_of(void *mem) |
|
246 { |
|
247 return chunksize(mem2chunk(mem)) - sizeof(mchunkptr); |
|
248 } |
|
249 |
|
250 /*! |
|
251 Allocates memory for an array of \a nmemb elements of \a size each and returns |
|
252 a pointer to the allocated memory. The memory is set to zero. Returns 0 if |
|
253 the memory could not be allocated. |
|
254 */ |
|
255 void *QMallocPool::calloc(size_t nmemb, size_t size) |
|
256 { |
|
257 Q_ASSERT(d && "Cannot operate on a null malloc pool"); |
|
258 QMallocPtr p(d); |
|
259 return dlcalloc(nmemb, size); |
|
260 } |
|
261 |
|
262 /*! |
|
263 Allocates \a size bytes and returns a pointer to the allocated memory. The |
|
264 memory is not cleared. Returns 0 if the memory could not be allocated. |
|
265 */ |
|
266 void *QMallocPool::malloc(size_t size) |
|
267 { |
|
268 Q_ASSERT(d && "Cannot operate on a null malloc pool"); |
|
269 QMallocPtr p(d); |
|
270 return dlmalloc(size); |
|
271 } |
|
272 |
|
273 /*! |
|
274 Frees the memory space pointed to by \a ptr, which must have been returned |
|
275 by a previous call to malloc(), calloc() or realloc(). Otherwise, or if |
|
276 \c {free(ptr)} has already been called before, undefined behavior |
|
277 occurs. If \a ptr is 0, no operation is performed. |
|
278 */ |
|
279 void QMallocPool::free(void *ptr) |
|
280 { |
|
281 Q_ASSERT(d && "Cannot operate on a null malloc pool"); |
|
282 QMallocPtr p(d); |
|
283 dlfree(ptr); |
|
284 } |
|
285 |
|
286 /*! |
|
287 Changes the size of the memory block pointed to by \a ptr to \a size bytes. |
|
288 The contents will be unchanged to the minimum of the old and new sizes; newly |
|
289 allocated memory will be uninitialized. If \a ptr is 0, the call is |
|
290 equivalent to malloc(size); if size is equal to zero, the call is equivalent |
|
291 to free(ptr). Unless ptr is 0, it must have been returned by an earlier call |
|
292 to malloc(), calloc() or realloc(). If the area pointed to was moved, a |
|
293 free(ptr) is done. |
|
294 */ |
|
295 void *QMallocPool::realloc(void *ptr, size_t size) |
|
296 { |
|
297 Q_ASSERT(d && "Cannot operate on a null malloc pool"); |
|
298 QMallocPtr p(d); |
|
299 return dlrealloc(ptr, size); |
|
300 } |
|
301 |
|
302 /*! |
|
303 Returns true if this is a valid malloc pool. Invalid malloc pools cannot be |
|
304 allocated from. |
|
305 */ |
|
306 bool QMallocPool::isValid() const |
|
307 { |
|
308 return d; |
|
309 } |
|
310 |
|
311 /*! |
|
312 Returns a MemoryStats structure containing information about the memory use |
|
313 of this pool. |
|
314 */ |
|
315 QMallocPool::MemoryStats QMallocPool::memoryStatistics() const |
|
316 { |
|
317 Q_ASSERT(d && "Cannot operate on a null malloc pool"); |
|
318 QMallocPtr p(d); |
|
319 |
|
320 struct mallinfo info = dlmallinfo(); |
|
321 |
|
322 MemoryStats rv = { d->poolLength, |
|
323 (unsigned long)info.usmblks, |
|
324 (unsigned long)info.arena, |
|
325 (unsigned long)info.uordblks, |
|
326 (unsigned long)info.keepcost }; |
|
327 return rv; |
|
328 } |
|
329 |
|
330 QTM_END_NAMESPACE |