effil/src/cpp/garbage-collector.cpp
Ilia 64628c1757 GC API for lua (#43)
Almost old gc api, but:
rebased on new master
GC::State -> enabled_ flag
release lua state as soon as possible
2017-04-16 14:08:24 +03:00

96 lines
2.4 KiB
C++

#include "garbage-collector.h"
#include "utils.h"
#include <vector>
#include <cassert>
namespace effil {
GC::GC()
: enabled_(true)
, lastCleanup_(0)
, step_(200) {}
GCObject* GC::findObject(GCObjectHandle handle) {
auto it = objects_.find(handle);
if (it == objects_.end()) {
DEBUG << "Null handle " << handle << std::endl;
return nullptr;
}
return it->second.get();
}
bool GC::has(GCObjectHandle handle) const {
std::lock_guard<std::mutex> g(lock_);
return objects_.find(handle) != objects_.end();
}
// Here is the naive tri-color marking
// garbage collecting algorithm implementation.
void GC::collect() {
std::lock_guard<std::mutex> g(lock_);
std::vector<GCObjectHandle> grey;
std::map<GCObjectHandle, std::shared_ptr<GCObject>> black;
for (const auto& handleAndObject : objects_)
if (handleAndObject.second->instances() > 1)
grey.push_back(handleAndObject.first);
while (!grey.empty()) {
GCObjectHandle handle = grey.back();
grey.pop_back();
auto object = objects_[handle];
black[handle] = object;
for (GCObjectHandle refHandle : object->refers())
if (black.find(refHandle) == black.end())
grey.push_back(refHandle);
}
DEBUG << "Removing " << (objects_.size() - black.size()) << " out of " << objects_.size() << std::endl;
// Sweep phase
objects_ = std::move(black);
lastCleanup_.store(0);
}
size_t GC::size() const {
std::lock_guard<std::mutex> g(lock_);
return objects_.size();
}
size_t GC::count() {
std::lock_guard<std::mutex> g(lock_);
return objects_.size();
}
GC& GC::instance() {
static GC pool;
return pool;
}
sol::table GC::getLuaApi(sol::state_view& lua) {
sol::table api = lua.create_table_with();
api["collect"] = [=] {
instance().collect();
};
api["pause"] = [] { instance().pause(); };
api["resume"] = [] { instance().resume(); };
api["enabled"] = [] { return instance().enabled(); };
api["step"] = [](sol::optional<int> newStep){
auto previous = instance().step();
if (newStep) {
REQUIRE(*newStep <= 0) << "gc.step have to be > 0";
instance().step(static_cast<size_t>(*newStep));
}
return previous;
};
api["count"] = [] {
return instance().count();
};
return api;
}
} // effil