VirtualBox

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

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