VirtualBox

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

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