/*
* Mutex-free cache for key1+key2=value.
*/
-#ifndef _DALVIK_ATOMICCACHE
-#define _DALVIK_ATOMICCACHE
+#ifndef DALVIK_ATOMICCACHE_H_
+#define DALVIK_ATOMICCACHE_H_
/*
* If set to "1", gather some stats on our caching success rate.
*
* Must be exactly 16 bytes.
*/
-typedef struct AtomicCacheEntry {
+struct AtomicCacheEntry {
u4 key1;
u4 key2;
u4 value;
volatile u4 version; /* version and lock flag */
-} AtomicCacheEntry;
+};
/*
* One cache.
* struct and "entries" separately, avoiding an indirection. (We already
* handle "numEntries" separately in ATOMIC_CACHE_LOOKUP.)
*/
-typedef struct AtomicCache {
+struct AtomicCache {
AtomicCacheEntry* entries; /* array of entries */
int numEntries; /* #of entries, must be power of 2 */
int hits; /* found entry in cache */
int misses; /* entry was for other keys */
int fills; /* entry was empty */
-} AtomicCache;
+};
/*
* Do a cache lookup. We need to be able to read and write entries
#define ATOMIC_CACHE_LOOKUP(_cache, _cacheSize, _key1, _key2) ({ \
AtomicCacheEntry* pEntry; \
int hash; \
- u4 firstVersion; \
+ u4 firstVersion, secondVersion; \
u4 value; \
\
/* simple hash function */ \
hash = (((u4)(_key1) >> 2) ^ (u4)(_key2)) & ((_cacheSize)-1); \
pEntry = (_cache)->entries + hash; \
\
- firstVersion = pEntry->version; \
- ANDROID_MEMBAR_FULL(); \
+ firstVersion = android_atomic_acquire_load((int32_t*)&pEntry->version); \
\
if (pEntry->key1 == (u4)(_key1) && pEntry->key2 == (u4)(_key2)) { \
/* \
* The fields match. Get the value, then read the version a \
* second time to verify that we didn't catch a partial update. \
* We're also hosed if "firstVersion" was odd, indicating that \
- * an update was in progress before we got here. \
+ * an update was in progress before we got here (unlikely). \
*/ \
- value = pEntry->value; \
- ANDROID_MEMBAR_FULL(); \
+ value = android_atomic_acquire_load((int32_t*) &pEntry->value); \
+ secondVersion = pEntry->version; \
\
- if ((firstVersion & 0x01) != 0 || firstVersion != pEntry->version) \
- { \
+ if ((firstVersion & 0x01) != 0 || firstVersion != secondVersion) { \
/* \
* We clashed with another thread. Instead of sitting and \
* spinning, which might not complete if we're a high priority \
* boost. \
*/ \
value = (u4) ATOMIC_CACHE_CALC; \
- dvmUpdateAtomicCache((u4) (_key1), (u4) (_key2), value, pEntry, \
- firstVersion CACHE_XARG(_cache) ); \
+ if (value == 0 && ATOMIC_CACHE_NULL_ALLOWED) { \
+ dvmUpdateAtomicCache((u4) (_key1), (u4) (_key2), value, pEntry, \
+ firstVersion CACHE_XARG(_cache) ); \
+ } \
} \
value; \
})
*/
void dvmDumpAtomicCacheStats(const AtomicCache* pCache);
-#endif /*_DALVIK_ATOMICCACHE*/
+#endif // DALVIK_ATOMICCACHE_H_