VirtualBox

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

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

VMM,SUPDrv,IPRT: Always initialize RTSPINLOCKTMP structures.

  • 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 24181 2009-10-30 10:51:56Z 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 uint32_t i;
179
180 pThis->papvLevel1[iLevel1New] = paTable;
181
182 /* link all entries into a free list. */
183 Assert(!(pThis->cCur % RTHT_LEVEL2_ENTRIES));
184 for (i = 0; i < RTHT_LEVEL2_ENTRIES - 1; i++)
185 {
186 RTHT_SET_FREE_IDX((PRTHTENTRYFREE)&paTable[i], i + 1 + pThis->cCur);
187 paTable[i].pvCtx = (void *)~(uintptr_t)7;
188 }
189 RTHT_SET_FREE_IDX((PRTHTENTRYFREE)&paTable[RTHT_LEVEL2_ENTRIES - 1], NIL_RTHT_INDEX);
190 paTable[RTHT_LEVEL2_ENTRIES - 1].pvCtx = (void *)~(uintptr_t)7;
191
192 /* join the free list with the other. */
193 if (pThis->iFreeTail == NIL_RTHT_INDEX)
194 pThis->iFreeHead = pThis->cCur;
195 else
196 {
197 PRTHTENTRYFREE pPrev = (PRTHTENTRYFREE)rtHandleTableLookupWithCtxIdx(pThis, pThis->iFreeTail);
198 Assert(pPrev);
199 RTHT_SET_FREE_IDX(pPrev, pThis->cCur);
200 }
201 pThis->iFreeTail = pThis->cCur + RTHT_LEVEL2_ENTRIES - 1;
202
203 pThis->cCur += RTHT_LEVEL2_ENTRIES;
204 }
205 else
206 {
207 /* free the table (raced someone, and we lost). */
208 rtHandleTableUnlock(pThis, &Tmp);
209 RTMemFree(paTable);
210 rtHandleTableLock(pThis, &Tmp);
211 }
212
213 rc = VERR_TRY_AGAIN;
214 }
215 } while (rc == VERR_TRY_AGAIN);
216
217 rtHandleTableUnlock(pThis, &Tmp);
218
219 return rc;
220}
221RT_EXPORT_SYMBOL(RTHandleTableAllocWithCtx);
222
223
224RTDECL(void *) RTHandleTableLookupWithCtx(RTHANDLETABLE hHandleTable, uint32_t h, void *pvCtx)
225{
226 void *pvObj = NULL;
227 PRTHTENTRYCTX pEntry;
228 PRTHANDLETABLEINT pThis;
229 RTSPINLOCKTMP Tmp /*= no init */;
230
231 /* validate the input */
232 pThis = (PRTHANDLETABLEINT)hHandleTable;
233 AssertPtrReturn(pThis, NULL);
234 AssertReturn(pThis->u32Magic == RTHANDLETABLE_MAGIC, NULL);
235 AssertReturn(pThis->fFlags & RTHANDLETABLE_FLAGS_CONTEXT, NULL);
236
237
238 /* acquire the lock */
239 rtHandleTableLock(pThis, &Tmp);
240
241 /*
242 * Perform the lookup and retaining.
243 */
244 pEntry = rtHandleTableLookupWithCtx(pThis, h);
245 if (pEntry && pEntry->pvCtx == pvCtx)
246 {
247 pvObj = pEntry->pvObj;
248 if (!RTHT_IS_FREE(pvObj))
249 {
250 if (pThis->pfnRetain)
251 {
252 int rc = pThis->pfnRetain(hHandleTable, pEntry->pvObj, pvCtx, pThis->pvRetainUser);
253 if (RT_FAILURE(rc))
254 pvObj = NULL;
255 }
256 }
257 else
258 pvObj = NULL;
259 }
260
261 /* release the lock */
262 rtHandleTableUnlock(pThis, &Tmp);
263 return pvObj;
264}
265RT_EXPORT_SYMBOL(RTHandleTableLookupWithCtx);
266
267
268RTDECL(void *) RTHandleTableFreeWithCtx(RTHANDLETABLE hHandleTable, uint32_t h, void *pvCtx)
269{
270 void *pvObj = NULL;
271 PRTHTENTRYCTX pEntry;
272 PRTHANDLETABLEINT pThis;
273 RTSPINLOCKTMP Tmp /*= no init */;
274
275 /* validate the input */
276 pThis = (PRTHANDLETABLEINT)hHandleTable;
277 AssertPtrReturn(pThis, NULL);
278 AssertReturn(pThis->u32Magic == RTHANDLETABLE_MAGIC, NULL);
279 AssertReturn(pThis->fFlags & RTHANDLETABLE_FLAGS_CONTEXT, NULL);
280
281
282 /* acquire the lock */
283 rtHandleTableLock(pThis, &Tmp);
284
285 /*
286 * Perform the lookup and retaining.
287 */
288 pEntry = rtHandleTableLookupWithCtx(pThis, h);
289 if (pEntry && pEntry->pvCtx == pvCtx)
290 {
291 pvObj = pEntry->pvObj;
292 if (!RTHT_IS_FREE(pvObj))
293 {
294 if (pThis->pfnRetain)
295 {
296 int rc = pThis->pfnRetain(hHandleTable, pEntry->pvObj, pvCtx, pThis->pvRetainUser);
297 if (RT_FAILURE(rc))
298 pvObj = NULL;
299 }
300
301 /*
302 * Link it into the free list.
303 */
304 if (pvObj)
305 {
306 PRTHTENTRYFREE pFree;
307 uint32_t i;
308
309 pEntry->pvCtx = (void *)~(uintptr_t)7;
310
311 pFree = (PRTHTENTRYFREE)pEntry;
312 RTHT_SET_FREE_IDX(pFree, NIL_RTHT_INDEX);
313
314 i = h - pThis->uBase;
315 if (pThis->iFreeTail == NIL_RTHT_INDEX)
316 pThis->iFreeHead = pThis->iFreeTail = i;
317 else
318 {
319 PRTHTENTRYFREE pPrev = (PRTHTENTRYFREE)rtHandleTableLookupWithCtxIdx(pThis, pThis->iFreeTail);
320 Assert(pPrev);
321 RTHT_SET_FREE_IDX(pPrev, i);
322 pThis->iFreeTail = i;
323 }
324
325 Assert(pThis->cCurAllocated > 0);
326 pThis->cCurAllocated--;
327 }
328 }
329 else
330 pvObj = NULL;
331 }
332
333 /* release the lock */
334 rtHandleTableUnlock(pThis, &Tmp);
335 return pvObj;
336}
337RT_EXPORT_SYMBOL(RTHandleTableFreeWithCtx);
338
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