VirtualBox

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

Last change on this file since 20606 was 20575, checked in by vboxsync, 15 years ago

IPRT: Wrote the body for tstRTMemPool and fixed two isseus in mempool-generic.cpp: 1. messed up the linked list a little bit (as always). 2. don't assert on volatile pointers without owning the lock as someone else might change them while you're testing their validity and reading them multiple times.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1/* $Id: mempool-generic.cpp 20575 2009-06-15 01:52:07Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation Pool.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/mempool.h>
35
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/err.h>
39#include <iprt/mem.h>
40#include <iprt/spinlock.h>
41#include <iprt/string.h>
42
43#include "internal/magics.h"
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/** Pointer to a memory pool instance. */
50typedef struct RTMEMPOOLINT *PRTMEMPOOLINT;
51/** Pointer to a memory pool entry. */
52typedef struct RTMEMPOOLENTRY *PRTMEMPOOLENTRY;
53
54/**
55 * Memory pool entry.
56 */
57typedef struct RTMEMPOOLENTRY
58{
59 /** Pointer to the pool */
60 PRTMEMPOOLINT pMemPool;
61 /** Pointer to the next entry. */
62 PRTMEMPOOLENTRY volatile pNext;
63 /** Pointer to the previous entry. */
64 PRTMEMPOOLENTRY volatile pPrev;
65 /** The number of references to the pool entry. */
66 uint32_t volatile cRefs;
67} RTMEMPOOLENTRY;
68
69
70/**
71 * Memory pool instance data.
72 */
73typedef struct RTMEMPOOLINT
74{
75 /** Magic number (RTMEMPOOL_MAGIC). */
76 uint32_t u32Magic;
77 /** Spinlock protecting the pool entry list updates. */
78 RTSPINLOCK hSpinLock;
79 /** Head entry pointer. */
80 PRTMEMPOOLENTRY volatile pHead;
81 /** The number of entries in the pool (for statistical purposes). */
82 uint32_t volatile cEntries;
83 /** User data assoicated with the pool. */
84 void *pvUser;
85 /** The pool name. (variable length) */
86 char szName[8];
87} RTMEMPOOLINT;
88
89
90/*******************************************************************************
91* Defined Constants And Macros *
92*******************************************************************************/
93/** Validates a memory pool handle, translating RTMEMPOOL_DEFAULT when found,
94 * and returns rc if not valid. */
95#define RTMEMPOOL_VALID_RETURN_RC(pMemPool, rc) \
96 do { \
97 if (pMemPool == RTMEMPOOL_DEFAULT) \
98 pMemPool = &g_rtMemPoolDefault; \
99 else \
100 { \
101 AssertPtrReturn((pMemPool), (rc)); \
102 AssertReturn((pMemPool)->u32Magic == RTMEMPOOL_MAGIC, (rc)); \
103 } \
104 } while (0)
105
106/** Validates a memory pool entry and returns rc if not valid. */
107#define RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, rc) \
108 do { \
109 AssertPtrReturn(pEntry, (rc)); \
110 AssertPtrNullReturn((pEntry)->pMemPool, (rc)); \
111 Assert((pEntry)->cRefs < UINT32_MAX / 2); \
112 AssertReturn((pEntry)->pMemPool->u32Magic == RTMEMPOOL_MAGIC, (rc)); \
113 } while (0)
114
115
116/*******************************************************************************
117* Global Variables *
118*******************************************************************************/
119/** The */
120static RTMEMPOOLINT g_rtMemPoolDefault =
121{
122 /* .u32Magic = */ RTMEMPOOL_MAGIC,
123 /* .hSpinLock = */ NIL_RTSPINLOCK,
124 /* .pHead = */ NULL,
125 /* .cEntries = */ 0,
126 /* .pvUser = */ NULL,
127 /* .szName = */ "default"
128};
129
130
131
132RTDECL(int) RTMemPoolCreate(PRTMEMPOOL phMemPool, const char *pszName)
133{
134 AssertPtr(phMemPool);
135 AssertPtr(pszName);
136 Assert(*pszName);
137
138 size_t cchName = strlen(pszName);
139 PRTMEMPOOLINT pMemPool = (PRTMEMPOOLINT)RTMemAlloc(RT_OFFSETOF(RTMEMPOOLINT, szName[cchName + 1]));
140 if (!pMemPool)
141 return VERR_NO_MEMORY;
142 int rc = RTSpinlockCreate(&pMemPool->hSpinLock);
143 if (RT_SUCCESS(rc))
144 {
145 pMemPool->u32Magic = RTMEMPOOL_MAGIC;
146 pMemPool->pHead = NULL;
147 pMemPool->cEntries = 0;
148 pMemPool->pvUser = NULL;
149 memcpy(pMemPool->szName, pszName, cchName);
150 *phMemPool = pMemPool;
151 return VINF_SUCCESS;
152 }
153 RTMemFree(pMemPool);
154 return rc;
155}
156
157
158RTDECL(int) RTMemPoolDestroy(RTMEMPOOL hMemPool)
159{
160 if (hMemPool == NIL_RTMEMPOOL)
161 return VINF_SUCCESS;
162 PRTMEMPOOLINT pMemPool = hMemPool;
163 RTMEMPOOL_VALID_RETURN_RC(pMemPool, VERR_INVALID_HANDLE);
164 if (pMemPool == &g_rtMemPoolDefault)
165 return VINF_SUCCESS;
166
167 /*
168 * Invalidate the handle and free all associated resources.
169 */
170 ASMAtomicWriteU32(&pMemPool->u32Magic, RTMEMPOOL_MAGIC_DEAD);
171
172 int rc = RTSpinlockDestroy(pMemPool->hSpinLock); AssertRC(rc);
173 pMemPool->hSpinLock = NIL_RTSPINLOCK;
174
175 PRTMEMPOOLENTRY pEntry = pMemPool->pHead;
176 pMemPool->pHead = NULL;
177 while (pEntry)
178 {
179 PRTMEMPOOLENTRY pFree = pEntry;
180 Assert(pFree->cRefs > 0 && pFree->cRefs < UINT32_MAX / 2);
181 pEntry = pEntry->pNext;
182
183 pFree->pMemPool = NULL;
184 pFree->pNext = NULL;
185 pFree->pPrev = NULL;
186 pFree->cRefs = UINT32_MAX - 3;
187 RTMemFree(pFree);
188 }
189
190 RTMemFree(pMemPool);
191
192 return VINF_SUCCESS;
193}
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}
260
261
262RTDECL(void *) RTMemPoolAllocZ(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW
263{
264 PRTMEMPOOLINT pMemPool = hMemPool;
265 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
266
267 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAllocZ(cb + sizeof(*pEntry));
268 if (!pEntry)
269 return NULL;
270 rtMemPoolInitAndLink(pMemPool, pEntry);
271
272 return pEntry + 1;
273}
274
275
276RTDECL(void *) RTMemPoolDup(RTMEMPOOL hMemPool, const void *pvSrc, size_t cb) RT_NO_THROW
277{
278 PRTMEMPOOLINT pMemPool = hMemPool;
279 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
280
281 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cb + sizeof(*pEntry));
282 if (!pEntry)
283 return NULL;
284 memcpy(pEntry + 1, pvSrc, cb);
285 rtMemPoolInitAndLink(pMemPool, pEntry);
286
287 return pEntry + 1;
288}
289
290
291RTDECL(void *) RTMemPoolDupEx(RTMEMPOOL hMemPool, const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW
292{
293 PRTMEMPOOLINT pMemPool = hMemPool;
294 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
295
296 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cbSrc + cbExtra + sizeof(*pEntry));
297 if (!pEntry)
298 return NULL;
299 memcpy(pEntry + 1, pvSrc, cbSrc);
300 memset((uint8_t *)(pEntry + 1) + cbSrc, '\0', cbExtra);
301 rtMemPoolInitAndLink(pMemPool, pEntry);
302
303 return pEntry + 1;
304}
305
306
307
308RTDECL(void *) RTMemPoolRealloc(RTMEMPOOL hMemPool, void *pvOld, size_t cbNew) RT_NO_THROW
309{
310 /*
311 * Fend off the odd cases.
312 */
313 if (!cbNew)
314 {
315 RTMemPoolRelease(hMemPool, pvOld);
316 return NULL;
317 }
318
319 if (!pvOld)
320 return RTMemPoolAlloc(hMemPool, cbNew);
321
322 /*
323 * Real realloc.
324 */
325 PRTMEMPOOLINT pNewMemPool = hMemPool;
326 RTMEMPOOL_VALID_RETURN_RC(pNewMemPool, NULL);
327
328 PRTMEMPOOLENTRY pOldEntry = (PRTMEMPOOLENTRY)pvOld - 1;
329 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pOldEntry, NULL);
330 PRTMEMPOOLINT pOldMemPool = pOldEntry->pMemPool;
331 AssertReturn(pOldEntry->cRefs == 1, NULL);
332
333 /*
334 * Unlink it from the current pool and try reallocate it.
335 */
336 rtMemPoolUnlink(pOldEntry);
337
338 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemRealloc(pOldEntry, cbNew + sizeof(*pEntry));
339 if (!pEntry)
340 {
341 rtMemPoolInitAndLink(pOldMemPool, pOldEntry);
342 return NULL;
343 }
344 rtMemPoolInitAndLink(pNewMemPool, pEntry);
345
346 return pEntry + 1;
347}
348
349
350RTDECL(void) RTMemPoolFree(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW
351{
352 RTMemPoolRelease(hMemPool, pv);
353}
354
355
356RTDECL(uint32_t) RTMemPoolRetain(void *pv) RT_NO_THROW
357{
358 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
359 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
360
361 uint32_t cRefs = ASMAtomicIncU32(&pEntry->cRefs);
362 Assert(cRefs < UINT32_MAX / 2);
363
364 return cRefs;
365}
366
367
368RTDECL(uint32_t) RTMemPoolRelease(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW
369{
370 if (!pv)
371 return 0;
372
373 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
374 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
375 Assert( hMemPool == NIL_RTMEMPOOL
376 || hMemPool == pEntry->pMemPool
377 || (hMemPool == RTMEMPOOL_DEFAULT && pEntry->pMemPool == &g_rtMemPoolDefault));
378 AssertReturn(pEntry->cRefs > 0, UINT32_MAX);
379
380 uint32_t cRefs = ASMAtomicDecU32(&pEntry->cRefs);
381 Assert(cRefs < UINT32_MAX / 2);
382 if (!cRefs)
383 {
384 rtMemPoolUnlink(pEntry);
385 pEntry->cRefs = UINT32_MAX - 2;
386 RTMemFree(pEntry);
387 }
388
389 return cRefs;
390}
391
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