VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/handletablesimple.cpp@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: handletablesimple.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Handle Tables.
4 */
5
6/*
7 * Copyright (C) 2008-2022 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/handletable.h>
32#include "internal/iprt.h"
33
34#include <iprt/mem.h>
35#include <iprt/spinlock.h>
36#include <iprt/err.h>
37#include <iprt/assert.h>
38#include <iprt/param.h>
39#include <iprt/string.h>
40#include <iprt/asm.h>
41#include "internal/magics.h"
42#include "handletable.h"
43
44
45RTDECL(int) RTHandleTableAlloc(RTHANDLETABLE hHandleTable, void *pvObj, uint32_t *ph)
46{
47 /* validate the input */
48 PRTHANDLETABLEINT pThis = (PRTHANDLETABLEINT)hHandleTable;
49 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
50 AssertReturn(pThis->u32Magic == RTHANDLETABLE_MAGIC, VERR_INVALID_HANDLE);
51 AssertReturn(!(pThis->fFlags & RTHANDLETABLE_FLAGS_CONTEXT), VERR_INVALID_FUNCTION);
52 AssertReturn(!RTHT_IS_FREE(pvObj), VERR_INVALID_PARAMETER);
53 AssertPtrReturn(ph, VERR_INVALID_POINTER);
54 *ph = pThis->uBase - 1;
55
56 /*
57 * Allocation loop.
58 */
59 rtHandleTableLock(pThis);
60
61 int rc;
62 do
63 {
64 /*
65 * Try grab a free entry from the head of the free list.
66 */
67 uint32_t i = pThis->iFreeHead;
68 if (i != NIL_RTHT_INDEX)
69 {
70 PRTHTENTRYFREE pFree = (PRTHTENTRYFREE)rtHandleTableLookupSimpleIdx(pThis, i);
71 Assert(pFree);
72 if (i == pThis->iFreeTail)
73 pThis->iFreeTail = pThis->iFreeHead = NIL_RTHT_INDEX;
74 else
75 pThis->iFreeHead = RTHT_GET_FREE_IDX(pFree);
76 pThis->cCurAllocated++;
77 Assert(pThis->cCurAllocated <= pThis->cCur);
78
79 /*
80 * Setup the entry and return.
81 */
82 PRTHTENTRY pEntry = (PRTHTENTRY)pFree;
83 pEntry->pvObj = pvObj;
84 *ph = i + pThis->uBase;
85 rc = VINF_SUCCESS;
86 }
87 /*
88 * Must expand the handle table, unless it's full.
89 */
90 else if (pThis->cCur >= pThis->cMax)
91 {
92 rc = VERR_NO_MORE_HANDLES;
93 Assert(pThis->cCur == pThis->cCurAllocated);
94 }
95 else
96 {
97 /*
98 * Do we have to expand the 1st level table too?
99 */
100 uint32_t const iLevel1 = pThis->cCur / RTHT_LEVEL2_ENTRIES;
101 uint32_t cLevel1 = iLevel1 >= pThis->cLevel1
102 ? pThis->cLevel1 + PAGE_SIZE / sizeof(void *)
103 : 0;
104 if (cLevel1 > pThis->cMax / RTHT_LEVEL2_ENTRIES)
105 cLevel1 = pThis->cMax / RTHT_LEVEL2_ENTRIES;
106 Assert(!cLevel1 || pThis->cMax / RTHT_LEVEL2_ENTRIES >= RTHT_LEVEL1_DYN_ALLOC_THRESHOLD);
107
108 /* leave the lock (never do fancy stuff from behind a spinlock). */
109 rtHandleTableUnlock(pThis);
110
111 /*
112 * Do the allocation(s).
113 */
114 rc = VERR_TRY_AGAIN;
115 void **papvLevel1 = NULL;
116 if (cLevel1)
117 {
118 papvLevel1 = (void **)RTMemAlloc(sizeof(void *) * cLevel1);
119 if (!papvLevel1)
120 return VERR_NO_MEMORY;
121 }
122
123 PRTHTENTRY paTable = (PRTHTENTRY)RTMemAlloc(sizeof(*paTable) * RTHT_LEVEL2_ENTRIES);
124 if (!paTable)
125 {
126 RTMemFree(papvLevel1);
127 return VERR_NO_MEMORY;
128 }
129
130 /* re-enter the lock. */
131 rtHandleTableLock(pThis);
132
133 /*
134 * Insert the new bits, but be a bit careful as someone might have
135 * raced us expanding the table.
136 */
137 /* deal with the 1st level lookup expansion first */
138 if (cLevel1)
139 {
140 Assert(papvLevel1);
141 if (cLevel1 > pThis->cLevel1)
142 {
143 /* Replace the 1st level table. */
144 memcpy(papvLevel1, pThis->papvLevel1, sizeof(void *) * pThis->cLevel1);
145 memset(&papvLevel1[pThis->cLevel1], 0, sizeof(void *) * (cLevel1 - pThis->cLevel1));
146 pThis->cLevel1 = cLevel1;
147 void **papvTmp = pThis->papvLevel1;
148 pThis->papvLevel1 = papvLevel1;
149 papvLevel1 = papvTmp;
150 }
151
152 /* free the obsolete one (outside the lock of course) */
153 rtHandleTableUnlock(pThis);
154 RTMemFree(papvLevel1);
155 rtHandleTableLock(pThis);
156 }
157
158 /* insert the table we allocated. */
159 uint32_t iLevel1New = pThis->cCur / RTHT_LEVEL2_ENTRIES;
160 if ( iLevel1New < pThis->cLevel1
161 && pThis->cCur < pThis->cMax)
162 {
163 pThis->papvLevel1[iLevel1New] = paTable;
164
165 /* link all entries into a free list. */
166 Assert(!(pThis->cCur % RTHT_LEVEL2_ENTRIES));
167 for (i = 0; i < RTHT_LEVEL2_ENTRIES - 1; i++)
168 RTHT_SET_FREE_IDX((PRTHTENTRYFREE)&paTable[i], i + 1 + pThis->cCur);
169 RTHT_SET_FREE_IDX((PRTHTENTRYFREE)&paTable[RTHT_LEVEL2_ENTRIES - 1], NIL_RTHT_INDEX);
170
171 /* join the free list with the other. */
172 if (pThis->iFreeTail == NIL_RTHT_INDEX)
173 pThis->iFreeHead = pThis->cCur;
174 else
175 {
176 PRTHTENTRYFREE pPrev = (PRTHTENTRYFREE)rtHandleTableLookupSimpleIdx(pThis, pThis->iFreeTail);
177 Assert(pPrev);
178 RTHT_SET_FREE_IDX(pPrev, pThis->cCur);
179 }
180 pThis->iFreeTail = pThis->cCur + RTHT_LEVEL2_ENTRIES - 1;
181
182 pThis->cCur += RTHT_LEVEL2_ENTRIES;
183 }
184 else
185 {
186 /* free the table (raced someone, and we lost). */
187 rtHandleTableUnlock(pThis);
188 RTMemFree(paTable);
189 rtHandleTableLock(pThis);
190 }
191
192 rc = VERR_TRY_AGAIN;
193 }
194 } while (rc == VERR_TRY_AGAIN);
195
196 rtHandleTableUnlock(pThis);
197
198 return rc;
199}
200RT_EXPORT_SYMBOL(RTHandleTableAlloc);
201
202
203RTDECL(void *) RTHandleTableLookup(RTHANDLETABLE hHandleTable, uint32_t h)
204{
205 /* validate the input */
206 PRTHANDLETABLEINT pThis = (PRTHANDLETABLEINT)hHandleTable;
207 AssertPtrReturn(pThis, NULL);
208 AssertReturn(pThis->u32Magic == RTHANDLETABLE_MAGIC, NULL);
209 AssertReturn(!(pThis->fFlags & RTHANDLETABLE_FLAGS_CONTEXT), NULL);
210
211 void *pvObj = NULL;
212
213 /* acquire the lock */
214 rtHandleTableLock(pThis);
215
216 /*
217 * Perform the lookup and retaining.
218 */
219 PRTHTENTRY pEntry = rtHandleTableLookupSimple(pThis, h);
220 if (pEntry)
221 {
222 pvObj = pEntry->pvObj;
223 if (!RTHT_IS_FREE(pvObj))
224 {
225 if (pThis->pfnRetain)
226 {
227 int rc = pThis->pfnRetain(hHandleTable, pEntry->pvObj, NULL, pThis->pvRetainUser);
228 if (RT_FAILURE(rc))
229 pvObj = NULL;
230 }
231 }
232 else
233 pvObj = NULL;
234 }
235
236 /* release the lock */
237 rtHandleTableUnlock(pThis);
238 return pvObj;
239}
240RT_EXPORT_SYMBOL(RTHandleTableLookup);
241
242
243RTDECL(void *) RTHandleTableFree(RTHANDLETABLE hHandleTable, uint32_t h)
244{
245 /* validate the input */
246 PRTHANDLETABLEINT pThis = (PRTHANDLETABLEINT)hHandleTable;
247 AssertPtrReturn(pThis, NULL);
248 AssertReturn(pThis->u32Magic == RTHANDLETABLE_MAGIC, NULL);
249 AssertReturn(!(pThis->fFlags & RTHANDLETABLE_FLAGS_CONTEXT), NULL);
250
251 void *pvObj = NULL;
252
253 /* acquire the lock */
254 rtHandleTableLock(pThis);
255
256 /*
257 * Perform the lookup and retaining.
258 */
259 PRTHTENTRY pEntry = rtHandleTableLookupSimple(pThis, h);
260 if (pEntry)
261 {
262 pvObj = pEntry->pvObj;
263 if (!RTHT_IS_FREE(pvObj))
264 {
265 if (pThis->pfnRetain)
266 {
267 int rc = pThis->pfnRetain(hHandleTable, pEntry->pvObj, NULL, pThis->pvRetainUser);
268 if (RT_FAILURE(rc))
269 pvObj = NULL;
270 }
271
272 /*
273 * Link it into the free list.
274 */
275 if (pvObj)
276 {
277 PRTHTENTRYFREE pFree = (PRTHTENTRYFREE)pEntry;
278 RTHT_SET_FREE_IDX(pFree, NIL_RTHT_INDEX);
279
280 uint32_t const i = h - pThis->uBase;
281 if (pThis->iFreeTail == NIL_RTHT_INDEX)
282 pThis->iFreeHead = pThis->iFreeTail = i;
283 else
284 {
285 PRTHTENTRYFREE pPrev = (PRTHTENTRYFREE)rtHandleTableLookupSimpleIdx(pThis, pThis->iFreeTail);
286 Assert(pPrev);
287 RTHT_SET_FREE_IDX(pPrev, i);
288 pThis->iFreeTail = i;
289 }
290
291 Assert(pThis->cCurAllocated > 0);
292 pThis->cCurAllocated--;
293 }
294 }
295 else
296 pvObj = NULL;
297 }
298
299 /* release the lock */
300 rtHandleTableUnlock(pThis);
301 return pvObj;
302}
303RT_EXPORT_SYMBOL(RTHandleTableFree);
304
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