VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/handletablectx.cpp

Last change on this file was 100308, checked in by vboxsync, 11 months ago

Runtime: Replace occurence of PAGE_SIZE with RTSystemgetPageSize() in code used by linux.arm64 guest additions, bugref:10476

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

© 2023 Oracle
ContactPrivacy policyTerms of Use