VirtualBox

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

Last change on this file since 86669 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/* $Id: mempool-generic.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation Pool.
4 */
5
6/*
7 * Copyright (C) 2009-2020 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/errcore.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_UOFFSETOF_DYN(RTMEMPOOLINT, szName[cchName + 1]));
138 if (!pMemPool)
139 return VERR_NO_MEMORY;
140 int rc = RTSpinlockCreate(&pMemPool->hSpinLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "RTMemPoolCreate");
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 RTSpinlockAcquire(pMemPool->hSpinLock);
206
207 PRTMEMPOOLENTRY pHead = pMemPool->pHead;
208 pEntry->pNext = pHead;
209 if (pHead)
210 pHead->pPrev = pEntry;
211 pMemPool->pHead = pEntry;
212
213 RTSpinlockRelease(pMemPool->hSpinLock);
214 }
215
216 ASMAtomicIncU32(&pMemPool->cEntries);
217}
218
219
220DECLINLINE(void) rtMemPoolUnlink(PRTMEMPOOLENTRY pEntry)
221{
222 PRTMEMPOOLINT pMemPool = pEntry->pMemPool;
223 if (pMemPool->hSpinLock != NIL_RTSPINLOCK)
224 {
225 RTSpinlockAcquire(pMemPool->hSpinLock);
226
227 PRTMEMPOOLENTRY pNext = pEntry->pNext;
228 PRTMEMPOOLENTRY pPrev = pEntry->pPrev;
229 if (pNext)
230 pNext->pPrev = pPrev;
231 if (pPrev)
232 pPrev->pNext = pNext;
233 else
234 pMemPool->pHead = pNext;
235 pEntry->pMemPool = NULL;
236
237 RTSpinlockRelease(pMemPool->hSpinLock);
238 }
239 else
240 pEntry->pMemPool = NULL;
241
242 ASMAtomicDecU32(&pMemPool->cEntries);
243}
244
245
246RTDECL(void *) RTMemPoolAlloc(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW_DEF
247{
248 PRTMEMPOOLINT pMemPool = hMemPool;
249 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
250
251 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cb + sizeof(*pEntry));
252 if (!pEntry)
253 return NULL;
254 rtMemPoolInitAndLink(pMemPool, pEntry);
255
256 return pEntry + 1;
257}
258RT_EXPORT_SYMBOL(RTMemPoolAlloc);
259
260
261RTDECL(void *) RTMemPoolAllocZ(RTMEMPOOL hMemPool, size_t cb) RT_NO_THROW_DEF
262{
263 PRTMEMPOOLINT pMemPool = hMemPool;
264 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
265
266 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAllocZ(cb + sizeof(*pEntry));
267 if (!pEntry)
268 return NULL;
269 rtMemPoolInitAndLink(pMemPool, pEntry);
270
271 return pEntry + 1;
272}
273RT_EXPORT_SYMBOL(RTMemPoolAllocZ);
274
275
276RTDECL(void *) RTMemPoolDup(RTMEMPOOL hMemPool, const void *pvSrc, size_t cb) RT_NO_THROW_DEF
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}
289RT_EXPORT_SYMBOL(RTMemPoolDup);
290
291
292RTDECL(void *) RTMemPoolDupEx(RTMEMPOOL hMemPool, const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW_DEF
293{
294 PRTMEMPOOLINT pMemPool = hMemPool;
295 RTMEMPOOL_VALID_RETURN_RC(pMemPool, NULL);
296
297 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemAlloc(cbSrc + cbExtra + sizeof(*pEntry));
298 if (!pEntry)
299 return NULL;
300 memcpy(pEntry + 1, pvSrc, cbSrc);
301 memset((uint8_t *)(pEntry + 1) + cbSrc, '\0', cbExtra);
302 rtMemPoolInitAndLink(pMemPool, pEntry);
303
304 return pEntry + 1;
305}
306RT_EXPORT_SYMBOL(RTMemPoolDupEx);
307
308
309
310RTDECL(void *) RTMemPoolRealloc(RTMEMPOOL hMemPool, void *pvOld, size_t cbNew) RT_NO_THROW_DEF
311{
312 /*
313 * Fend off the odd cases.
314 */
315 if (!cbNew)
316 {
317 RTMemPoolRelease(hMemPool, pvOld);
318 return NULL;
319 }
320
321 if (!pvOld)
322 return RTMemPoolAlloc(hMemPool, cbNew);
323
324 /*
325 * Real realloc.
326 */
327 PRTMEMPOOLINT pNewMemPool = hMemPool;
328 RTMEMPOOL_VALID_RETURN_RC(pNewMemPool, NULL);
329
330 PRTMEMPOOLENTRY pOldEntry = (PRTMEMPOOLENTRY)pvOld - 1;
331 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pOldEntry, NULL);
332 PRTMEMPOOLINT pOldMemPool = pOldEntry->pMemPool;
333 AssertReturn(pOldEntry->cRefs == 1, NULL);
334
335 /*
336 * Unlink it from the current pool and try reallocate it.
337 */
338 rtMemPoolUnlink(pOldEntry);
339
340 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)RTMemRealloc(pOldEntry, cbNew + sizeof(*pEntry));
341 if (!pEntry)
342 {
343 rtMemPoolInitAndLink(pOldMemPool, pOldEntry);
344 return NULL;
345 }
346 rtMemPoolInitAndLink(pNewMemPool, pEntry);
347
348 return pEntry + 1;
349}
350RT_EXPORT_SYMBOL(RTMemPoolRealloc);
351
352
353RTDECL(void) RTMemPoolFree(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW_DEF
354{
355 RTMemPoolRelease(hMemPool, pv);
356}
357RT_EXPORT_SYMBOL(RTMemPoolFree);
358
359
360RTDECL(uint32_t) RTMemPoolRetain(void *pv) RT_NO_THROW_DEF
361{
362 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
363 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
364
365 uint32_t cRefs = ASMAtomicIncU32(&pEntry->cRefs);
366 Assert(cRefs < UINT32_MAX / 2);
367
368 return cRefs;
369}
370RT_EXPORT_SYMBOL(RTMemPoolRetain);
371
372
373RTDECL(uint32_t) RTMemPoolRelease(RTMEMPOOL hMemPool, void *pv) RT_NO_THROW_DEF
374{
375 if (!pv)
376 return 0;
377
378 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
379 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
380 Assert( hMemPool == NIL_RTMEMPOOL
381 || hMemPool == pEntry->pMemPool
382 || (hMemPool == RTMEMPOOL_DEFAULT && pEntry->pMemPool == &g_rtMemPoolDefault)); RT_NOREF_PV(hMemPool);
383 AssertReturn(pEntry->cRefs > 0, UINT32_MAX);
384
385 uint32_t cRefs = ASMAtomicDecU32(&pEntry->cRefs);
386 Assert(cRefs < UINT32_MAX / 2);
387 if (!cRefs)
388 {
389 rtMemPoolUnlink(pEntry);
390 pEntry->cRefs = UINT32_MAX - 2;
391 RTMemFree(pEntry);
392 }
393
394 return cRefs;
395}
396RT_EXPORT_SYMBOL(RTMemPoolRelease);
397
398
399RTDECL(uint32_t) RTMemPoolRefCount(void *pv) RT_NO_THROW_DEF
400{
401 PRTMEMPOOLENTRY pEntry = (PRTMEMPOOLENTRY)pv - 1;
402 RTMEMPOOL_VALID_ENTRY_RETURN_RC(pEntry, UINT32_MAX);
403
404 uint32_t cRefs = ASMAtomicReadU32(&pEntry->cRefs);
405 Assert(cRefs < UINT32_MAX / 2);
406
407 return cRefs;
408}
409RT_EXPORT_SYMBOL(RTMemPoolRefCount);
410
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