VirtualBox

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

© 2023 Oracle
ContactPrivacy policyTerms of Use