VirtualBox

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

Last change on this file since 23124 was 21337, checked in by vboxsync, 15 years ago

IPRT,HostDrv,AddDrv: Export public IPRT symbols for the linux kernel (pain).

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