VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/cache.cpp@ 16802

Last change on this file since 16802 was 10848, checked in by vboxsync, 16 years ago

Export to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.3 KB
Line 
1/* $Id: cache.cpp 10848 2008-07-24 09:11:00Z vboxsync $ */
2/** @file
3 * IPRT - Object cache
4 */
5
6/*
7 * Copyright (C) 2006-2007 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
36#include <iprt/cdefs.h>
37#include <iprt/types.h>
38#include <iprt/err.h>
39#include <iprt/spinlock.h>
40#include <iprt/mem.h>
41#include <iprt/cache.h>
42#include <iprt/asm.h>
43
44#include "internal/magics.h"
45
46/**
47 * Create a cache for objects.
48 *
49 * @returns iprt status code.
50 * @param ppObjCache Where to store the pointer to the created cache.
51 * @param cElements Number of elements the cache can hold.
52 * 0 if unlimited size.
53 * @param cbElement Size of one element in bytes
54 * @param fProt Protection flags for protecting cache against concurrent access
55 * from different threads.
56 * RTOBJCACHE_PROTECT_REQUESTER to protect the request function.
57 * RTOBJCACHE_PROTECT_INSERT to protect the insert function.
58 */
59RTDECL(int) RTCacheCreate(PRTOBJCACHE *ppCache, uint32_t cElements, size_t cbElement, uint32_t fProt)
60{
61 int rc = VINF_SUCCESS;
62 uint32_t cbCache = sizeof(RTOBJCACHE);
63
64 if ( RT_UNLIKELY(!VALID_PTR(ppCache))
65 || !cbElement
66 || (fProt & ~RTOBJCACHE_PROTECT_VALID))
67 return VERR_INVALID_PARAMETER;
68
69 if (cElements > 0)
70 cbCache += (cElements + 1) * sizeof(void *); /* One slot is always free. */
71
72 PRTOBJCACHE pCacheNew = (PRTOBJCACHE)RTMemAllocZ(cbCache);
73 if (!pCacheNew)
74 return VERR_NO_MEMORY;
75
76 pCacheNew->cbObj = cbElement;
77 pCacheNew->cElements = cElements;
78 pCacheNew->SpinlockRequest = NIL_RTSPINLOCK;
79 pCacheNew->SpinlockInsert = NIL_RTSPINLOCK;
80 if (fProt & RTOBJCACHE_PROTECT_REQUEST)
81 {
82 rc = RTSpinlockCreate(&pCacheNew->SpinlockRequest);
83 if (RT_FAILURE(rc))
84 {
85 RTMemFree(pCacheNew);
86 return rc;
87 }
88 }
89
90 if (fProt & RTOBJCACHE_PROTECT_INSERT)
91 {
92 rc = RTSpinlockCreate(&pCacheNew->SpinlockInsert);
93 if (RT_FAILURE(rc))
94 {
95 if (pCacheNew->SpinlockRequest != NIL_RTSPINLOCK)
96 RTSpinlockDestroy(pCacheNew->SpinlockRequest);
97
98 RTMemFree(pCacheNew);
99 return rc;
100 }
101 }
102
103 /* Initialize array if cache is limited. */
104 if (pCacheNew->cElements > 0)
105 {
106 pCacheNew->u.defined.cElementsInCache = 0;
107 pCacheNew->u.defined.cNextObjRead = 0;
108 pCacheNew->u.defined.cNextFreeSlotWrite = 0;
109 }
110 else
111 {
112 /* Unlimited cache - Create dummy element. */
113 PRTOBJCACHEHDR pDummy = (PRTOBJCACHEHDR)RTMemAllocZ(sizeof(RTOBJCACHEHDR) + pCacheNew->cbObj);
114 if (!pDummy)
115 {
116 /* Cleanup. */
117 if (pCacheNew->SpinlockRequest != NIL_RTSPINLOCK)
118 RTSpinlockDestroy(pCacheNew->SpinlockRequest);
119
120 if (pCacheNew->SpinlockInsert != NIL_RTSPINLOCK)
121 RTSpinlockDestroy(pCacheNew->SpinlockInsert);
122
123 RTMemFree(pCacheNew);
124 return VERR_NO_MEMORY;
125 }
126
127 pDummy->uMagic = RTMEMCACHE_MAGIC;
128 pCacheNew->u.unlimited.pFirst = pDummy;
129 pCacheNew->u.unlimited.pLast = pDummy;
130 }
131
132 if (RT_SUCCESS(rc))
133 *ppCache = pCacheNew;
134
135 return rc;
136}
137
138/**
139 * Destroy a cache freeing allocated memory.
140 *
141 * @returns iprt status code.
142 * @param pCache Pointer to the cache.
143 */
144RTDECL(int) RTCacheDestroy(PRTOBJCACHE pCache)
145{
146 if (pCache->SpinlockRequest != NIL_RTSPINLOCK)
147 RTSpinlockDestroy(pCache->SpinlockRequest);
148
149 if (pCache->SpinlockInsert != NIL_RTSPINLOCK)
150 RTSpinlockDestroy(pCache->SpinlockInsert);
151
152 /* Free all objects left in cache. */
153 if (pCache->cElements == 0)
154 {
155 volatile RTOBJCACHEHDR *pHdr = pCache->u.unlimited.pFirst;
156
157 while (pHdr)
158 {
159 volatile RTOBJCACHEHDR *pTemp = pHdr;
160
161 pHdr = pHdr->pNext;
162 RTMemFree((void *)pTemp);
163 }
164 }
165 else
166 {
167 while (pCache->u.defined.cNextObjRead != pCache->u.defined.cNextFreeSlotWrite)
168 {
169 if (pCache->u.defined.apObjCached[pCache->u.defined.cNextObjRead])
170 RTMemFree((void *)pCache->u.defined.apObjCached[pCache->u.defined.cNextObjRead]);
171 pCache->u.defined.cNextObjRead++;
172 pCache->u.defined.cNextObjRead &= pCache->cElements;
173 }
174 }
175
176 RTMemFree(pCache);
177
178 return VINF_SUCCESS;
179}
180
181/**
182 * Request an object from the cache.
183 *
184 * @returns iprt status
185 * VERR_CACHE_EMPTY if cache is not unlimited and there is no object left in cache.
186 * @param pCache Pointer to the cache to get an object from.
187 * @param ppObj Where to store the pointer to the object.
188 */
189RTDECL(int) RTCacheRequest(PRTOBJCACHE pCache, void **ppObj)
190{
191 RTSPINLOCKTMP spinlockTmp;
192
193 if (pCache->SpinlockRequest != NIL_RTSPINLOCK)
194 RTSpinlockAcquire(pCache->SpinlockRequest, &spinlockTmp);
195
196 if (pCache->cElements == 0)
197 {
198 if (pCache->u.unlimited.pFirst != pCache->u.unlimited.pLast)
199 {
200 volatile RTOBJCACHEHDR *pHdr = pCache->u.unlimited.pFirst;
201
202 pCache->u.unlimited.pFirst = pHdr->pNext;
203
204 if (pCache->SpinlockRequest != NIL_RTSPINLOCK)
205 RTSpinlockRelease(pCache->SpinlockRequest, &spinlockTmp);
206
207 pHdr->pNext = NULL;
208 *ppObj = (uint8_t *)pHdr + sizeof(RTOBJCACHEHDR);
209 }
210 else
211 {
212 /* We have to create a new cached object. - We can leave the spinlock safely here. */
213 if (pCache->SpinlockRequest != NIL_RTSPINLOCK)
214 RTSpinlockRelease(pCache->SpinlockRequest, &spinlockTmp);
215
216 PRTOBJCACHEHDR pObjNew = (PRTOBJCACHEHDR)RTMemAllocZ(sizeof(RTOBJCACHEHDR) + pCache->cbObj);
217 if (!pObjNew)
218 return VERR_NO_MEMORY;
219
220 pObjNew->uMagic = RTMEMCACHE_MAGIC;
221 *ppObj = (uint8_t *)pObjNew + sizeof(RTOBJCACHEHDR);
222 }
223 }
224 else
225 {
226 if (pCache->u.defined.cElementsInCache > 0)
227 {
228 *ppObj = (void *)pCache->u.defined.apObjCached[pCache->u.defined.cNextObjRead];
229 pCache->u.defined.cNextObjRead++;
230 pCache->u.defined.cNextObjRead &= pCache->cElements;
231 ASMAtomicDecU32((volatile uint32_t *)&pCache->u.defined.cElementsInCache);
232
233 if (pCache->SpinlockRequest != NIL_RTSPINLOCK)
234 RTSpinlockRelease(pCache->SpinlockRequest, &spinlockTmp);
235 }
236 else
237 {
238 if (pCache->SpinlockRequest != NIL_RTSPINLOCK)
239 RTSpinlockRelease(pCache->SpinlockRequest, &spinlockTmp);
240
241 return VERR_CACHE_EMPTY;
242 }
243 }
244
245 return VINF_SUCCESS;
246}
247
248/**
249 * Insert an object into the cache.
250 *
251 * @returns iprt status code.
252 * VERR_CACHE_FULL if cache is not unlimited and there is no free entry left in cache.
253 * @param pCache Pointer to the cache.
254 * @param pObj Pointer to the object to insert.
255 */
256RTDECL(int) RTCacheInsert(PRTOBJCACHE pCache, void *pObj)
257{
258 RTSPINLOCKTMP spinlockTmp;
259 int rc = VINF_SUCCESS;
260
261 if (pCache->SpinlockInsert != NIL_RTSPINLOCK)
262 RTSpinlockAcquire(pCache->SpinlockInsert, &spinlockTmp);
263
264 if (pCache->cElements == 0)
265 {
266 PRTOBJCACHEHDR pHdr = (PRTOBJCACHEHDR)((uint8_t *)pObj - sizeof(RTOBJCACHEHDR));
267
268 AssertMsg(pHdr->uMagic == RTMEMCACHE_MAGIC, ("This is not a cached object\n"));
269
270 pCache->u.unlimited.pLast->pNext = pHdr;
271 pCache->u.unlimited.pLast = pHdr;
272 }
273 else
274 {
275 if (pCache->u.defined.cElementsInCache == pCache->cElements)
276 rc = VERR_CACHE_FULL;
277 else
278 {
279 pCache->u.defined.apObjCached[pCache->u.defined.cNextFreeSlotWrite] = pObj;
280 pCache->u.defined.cNextFreeSlotWrite++;
281 pCache->u.defined.cNextFreeSlotWrite &= pCache->cElements;
282 ASMAtomicIncU32((volatile uint32_t *)&pCache->u.defined.cElementsInCache);
283 }
284 }
285
286 if (pCache->SpinlockInsert != NIL_RTSPINLOCK)
287 RTSpinlockRelease(pCache->SpinlockInsert, &spinlockTmp);
288
289 return rc;
290}
291
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