VirtualBox

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

Last change on this file since 25528 was 25000, checked in by vboxsync, 15 years ago

IPRT: Fixed -Wshadow warnings, found two bugs in error paths.

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