gwenhywfar
4.3.3
|
00001 /*************************************************************************** 00002 begin : Mon Jul 14 2008 00003 copyright : (C) 2008 by Martin Preuss 00004 email : martin@libchipcard.de 00005 00006 *************************************************************************** 00007 * * 00008 * This library is free software; you can redistribute it and/or * 00009 * modify it under the terms of the GNU Lesser General Public * 00010 * License as published by the Free Software Foundation; either * 00011 * version 2.1 of the License, or (at your option) any later version. * 00012 * * 00013 * This library is distributed in the hope that it will be useful, * 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00016 * Lesser General Public License for more details. * 00017 * * 00018 * You should have received a copy of the GNU Lesser General Public * 00019 * License along with this library; if not, write to the Free Software * 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 00021 * MA 02111-1307 USA * 00022 * * 00023 ***************************************************************************/ 00024 00025 00026 #ifdef HAVE_CONFIG_H 00027 # include <config.h> 00028 #endif 00029 00030 #include "memcache_p.h" 00031 #include <gwenhywfar/misc.h> 00032 #include <gwenhywfar/debug.h> 00033 00034 00035 00036 GWEN_IDMAP_FUNCTIONS(GWEN_MEMCACHE_ENTRY, GWEN_MemCacheEntry) 00037 00038 00039 00040 GWEN_MEMCACHE_ENTRY *GWEN_MemCacheEntry_new(GWEN_MEMCACHE *memCache, 00041 uint32_t id, 00042 void *dataPtr, 00043 size_t dataLen) { 00044 GWEN_MEMCACHE_ENTRY *me; 00045 00046 GWEN_NEW_OBJECT(GWEN_MEMCACHE_ENTRY, me); 00047 00048 me->memCache=memCache; 00049 me->id=id; 00050 me->dataPtr=dataPtr; 00051 me->dataLen=dataLen; 00052 me->isValid=1; 00053 00054 /* update memcache */ 00055 me->memCache->currentCacheEntries++; 00056 me->memCache->currentCacheMemory+=me->dataLen; 00057 00058 return me; 00059 } 00060 00061 00062 00063 void GWEN_MemCacheEntry_free(GWEN_MEMCACHE_ENTRY *me) { 00064 if (me) { 00065 assert(me->useCounter==0); 00066 assert(me->memCache); 00067 00068 /* update memcache */ 00069 me->memCache->currentCacheEntries--; 00070 me->memCache->currentCacheMemory-=me->dataLen; 00071 00072 if (me->dataPtr && me->dataLen) 00073 free(me->dataPtr); 00074 00075 GWEN_FREE_OBJECT(me); 00076 } 00077 } 00078 00079 00080 00081 int GWEN_MemCacheEntry_GetUseCounter(const GWEN_MEMCACHE_ENTRY *me) { 00082 assert(me); 00083 return me->useCounter; 00084 } 00085 00086 00087 00088 time_t GWEN_MemCacheEntry_GetUnusedSince(GWEN_MEMCACHE_ENTRY *me) { 00089 assert(me); 00090 return me->unusedSince; 00091 } 00092 00093 00094 00095 uint32_t GWEN_MemCacheEntry_GetId(GWEN_MEMCACHE_ENTRY *me) { 00096 assert(me); 00097 return me->id; 00098 } 00099 00100 00101 00102 void *GWEN_MemCacheEntry_GetDataPtr(GWEN_MEMCACHE_ENTRY *me) { 00103 assert(me); 00104 return me->dataPtr; 00105 } 00106 00107 00108 00109 size_t GWEN_MemCacheEntry_GetDataLen(GWEN_MEMCACHE_ENTRY *me) { 00110 assert(me); 00111 return me->dataLen; 00112 } 00113 00114 00115 00116 void GWEN_MemCacheEntry_BeginUse(GWEN_MEMCACHE_ENTRY *me) { 00117 int rv; 00118 00119 assert(me); 00120 rv=GWEN_MemCache_Lock(me->memCache); 00121 if (rv) { 00122 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00123 assert(0); 00124 } 00125 me->useCounter++; 00126 GWEN_MemCache_Unlock(me->memCache); 00127 } 00128 00129 00130 00131 void GWEN_MemCacheEntry_EndUse(GWEN_MEMCACHE_ENTRY *me) { 00132 int rv; 00133 00134 assert(me); 00135 rv=GWEN_MemCache_Lock(me->memCache); 00136 if (rv) { 00137 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00138 assert(0); 00139 } 00140 if (me->useCounter>0) { 00141 me->useCounter--; 00142 if (me->useCounter==0) { 00143 if (!(me->isValid)) { 00144 GWEN_MemCacheEntry_free(me); 00145 } 00146 else 00147 me->unusedSince=time(0); 00148 } 00149 } 00150 else { 00151 DBG_ERROR(GWEN_LOGDOMAIN, "Use counter < 1, aborting"); 00152 GWEN_MemCache_Unlock(me->memCache); 00153 assert(me->useCounter>0); 00154 } 00155 GWEN_MemCache_Unlock(me->memCache); 00156 } 00157 00158 00159 00160 00161 00162 00163 00164 GWEN_MEMCACHE *GWEN_MemCache_new(size_t maxCacheMemory, 00165 uint32_t maxCacheEntries) { 00166 GWEN_MEMCACHE *mc; 00167 00168 GWEN_NEW_OBJECT(GWEN_MEMCACHE, mc); 00169 mc->mutex=GWEN_Mutex_new(); 00170 mc->idMap=GWEN_MemCacheEntry_IdMap_new(GWEN_IdMapAlgo_Hex4); 00171 mc->maxCacheMemory=maxCacheMemory; 00172 mc->maxCacheEntries=maxCacheEntries; 00173 00174 return mc; 00175 } 00176 00177 00178 00179 void GWEN_MemCache_free(GWEN_MEMCACHE *mc) { 00180 if (mc) { 00181 GWEN_MemCacheEntry_IdMap_free(mc->idMap); 00182 GWEN_Mutex_free(mc->mutex); 00183 GWEN_FREE_OBJECT(mc); 00184 } 00185 } 00186 00187 00188 00189 GWEN_MEMCACHE_ENTRY *GWEN_MemCache_FindEntry(GWEN_MEMCACHE *mc, 00190 uint32_t id) { 00191 GWEN_MEMCACHE_ENTRY *me; 00192 00193 assert(mc); 00194 GWEN_MemCache_Lock(mc); 00195 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id); 00196 if (me) { 00197 /* we can't call GWEN_MemCache_BeginUse() here because of the mutex */ 00198 me->useCounter++; 00199 } 00200 GWEN_MemCache_Unlock(mc); 00201 00202 return me; 00203 } 00204 00205 00206 00207 void GWEN_MemCache_PurgeEntry(GWEN_MEMCACHE *mc, 00208 uint32_t id) { 00209 GWEN_MEMCACHE_ENTRY *me; 00210 00211 assert(mc); 00212 GWEN_MemCache_Lock(mc); 00213 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id); 00214 if (me) { 00215 me->isValid=0; 00216 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id); 00217 if (me->useCounter==0) 00218 GWEN_MemCacheEntry_free(me); 00219 } 00220 GWEN_MemCache_Unlock(mc); 00221 } 00222 00223 00224 00225 int GWEN_MemCache__MakeRoom(GWEN_MEMCACHE *mc, 00226 size_t neededSize) { 00227 assert(mc); 00228 00229 /* release unused entries until there is enough memory */ 00230 while(neededSize) { 00231 GWEN_MEMCACHE_ENTRY *oldestEntry; 00232 GWEN_IDMAP_RESULT res; 00233 uint32_t currentId; 00234 00235 /* get oldest entry */ 00236 oldestEntry=NULL; 00237 res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, ¤tId); 00238 while(res==GWEN_IdMapResult_Ok) { 00239 GWEN_MEMCACHE_ENTRY *me; 00240 00241 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId); 00242 if (me) { 00243 if (me->isValid && me->useCounter==0) { 00244 if (oldestEntry==NULL) 00245 oldestEntry=me; 00246 else { 00247 if (me->unusedSince<oldestEntry->unusedSince) 00248 oldestEntry=me; 00249 } 00250 } 00251 } 00252 res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, ¤tId); 00253 } 00254 00255 if (oldestEntry==NULL) 00256 /* no unused entry found */ 00257 break; 00258 00259 /* subtract size of to-be-removed entry from needed size */ 00260 if (neededSize<oldestEntry->dataLen) 00261 neededSize=0; 00262 else 00263 neededSize-=oldestEntry->dataLen; 00264 00265 /* remove oldest entry (it is unused, so we also delete it here) */ 00266 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, oldestEntry->id); 00267 GWEN_MemCacheEntry_free(oldestEntry); 00268 } 00269 00270 return (neededSize==0)?0:GWEN_ERROR_MEMORY_FULL; 00271 } 00272 00273 00274 00275 GWEN_MEMCACHE_ENTRY *GWEN_MemCache_CreateEntry(GWEN_MEMCACHE *mc, 00276 uint32_t id, 00277 void *dataPtr, 00278 size_t dataLen) { 00279 GWEN_MEMCACHE_ENTRY *me; 00280 00281 assert(mc); 00282 GWEN_MemCache_Lock(mc); 00283 00284 /* invalidate possibly existing entry in any case */ 00285 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id); 00286 if (me) { 00287 me->isValid=0; 00288 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id); 00289 if (me->useCounter==0) 00290 GWEN_MemCacheEntry_free(me); 00291 } 00292 00293 /* check for limits: entry count */ 00294 if (mc->currentCacheEntries>=mc->maxCacheEntries) { 00295 int rv; 00296 00297 /* release unused entries (at least 1 byte) */ 00298 rv=GWEN_MemCache__MakeRoom(mc, 1); 00299 if (rv) { 00300 DBG_WARN(GWEN_LOGDOMAIN, "Too many entries in use"); 00301 GWEN_MemCache_Unlock(mc); 00302 return NULL; 00303 } 00304 } 00305 00306 /* check for limits: memory in use */ 00307 if ((mc->currentCacheMemory+dataLen)>=mc->maxCacheMemory) { 00308 size_t diff; 00309 int rv; 00310 00311 diff=(mc->currentCacheMemory+dataLen)-mc->maxCacheMemory; 00312 /* release unused entries */ 00313 rv=GWEN_MemCache__MakeRoom(mc, diff); 00314 if (rv) { 00315 DBG_WARN(GWEN_LOGDOMAIN, "Too much memory in use"); 00316 GWEN_MemCache_Unlock(mc); 00317 return NULL; 00318 } 00319 } 00320 00321 /* create new entry */ 00322 me=GWEN_MemCacheEntry_new(mc, id, dataPtr, dataLen); 00323 assert(me); 00324 me->useCounter++; 00325 GWEN_MemCacheEntry_IdMap_Insert(mc->idMap, id, me); 00326 00327 GWEN_MemCache_Unlock(mc); 00328 00329 return me; 00330 } 00331 00332 00333 00334 void GWEN_MemCache_PurgeEntries(GWEN_MEMCACHE *mc, 00335 uint32_t id, uint32_t mask) { 00336 GWEN_IDMAP_RESULT res; 00337 uint32_t currentId; 00338 00339 assert(mc); 00340 GWEN_MemCache_Lock(mc); 00341 00342 res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, ¤tId); 00343 while(res==GWEN_IdMapResult_Ok) { 00344 uint32_t nextId; 00345 00346 nextId=currentId; 00347 res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, &nextId); 00348 if ((currentId & mask)==id) { 00349 GWEN_MEMCACHE_ENTRY *me; 00350 00351 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId); 00352 if (me) { 00353 me->isValid=0; 00354 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, currentId); 00355 if (me->useCounter==0) 00356 GWEN_MemCacheEntry_free(me); 00357 } 00358 00359 } 00360 currentId=nextId; 00361 } 00362 00363 GWEN_MemCache_Unlock(mc); 00364 } 00365 00366 00367 00368 void GWEN_MemCache_Purge(GWEN_MEMCACHE *mc) { 00369 assert(mc); 00370 GWEN_MemCache_PurgeEntries(mc, 0, 0); 00371 } 00372 00373 00374 00375 int GWEN_MemCache_Lock(GWEN_MEMCACHE *mc) { 00376 assert(mc); 00377 return GWEN_Mutex_Lock(mc->mutex); 00378 } 00379 00380 00381 00382 int GWEN_MemCache_Unlock(GWEN_MEMCACHE *mc) { 00383 assert(mc); 00384 return GWEN_Mutex_Unlock(mc->mutex); 00385 } 00386 00387 00388 00389 00390 00391 00392 00393