VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/mempool-generic.cpp@ 37043

Last change on this file since 37043 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: mempool-generic.cpp 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation Pool.
4 */
5
6/*
7 * Copyright (C) 2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/mempool.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/mem.h>
38#include <iprt/spinlock.h>
39#include <iprt/string.h>
40
41#include "internal/magics.h"
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47/** Pointer to a memory pool instance. */
48typedef struct RTMEMPOOLINT *PRTMEMPOOLINT;
49/** Pointer to a memory pool entry. */
50typedef struct RTMEMPOOLENTRY *PRTMEMPOOLENTRY;
51
52/**
53 * Memory pool entry.
54 */
55typedef struct RTMEMPOOLENTRY
56{
57 /** Pointer to the pool */
58 PRTMEMPOOLINT pMemPool;
59 /** Pointer to the next entry. */
60 PRTMEMPOOLENTRY volatile pNext;
61 /** Pointer to the previous entry. */
62 PRTMEMPOOLENTRY volatile pPrev;
63 /** The number of references to the pool entry. */
64 uint32_t volatile cRefs;
65} RTMEMPOOLENTRY;
66
67
68/**
69 * Memory pool instance data.
70 */
71typedef struct RTMEMPOOLINT
72{
73 /** Magic number (RTMEMPOOL_MAGIC). */
74 uint32_t u32Magic;
75 /** Spinlock protecting the pool entry list updates. */
76 RTSPINLOCK hSpinLock;
77 /** Head entry pointer. */
78 PRTMEMPOOLENTRY volatile pHead;
79 /** The number of entries in the pool (for statistical purposes). */
80 uint32_t volatile cEntries;
81 /** User data associated with the pool. */
82 void *pvUser;
83 /** The pool name. (variable length) */
84 char szName[8];
85} RTMEMPOOLINT;
86
87
88/*******************************************************************************
89* Defined Constants And Macros *
90*******************************************************************************/
91/** Validates a memory pool handle, translating RTMEMPOOL_DEFAULT when found,
92 * and returns rc if not valid. */
93#define RTMEMPOOL_VALID_RETURN_RC(pMemPool, rc) \
94 do { \
95 if (pMemPool == RTMEMPOOL_DEFAULT) \
96 pMemPool = &g_rtMemPoolDefault; \
97 else \
98 { \
99 AssertPtrReturn((pMemPool), (rc)); \
100 AssertReturn((pMemPool)->u32Magic == RTMEMPOOL_MAGIC, (rc)); \
101 } \
102 } while (0)
103
104/** Validates a memory pool entry and returns rc if not valid. */
105#define RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, rc) \
106 do { \
107 AssertPtrReturn(pEntry, (rc)); \
108 AssertPtrNullReturn((pEntry)->pMemPool, (rc)); \
109 Assert((pEntry)->cRefs < UINT32_MAX / 2); \
110 AssertReturn((pEntry)->pMemPool->u32Magic == RTMEMPOOL_MAGIC, (rc)); \
111 } while (0)
112
113
114/*******************************************************************************
115* Global Variables *
116*******************************************************************************/
117/** The */
118static RTMEMPOOLINT g_rtMemPoolDefault =
119{
120 /* .u32Magic = */ RTMEMPOOL_MAGIC,
121 /* .hSpinLock = */ NIL_RTSPINLOCK,
122 /* .pHead = */ NULL,
123 /* .cEntries = */ 0,
124 /* .pvUser = */ NULL,
125 /* .szName = */ "default"
126};
127
128
129
130RTDECL(int) RTMemPoolCreate(PRTMEMPOOL phMemPool, const char *pszName)
131{
132 AssertPtr(phMemPool);
133 AssertPtr(pszName);
134 Assert(*pszName);
135
136 size_t cchName = strlen(pszName);
137 PRTMEMPOOLINT pMemPool = (PRTMEMPOOLINT)RTMemAlloc(RT_OFFSETOF(RTMEMPOOLINT, szName[cchName + 1]));
138 if (!pMemPool)
139 return VERR_NO_MEMORY;
140 int rc = RTSpinlockCreate(&pMemPool->hSpinLock);
141 if (RT_SUCCESS(rc))
142 {
143 pMemPool->u32Magic = RTMEMPOOL_MAGIC;
144 pMemPool->pHead = NULL;
145 pMemPool->cEntries = 0;
146 pMemPool->pvUser = NULL;
147 memcpy(pMemPool->szName, pszName, cchName);
148 *phMemPool = pMemPool;
149 return VINF_SUCCESS;
150 }
151 RTMemFree(pMemPool);
152 return rc;
153}
154RT_EXPORT_SYMBOL(RTMemPoolCreate);
155
156
157RTDECL(int) RTMemPoolDestroy(RTMEMPOOL hMemPool)
158{
159 if (hMemPool == NIL_RTMEMPOOL)
160 return VINF_SUCCESS;
161 PRTMEMPOOLINT pMemPool = hMemPool;
162 RTMEMPOOL_VALID_RETURN_RC(pMemPool, VERR_INVALID_HANDLE);
163 if (pMemPool == &g_rtMemPoolDefault)
164 return VINF_SUCCESS;
165
166 /*
167 * Invalidate the handle and free all associated resources.
168 */
169 ASMAtomicWriteU32(&pMemPool->u32Magic, RTMEMPOOL_MAGIC_DEAD);
170
171 int rc = RTSpinlockDestroy(pMemPool->hSpinLock); AssertRC(rc);
172 pMemPool->hSpinLock = NIL_RTSPINLOCK;
173
174 PRTMEMPOOLENTRY pEntry = pMemPool->pHead;
175 pMemPool->pHead = NULL;
176 while (pEntry)
177 {
178 PRTMEMPOOLENTRY pFree = pEntry;
179 Assert(pFree->cRefs > 0 && pFree->cRefs < UINT32_MAX / 2);
180 pEntry = pEntry->pNext;
181
182 pFree->pMemPool = NULL;
183 pFree->pNext = NULL;
184 pFree->pPrev = NULL;
185 pFree->cRefs = UINT32_MAX - 3;
186 RTMemFree(pFree);
187 }
188
189 RTMemFree(pMemPool);
190
191 return VINF_SUCCESS;
192}
193RT_EXPORT_SYMBOL(RTMemPoolDestroy);
194
195
196DECLINLINE(void) rtMemPoolInitAndLink(PRTMEMPOOLINT pMemPool, PRTMEMPOOLENTRY pEntry)
197{
198 pEntry->pMemPool = pMemPool;
199 pEntry->pNext = NULL;
200 pEntry->pPrev = NULL;
201 pEntry->cRefs = 1;
202
203 if (pMemPool->hSpinLock != NIL_RTSPINLOCK)
204 {
205 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
206 RTSpinlockAcquire(pMemPool->hSpinLock, &Tmp);
207
208 PRTMEMPOOLENTRY pHead = pMemPool->pHead;
209 pEntry->pNext = pHead;
210 if (pHead)
211 pHead->pPrev = pEntry;
212 pMemPool->pHead = pEntry;
213
214 RTSpinlockRelease(pMemPool->hSpinLock, &Tmp);
215 }
216
217 ASMAtomicIncU32(&pMemPool->cEntries);
218}
219
220
221DECLINLINE(void) rtMemPoolUnlink(PRTMEMPOOLENTRY pEntry)
222{
223 PRTMEMPOOLINT pMemPool = pEntry->pMemPool;
224 if (pMemPool->hSpinLock != NIL_RTSPINLOCK)
225 {
226 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
227 RTSpinlockAcquire(pMemPool->hSpinLock, &Tmp);
228
229 PRTMEMPOOLENTRY pNext = pEntry->pNext;
230 PRTMEMPOOLENTRY pPrev = pEntry->pPrev;
231 if (pNext)
232 pNext->pPrev = pPrev;
233 if (pPrev)
234 pPrev->pNext = pNext;
235 else
236 pMemPool->pHead = pNext;
237 pEntry->pMemPool = NULL;
238
239 RTSpinlockRelease(pMemPool->hSpinLock, &Tmp);
240 }
241 else
242 pEntry->pMemPool = NULL;
243
244 ASMAtomicDecU32(&pMemPool->cEntries);
245}
246
247
248RTDECL(void *) RTMemPoolAlloc(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW
249{
250 PRTMEMPOOLINT pMemPool = hMemPool;
251 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
252
253 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cb + sizeof(*pEntry));
254 if (!pEntry)
255 return NULL;
256 rtMemPoolInitAndLink(pMemPool, pEntry);
257
258 return pEntry + 1;
259}
260RT_EXPORT_SYMBOL(RTMemPoolAlloc);
261
262
263RTDECL(void *) RTMemPoolAllocZ(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW
264{
265 PRTMEMPOOLINT pMemPool = hMemPool;
266 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
267
268 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAllocZ(cb + sizeof(*pEntry));
269 if (!pEntry)
270 return NULL;
271 rtMemPoolInitAndLink(pMemPool, pEntry);
272
273 return pEntry + 1;
274}
275RT_EXPORT_SYMBOL(RTMemPoolAllocZ);
276
277
278RTDECL(void *) RTMemPoolDup(RTMEMPOOL hMemPool, const void *pvSrc, size_t cb) RT_NO_THROW
279{
280 PRTMEMPOOLINT pMemPool = hMemPool;
281 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
282
283 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cb + sizeof(*pEntry));
284 if (!pEntry)
285 return NULL;
286 memcpy(pEntry + 1, pvSrc, cb);
287 rtMemPoolInitAndLink(pMemPool, pEntry);
288
289 return pEntry + 1;
290}
291RT_EXPORT_SYMBOL(RTMemPoolDup);
292
293
294RTDECL(void *) RTMemPoolDupEx(RTMEMPOOL hMemPool, const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW
295{
296 PRTMEMPOOLINT pMemPool = hMemPool;
297 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
298
299 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cbSrc + cbExtra + sizeof(*pEntry));
300 if (!pEntry)
301 return NULL;
302 memcpy(pEntry + 1, pvSrc, cbSrc);
303 memset((uint8_t *)(pEntry + 1) + cbSrc, '\0', cbExtra);
304 rtMemPoolInitAndLink(pMemPool, pEntry);
305
306 return pEntry + 1;
307}
308RT_EXPORT_SYMBOL(RTMemPoolDupEx);
309
310
311
312RTDECL(void *) RTMemPoolRealloc(RTMEMPOOL hMemPool, void *pvOld, size_t cbNew) RT_NO_THROW
313{
314 /*
315 * Fend off the odd cases.
316 */
317 if (!cbNew)
318 {
319 RTMemPoolRelease(hMemPool, pvOld);
320 return NULL;
321 }
322
323 if (!pvOld)
324 return RTMemPoolAlloc(hMemPool, cbNew);
325
326 /*
327 * Real realloc.
328 */
329 PRTMEMPOOLINT pNewMemPool = hMemPool;
330 RTMEMPOOL_VALID_RETURN_RC(pNewMemPool, NULL);
331
332 PRTMEMPOOLENTRY pOldEntry = (PRTMEMPOOLENTRY)pvOld - 1;
333 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pOldEntry, NULL);
334 PRTMEMPOOLINT pOldMemPool = pOldEntry->pMemPool;
335 AssertReturn(pOldEntry->cRefs == 1, NULL);
336
337 /*
338 * Unlink it from the current pool and try reallocate it.
339 */
340 rtMemPoolUnlink(pOldEntry);
341
342 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemRealloc(pOldEntry, cbNew + sizeof(*pEntry));
343 if (!pEntry)
344 {
345 rtMemPoolInitAndLink(pOldMemPool, pOldEntry);
346 return NULL;
347 }
348 rtMemPoolInitAndLink(pNewMemPool, pEntry);
349
350 return pEntry + 1;
351}
352RT_EXPORT_SYMBOL(RTMemPoolRealloc);
353
354
355RTDECL(void) RTMemPoolFree(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW
356{
357 RTMemPoolRelease(hMemPool, pv);
358}
359RT_EXPORT_SYMBOL(RTMemPoolFree);
360
361
362RTDECL(uint32_t) RTMemPoolRetain(void *pv) RT_NO_THROW
363{
364 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
365 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
366
367 uint32_t cRefs = ASMAtomicIncU32(&pEntry->cRefs);
368 Assert(cRefs < UINT32_MAX / 2);
369
370 return cRefs;
371}
372RT_EXPORT_SYMBOL(RTMemPoolRetain);
373
374
375RTDECL(uint32_t) RTMemPoolRelease(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW
376{
377 if (!pv)
378 return 0;
379
380 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
381 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
382 Assert( hMemPool == NIL_RTMEMPOOL
383 || hMemPool == pEntry->pMemPool
384 || (hMemPool == RTMEMPOOL_DEFAULT && pEntry->pMemPool == &g_rtMemPoolDefault));
385 AssertReturn(pEntry->cRefs > 0, UINT32_MAX);
386
387 uint32_t cRefs = ASMAtomicDecU32(&pEntry->cRefs);
388 Assert(cRefs < UINT32_MAX / 2);
389 if (!cRefs)
390 {
391 rtMemPoolUnlink(pEntry);
392 pEntry->cRefs = UINT32_MAX - 2;
393 RTMemFree(pEntry);
394 }
395
396 return cRefs;
397}
398RT_EXPORT_SYMBOL(RTMemPoolRelease);
399
400
401RTDECL(uint32_t) RTMemPoolRefCount(void *pv) RT_NO_THROW
402{
403 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
404 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
405
406 uint32_t cRefs = ASMAtomicReadU32(&pEntry->cRefs);
407 Assert(cRefs < UINT32_MAX / 2);
408
409 return cRefs;
410}
411RT_EXPORT_SYMBOL(RTMemPoolRefCount);
412
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette