VirtualBox

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

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