VirtualBox

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

Last change on this file since 96763 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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