status_t TeamDebugInfo::GetType(GlobalTypeCache* cache, const BString& name, const TypeLookupConstraints& constraints, Type*& _type) { // maybe the type is already cached AutoLocker<GlobalTypeCache> cacheLocker(cache); Type* type = cache->GetType(name, constraints); if (type != NULL) { type->AcquireReference(); _type = type; return B_OK; } cacheLocker.Unlock(); // Clone the image list and get references to the images, so we can iterate // through them without locking. AutoLocker<BLocker> locker(fLock); ImageList images; for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) { if (images.AddItem(imageDebugInfo)) imageDebugInfo->AcquireReference(); } locker.Unlock(); // get the type status_t error = B_ENTRY_NOT_FOUND; for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++) { error = imageDebugInfo->GetType(cache, name, constraints, type); if (error == B_OK) { _type = type; break; } } // release the references for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++) imageDebugInfo->ReleaseReference(); return error; }
bool TeamDebugInfo::HasType(GlobalTypeCache* cache, const BString& name, const TypeLookupConstraints& constraints) { // maybe the type is already cached AutoLocker<GlobalTypeCache> cacheLocker(cache); Type* type = cache->GetType(name, constraints); if (type != NULL) return true; cacheLocker.Unlock(); // Clone the image list and get references to the images, so we can iterate // through them without locking. AutoLocker<BLocker> locker(fLock); ImageList images; for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) { if (images.AddItem(imageDebugInfo)) imageDebugInfo->AcquireReference(); } locker.Unlock(); bool found = false; for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++) { if (imageDebugInfo->HasType(name, constraints)) { found = true; break; } } // release the references for (int32 i = 0; ImageDebugInfo* imageDebugInfo = images.ItemAt(i); i++) imageDebugInfo->ReleaseReference(); return found; }
static status_t object_cache_maintainer(void*) { while (true) { MutexLocker locker(sMaintenanceLock); // wait for the next request while (sMaintenanceQueue.IsEmpty()) { // perform memory manager maintenance, if needed if (MemoryManager::MaintenanceNeeded()) { locker.Unlock(); MemoryManager::PerformMaintenance(); locker.Lock(); continue; } ConditionVariableEntry entry; sMaintenanceCondition.Add(&entry); locker.Unlock(); entry.Wait(); locker.Lock(); } ObjectCache* cache = sMaintenanceQueue.RemoveHead(); while (true) { bool resizeRequested = cache->maintenance_resize; bool deleteRequested = cache->maintenance_delete; if (!resizeRequested && !deleteRequested) { cache->maintenance_pending = false; cache->maintenance_in_progress = false; break; } cache->maintenance_resize = false; cache->maintenance_in_progress = true; locker.Unlock(); if (deleteRequested) { delete_object_cache_internal(cache); break; } // resize the cache, if necessary MutexLocker cacheLocker(cache->lock); if (resizeRequested) { status_t error = object_cache_reserve_internal(cache, cache->min_object_reserve, 0); if (error != B_OK) { dprintf("object cache resizer: Failed to resize object " "cache %p!\n", cache); break; } } locker.Lock(); } } // never can get here return B_OK; }
static void object_cache_low_memory(void* dummy, uint32 resources, int32 level) { if (level == B_NO_LOW_RESOURCE) return; MutexLocker cacheListLocker(sObjectCacheListLock); // Append the first cache to the end of the queue. We assume that it is // one of the caches that will never be deleted and thus we use it as a // marker. ObjectCache* firstCache = sObjectCaches.RemoveHead(); sObjectCaches.Add(firstCache); cacheListLocker.Unlock(); ObjectCache* cache; do { cacheListLocker.Lock(); cache = sObjectCaches.RemoveHead(); sObjectCaches.Add(cache); MutexLocker maintenanceLocker(sMaintenanceLock); if (cache->maintenance_pending || cache->maintenance_in_progress) { // We don't want to mess with caches in maintenance. continue; } cache->maintenance_pending = true; cache->maintenance_in_progress = true; maintenanceLocker.Unlock(); cacheListLocker.Unlock(); // We are calling the reclaimer without the object cache lock // to give the owner a chance to return objects to the slabs. if (cache->reclaimer) cache->reclaimer(cache->cookie, level); if ((cache->flags & CACHE_NO_DEPOT) == 0) object_depot_make_empty(&cache->depot, 0); MutexLocker cacheLocker(cache->lock); size_t minimumAllowed; switch (level) { case B_LOW_RESOURCE_NOTE: minimumAllowed = cache->pressure / 2 + 1; cache->pressure -= cache->pressure / 8; break; case B_LOW_RESOURCE_WARNING: cache->pressure /= 2; minimumAllowed = 0; break; default: cache->pressure = 0; minimumAllowed = 0; break; } while (cache->empty_count > minimumAllowed) { // make sure we respect the cache's minimum object reserve size_t objectsPerSlab = cache->empty.Head()->size; size_t freeObjects = cache->total_objects - cache->used_count; if (freeObjects < cache->min_object_reserve + objectsPerSlab) break; cache->ReturnSlab(cache->empty.RemoveHead(), 0); cache->empty_count--; } cacheLocker.Unlock(); // Check whether in the meantime someone has really requested // maintenance for the cache. maintenanceLocker.Lock(); if (cache->maintenance_delete) { delete_object_cache_internal(cache); continue; } cache->maintenance_in_progress = false; if (cache->maintenance_resize) sMaintenanceQueue.Add(cache); else cache->maintenance_pending = false; } while (cache != firstCache); }