#pragma once
#ifndef __AUTO_BLOCK_ITERATOR__
#define __AUTO_BLOCK_ITERATOR__
#include "Admin.h"
#include "Definitions.h"
#include "Large.h"
#include "Region.h"
#include "Zone.h"
#include "BlockRef.h"
namespace Auto {
template <class Visitor> bool visitAllocatedBlocks(Zone *zone, Visitor& visitor) {
for (Region *region = zone->region_list(); region != NULL; region = region->next()) {
SubzoneRangeIterator iterator(region->subzone_range());
while (Subzone *subzone = iterator.next()) {
usword_t n = subzone->allocation_limit();
for (usword_t q = 0; q < n; q = subzone->next_quantum(q)) {
if (!subzone->is_free(q)) {
visitor.visit(zone, subzone, q);
}
}
}
}
for (Large *large = zone->large_list(); large != NULL; large = large->next()) {
if (!visitor.visit(zone, large)) return false;
}
return true;
}
template <class Visitor> class ConcurrentVisitorHelper {
Zone *_zone;
Visitor &_visitor;
Large *_current_large; Region *_current_region; SubzoneRangeIterator _iterator; spin_lock_t _lock;
private:
void visit_large(Large *large_to_visit) {
do {
_visitor.visit(_zone, large_to_visit);
large_to_visit = _visitor.visit_larges_concurrently() ? NULL : large_to_visit->next();
} while (large_to_visit != NULL);
}
void visit_subzone(Subzone *subzone_to_visit) {
_visitor.visit(_zone, subzone_to_visit);
}
public:
ConcurrentVisitorHelper(Zone *zone, Visitor &visitor) : _zone(zone), _visitor(visitor), _current_large(zone->large_list()), _current_region(zone->region_list()), _iterator(_current_region->subzone_range()), _lock(0) {}
inline boolean_t visit(boolean_t is_dedicated, boolean_t work_to_completion) {
boolean_t did_work;
do {
did_work = false;
Large *large_to_visit = NULL;
Subzone *subzone_to_visit = NULL;
{
SpinLock lock(&_lock);
if (_current_large != NULL) {
large_to_visit = _current_large;
if (_visitor.visit_larges_concurrently()) {
_current_large = _current_large->next();
} else {
_current_large = NULL;
}
did_work = true;
}
if (large_to_visit == NULL) {
subzone_to_visit = _iterator.next();
if (!subzone_to_visit && _current_region) {
_current_region = _current_region->next();
if (_current_region) {
_iterator = SubzoneRangeIterator(_current_region->subzone_range());
subzone_to_visit = _iterator.next();
}
}
}
}
if (large_to_visit) visit_large(large_to_visit);
if (subzone_to_visit != NULL) {
did_work = true;
visit_subzone(subzone_to_visit);
}
} while (did_work && work_to_completion);
return did_work;
}
static boolean_t visitor_wrapper(void *arg, boolean_t is_dedicated, boolean_t work_to_completion) {
ConcurrentVisitorHelper<Visitor> *helper = (ConcurrentVisitorHelper *)arg;
return helper->visit(is_dedicated, work_to_completion);
}
};
template <class Visitor> void visitAllocatedBlocks_concurrent(Zone *zone, Visitor& visitor) {
ConcurrentVisitorHelper<Visitor> helper(zone, visitor);
zone->perform_work_with_helper_threads(ConcurrentVisitorHelper<Visitor>::visitor_wrapper, &helper);
}
template <class Visitor> void visitPendingBlocks(Zone *zone, Visitor& visitor) {
for (Region *region = zone->region_list(); region != NULL; region = region->next()) {
SubzoneRangeIterator iterator(region->subzone_range());
while (Subzone *subzone = iterator.next()) {
usword_t n = subzone->allocation_limit();
for (usword_t q = 0; q < n; q = subzone->next_quantum(q)) {
if (!subzone->is_free(q) && subzone->test_and_clear_pending(q)) {
visitor(subzone, q);
}
}
}
}
for (Large *large = zone->large_list(); large != NULL; large = large->next()) {
if (large->is_pending()) {
large->clear_pending();
visitor(large);
}
}
}
template <class Visitor> bool visitAllBlocks(Zone *zone, Visitor& visitor) {
for (Region *region = zone->region_list(); region != NULL; region = region->next()) {
SubzoneRangeIterator iterator(region->subzone_range());
while (Subzone *subzone = iterator.next()) {
usword_t n = subzone->allocation_limit();
for (usword_t q = 0; q < n; q = subzone->next_quantum(q)) {
if (!visitor.visit(zone, subzone, q)) return false;
}
}
}
for (Large *large = zone->large_list(); large != NULL; large = large->next()) {
if (!visitor.visit(zone, large)) return false;
}
return true;
}
template <class Visitor> bool visitAssociationsNoLock(Zone *zone, Visitor& visitor) {
AssociationsHashMap &associations(zone->associations());
for (AssociationsHashMap::iterator i = associations.begin(), iend = associations.end(); i != iend; i++) {
void *block = i->first;
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), jend = refs->end(); j != jend; j++) {
ObjectAssociationMap::value_type &pair = *j;
if (!visitor(zone, block, pair.first, pair.second)) return false;
}
}
return true;
}
template <typename Visitor> bool visitRootsNoLock(Zone *zone, Visitor visitor) {
PtrHashSet &roots(zone->roots());
for (PtrHashSet::const_iterator i = roots.begin(), end = roots.end(); i != end; ++i) {
if (!visitor((void **)*i)) return false;
}
return true;
}
template <class BlockDo> void blockDo(Zone *zone, void *block, BlockDo &op) {
if (zone->in_subzone_memory(block)) {
Subzone *subzone = Subzone::subzone(block);
usword_t q;
if (subzone->block_is_start(block, &q)) op(subzone, q);
} else if (zone->block_is_start_large(block)) {
op(Large::large(block));
}
}
inline void blockDo(Zone *zone, void *block, void (^subzoneDo) (Subzone *subzone, usword_t q), void (^largeDo) (Large *large), void (^elseDo) (void *block) = NULL) {
if (zone->in_subzone_memory(block)) {
Subzone *subzone = Subzone::subzone(block);
usword_t q;
if (subzone->block_is_start(block, &q)) subzoneDo(subzone, q);
} else if (zone->block_is_start_large(block)) {
largeDo(Large::large(block));
} else if (elseDo) {
elseDo(block);
}
}
inline void blockStartNoLockDo(Zone *zone, void *address, void (^subzoneDo) (Subzone *subzone, usword_t q), void (^largeDo) (Large *large)) {
if (zone->in_subzone_memory(address)) {
Subzone *subzone = Subzone::subzone(address);
usword_t q;
if (subzone->block_start(address, q)) subzoneDo(subzone, q);
} else if (zone->in_large_memory(address)) {
Large *large = zone->block_start_large(address);
if (large) largeDo(large);
}
}
};
#endif // __AUTO_BLOCK_ITERATOR__