VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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