VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/handletablesimple.cpp@ 27802

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