VirtualBox

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

Last change on this file since 20364 was 19865, checked in by vboxsync, 16 years ago

IPRT: Made handletable.cpp and handletablectx.cpp build cleanly as C.

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