Fix codestyle

This commit is contained in:
Ilia Udalov 2017-02-18 14:06:30 +03:00
parent 78f2306657
commit e8bbb5d293
15 changed files with 209 additions and 266 deletions

View File

@ -8,9 +8,9 @@
namespace effil { namespace effil {
GarbageCollector::GarbageCollector() GarbageCollector::GarbageCollector()
: state_(GCState::Idle), : state_(GCState::Idle)
lastCleanup_(0), , lastCleanup_(0)
step_(200) {} , step_(200) {}
GCObject* GarbageCollector::get(GCObjectHandle handle) { GCObject* GarbageCollector::get(GCObjectHandle handle) {
std::lock_guard<std::mutex> g(lock_); std::lock_guard<std::mutex> g(lock_);
@ -32,30 +32,30 @@ bool GarbageCollector::has(GCObjectHandle handle) const {
void GarbageCollector::cleanup() { void GarbageCollector::cleanup() {
std::lock_guard<std::mutex> g(lock_); std::lock_guard<std::mutex> g(lock_);
if (state_ == GCState::Stopped) return; if (state_ == GCState::Stopped)
return;
assert(state_ != GCState::Running); assert(state_ != GCState::Running);
state_ = GCState::Running; state_ = GCState::Running;
std::vector<GCObjectHandle> grey; std::vector<GCObjectHandle> grey;
std::map<GCObjectHandle, std::shared_ptr<GCObject>> black; std::map<GCObjectHandle, std::shared_ptr<GCObject>> black;
for(const auto& handleAndObject : objects_) for (const auto& handleAndObject : objects_)
if (handleAndObject.second->instances() > 1) if (handleAndObject.second->instances() > 1)
grey.push_back(handleAndObject.first); grey.push_back(handleAndObject.first);
while(!grey.empty()) { while (!grey.empty()) {
GCObjectHandle handle = grey.back(); GCObjectHandle handle = grey.back();
grey.pop_back(); grey.pop_back();
auto object = objects_[handle]; auto object = objects_[handle];
black[handle] = object; black[handle] = object;
for(GCObjectHandle refHandle : object->refers()) for (GCObjectHandle refHandle : object->refers())
if (black.find(refHandle) == black.end()) if (black.find(refHandle) == black.end())
grey.push_back(refHandle); grey.push_back(refHandle);
} }
DEBUG << "Removing " << (objects_.size() - black.size()) DEBUG << "Removing " << (objects_.size() - black.size()) << " out of " << objects_.size() << std::endl;
<< " out of " << objects_.size() << std::endl;
// Sweep phase // Sweep phase
objects_ = std::move(black); objects_ = std::move(black);
@ -80,7 +80,6 @@ void GarbageCollector::resume() {
state_ = GCState::Idle; state_ = GCState::Idle;
} }
GarbageCollector& getGC() { GarbageCollector& getGC() {
static GarbageCollector pool; static GarbageCollector pool;
return pool; return pool;

View File

@ -18,7 +18,8 @@ static const GCObjectHandle GCNull = nullptr;
// Child has to care about storing data and concurrent access. // Child has to care about storing data and concurrent access.
class GCObject { class GCObject {
public: public:
GCObject() noexcept : refs_(new std::set<GCObjectHandle>) {} GCObject() noexcept
: refs_(new std::set<GCObjectHandle>) {}
GCObject(const GCObject& init) = default; GCObject(const GCObject& init) = default;
GCObject(GCObject&& init) = default; GCObject(GCObject&& init) = default;
virtual ~GCObject() = default; virtual ~GCObject() = default;
@ -31,11 +32,7 @@ protected:
std::shared_ptr<std::set<GCObjectHandle>> refs_; std::shared_ptr<std::set<GCObjectHandle>> refs_;
}; };
enum class GCState { enum class GCState { Idle, Running, Stopped };
Idle,
Running,
Stopped
};
class GarbageCollector { class GarbageCollector {
public: public:
@ -43,9 +40,10 @@ public:
~GarbageCollector() = default; ~GarbageCollector() = default;
// This method is used to create all managed objects. // This method is used to create all managed objects.
template<typename ObjectType,typename... Args> template <typename ObjectType, typename... Args>
ObjectType create(Args&&... args) { ObjectType create(Args&&... args) {
if (lastCleanup_.fetch_add(1) == step_) cleanup(); if (lastCleanup_.fetch_add(1) == step_)
cleanup();
auto object = std::make_shared<ObjectType>(std::forward<Args>(args)...); auto object = std::make_shared<ObjectType>(std::forward<Args>(args)...);
std::lock_guard<std::mutex> g(lock_); std::lock_guard<std::mutex> g(lock_);
@ -75,7 +73,6 @@ private:
GarbageCollector(const GarbageCollector&) = delete; GarbageCollector(const GarbageCollector&) = delete;
}; };
GarbageCollector& getGC(); GarbageCollector& getGC();
} // effil } // effil

View File

@ -12,25 +12,21 @@ sol::object createThreadFactory(sol::this_state lua, const sol::function& func)
return sol::make_object(lua, std::make_unique<ThreadFactory>(func)); return sol::make_object(lua, std::make_unique<ThreadFactory>(func));
} }
sol::object createShare(sol::this_state lua) { sol::object createShare(sol::this_state lua) { return sol::make_object(lua, getGC().create<SharedTable>()); }
return sol::make_object(lua, getGC().create<SharedTable>());
}
} // namespace } // namespace
extern "C" int luaopen_libeffil(lua_State *L) { extern "C" int luaopen_libeffil(lua_State* L) {
sol::state_view lua(L); sol::state_view lua(L);
effil::LuaThread::getUserType(lua); effil::LuaThread::getUserType(lua);
SharedTable::getUserType(lua); SharedTable::getUserType(lua);
ThreadFactory::getUserType(lua); ThreadFactory::getUserType(lua);
sol::table public_api = lua.create_table_with( sol::table public_api = lua.create_table_with("thread", createThreadFactory, //
"thread", createThreadFactory, // "thread_id", threadId, //
"thread_id", threadId, // "sleep", sleep, //
"sleep", sleep, // "yield", yield, //
"yield", yield, // "share", createShare //
"share", createShare // );
);
sol::stack::push(lua, public_api); sol::stack::push(lua, public_api);
return 1; return 1;
} }

View File

@ -8,24 +8,21 @@
namespace effil { namespace effil {
SharedTable::SharedTable() SharedTable::SharedTable()
: GCObject(), : GCObject()
data_(std::make_shared<SharedData>()) { , data_(std::make_shared<SharedData>()) {}
}
SharedTable::SharedTable(const SharedTable& init) SharedTable::SharedTable(const SharedTable& init)
: GCObject(init), : GCObject(init)
data_(init.data_) { , data_(init.data_) {}
}
sol::object SharedTable::getUserType(sol::state_view &lua) { sol::object SharedTable::getUserType(sol::state_view& lua) {
static sol::usertype<SharedTable> type( static sol::usertype<SharedTable> type("new", sol::no_constructor, //
"new", sol::no_constructor, // sol::meta_function::new_index, &SharedTable::luaSet, //
sol::meta_function::new_index, &SharedTable::luaSet,// sol::meta_function::index, &SharedTable::luaGet, //
sol::meta_function::index, &SharedTable::luaGet,// sol::meta_function::length, &SharedTable::length, //
sol::meta_function::length, &SharedTable::length,// "__pairs", &SharedTable::pairs, //
"__pairs", &SharedTable::pairs, // "__ipairs", &SharedTable::ipairs //
"__ipairs", &SharedTable::ipairs // );
);
sol::stack::push(lua, type); sol::stack::push(lua, type);
return sol::stack::pop<sol::object>(lua); return sol::stack::pop<sol::object>(lua);
} }
@ -33,8 +30,10 @@ sol::object SharedTable::getUserType(sol::state_view &lua) {
void SharedTable::set(StoredObject&& key, StoredObject&& value) { void SharedTable::set(StoredObject&& key, StoredObject&& value) {
std::lock_guard<SpinMutex> g(data_->lock); std::lock_guard<SpinMutex> g(data_->lock);
if (key->gcHandle()) refs_->insert(key->gcHandle()); if (key->gcHandle())
if (value->gcHandle()) refs_->insert(value->gcHandle()); refs_->insert(key->gcHandle());
if (value->gcHandle())
refs_->insert(value->gcHandle());
data_->entries[std::move(key)] = std::move(value); data_->entries[std::move(key)] = std::move(value);
} }
@ -59,8 +58,10 @@ void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_objec
// in this case object is not obligatory to own data // in this case object is not obligatory to own data
auto it = data_->entries.find(key); auto it = data_->entries.find(key);
if (it != data_->entries.end()) { if (it != data_->entries.end()) {
if (it->first->gcHandle()) refs_->erase(it->first->gcHandle()); if (it->first->gcHandle())
if (it->second->gcHandle()) refs_->erase(it->second->gcHandle()); refs_->erase(it->first->gcHandle());
if (it->second->gcHandle())
refs_->erase(it->second->gcHandle());
data_->entries.erase(it); data_->entries.erase(it);
} }
@ -85,14 +86,12 @@ size_t SharedTable::length() const {
size_t len = 0u; size_t len = 0u;
sol::optional<double> value; sol::optional<double> value;
auto iter = data_->entries.find(createStoredObject(static_cast<double>(1))); auto iter = data_->entries.find(createStoredObject(static_cast<double>(1)));
if (iter != data_->entries.end()) if (iter != data_->entries.end()) {
{ do {
do
{
++len; ++len;
++iter; ++iter;
} } while ((iter != data_->entries.end()) && (value = storedObjectToDouble(iter->first)) &&
while ((iter != data_->entries.end()) && (value = storedObjectToDouble(iter->first)) && (static_cast<size_t>(value.value()) == len + 1)); (static_cast<size_t>(value.value()) == len + 1));
} }
return len; return len;
} }
@ -104,8 +103,7 @@ SharedTable::PairsIterator SharedTable::getNext(const sol::object& key, sol::thi
auto upper = data_->entries.upper_bound(obj); auto upper = data_->entries.upper_bound(obj);
if (upper != data_->entries.end()) if (upper != data_->entries.end())
return std::tuple<sol::object, sol::object>(upper->first->unpack(lua), upper->second->unpack(lua)); return std::tuple<sol::object, sol::object>(upper->first->unpack(lua), upper->second->unpack(lua));
} } else {
else {
if (!data_->entries.empty()) { if (!data_->entries.empty()) {
const auto& begin = data_->entries.begin(); const auto& begin = data_->entries.begin();
return std::tuple<sol::object, sol::object>(begin->first->unpack(lua), begin->second->unpack(lua)); return std::tuple<sol::object, sol::object>(begin->first->unpack(lua), begin->second->unpack(lua));
@ -115,14 +113,16 @@ SharedTable::PairsIterator SharedTable::getNext(const sol::object& key, sol::thi
} }
SharedTable::PairsIterator SharedTable::pairs(sol::this_state lua) const { SharedTable::PairsIterator SharedTable::pairs(sol::this_state lua) const {
auto next = [](sol::this_state lua, SharedTable table, sol::stack_object key){ return table.getNext(key, lua); }; auto next = [](sol::this_state lua, SharedTable table, sol::stack_object key) { return table.getNext(key, lua); };
return std::tuple<sol::function, sol::object>( return std::tuple<sol::function, sol::object>(
sol::make_object(lua, std::function<PairsIterator(sol::this_state lua, SharedTable table, sol::stack_object key)>(next)).as<sol::function>(), sol::make_object(
sol::make_object(lua, *this) lua, std::function<PairsIterator(sol::this_state lua, SharedTable table, sol::stack_object key)>(next))
); .as<sol::function>(),
sol::make_object(lua, *this));
} }
std::tuple<sol::object, sol::object> ipairsNext(sol::this_state lua, SharedTable table, sol::optional<unsigned long> key) { std::tuple<sol::object, sol::object> ipairsNext(sol::this_state lua, SharedTable table,
sol::optional<unsigned long> key) {
size_t index = key ? key.value() + 1 : 1; size_t index = key ? key.value() + 1 : 1;
auto objKey = createStoredObject(static_cast<double>(index)); auto objKey = createStoredObject(static_cast<double>(index));
sol::object value = table.get(objKey, lua); sol::object value = table.get(objKey, lua);
@ -132,10 +132,8 @@ std::tuple<sol::object, sol::object> ipairsNext(sol::this_state lua, SharedTable
} }
std::tuple<sol::function, sol::object> SharedTable::ipairs(sol::this_state lua) const { std::tuple<sol::function, sol::object> SharedTable::ipairs(sol::this_state lua) const {
return std::tuple<sol::function, sol::object>( return std::tuple<sol::function, sol::object>(sol::make_object(lua, ipairsNext).as<sol::function>(),
sol::make_object(lua, ipairsNext).as<sol::function>(), sol::make_object(lua, *this));
sol::make_object(lua, *this)
);
} }
} // effil } // effil

View File

@ -22,7 +22,7 @@ public:
SharedTable(const SharedTable& init); SharedTable(const SharedTable& init);
virtual ~SharedTable() = default; virtual ~SharedTable() = default;
static sol::object getUserType(sol::state_view &lua); static sol::object getUserType(sol::state_view& lua);
void set(StoredObject&&, StoredObject&&); void set(StoredObject&&, StoredObject&&);
sol::object get(const StoredObject& key, const sol::this_state& state) const; sol::object get(const StoredObject& key, const sol::this_state& state) const;
PairsIterator getNext(const sol::object& key, sol::this_state lua); PairsIterator getNext(const sol::object& key, sol::this_state lua);
@ -36,7 +36,6 @@ public:
PairsIterator ipairs(sol::this_state) const; PairsIterator ipairs(sol::this_state) const;
private: private:
struct SharedData { struct SharedData {
SpinMutex lock; SpinMutex lock;
DataEntries entries; DataEntries entries;
@ -46,4 +45,3 @@ private:
}; };
} // effil } // effil

View File

@ -8,14 +8,12 @@ namespace effil {
class SpinMutex { class SpinMutex {
public: public:
void lock() noexcept { void lock() noexcept {
while(lock_.test_and_set(std::memory_order_acquire)) { while (lock_.test_and_set(std::memory_order_acquire)) {
std::this_thread::yield(); std::this_thread::yield();
} }
} }
void unlock() noexcept { void unlock() noexcept { lock_.clear(std::memory_order_release); }
lock_.clear(std::memory_order_release);
}
private: private:
std::atomic_flag lock_ = ATOMIC_FLAG_INIT; std::atomic_flag lock_ = ATOMIC_FLAG_INIT;

View File

@ -13,7 +13,7 @@ namespace effil {
namespace { namespace {
template<typename StoredType> template <typename StoredType>
class PrimitiveHolder : public BaseHolder { class PrimitiveHolder : public BaseHolder {
public: public:
PrimitiveHolder(const sol::stack_object& luaObject) noexcept PrimitiveHolder(const sol::stack_object& luaObject) noexcept
@ -29,9 +29,7 @@ public:
return data_ < static_cast<const PrimitiveHolder<StoredType>*>(other)->data_; return data_ < static_cast<const PrimitiveHolder<StoredType>*>(other)->data_;
} }
sol::object unpack(sol::this_state state) const final { sol::object unpack(sol::this_state state) const final { return sol::make_object(state, data_); }
return sol::make_object(state, data_);
}
StoredType getData() { return data_; } StoredType getData() { return data_; }
@ -41,11 +39,12 @@ private:
class FunctionHolder : public BaseHolder { class FunctionHolder : public BaseHolder {
public: public:
template<typename SolObject> template <typename SolObject>
FunctionHolder(SolObject luaObject) noexcept { FunctionHolder(SolObject luaObject) noexcept {
sol::state_view lua(luaObject.lua_state()); sol::state_view lua(luaObject.lua_state());
sol::function dumper = lua["string"]["dump"]; sol::function dumper = lua["string"]["dump"];
if (!dumper.valid()) throw Exception() << "Invalid string.dump()"; if (!dumper.valid())
throw Exception() << "Invalid string.dump()";
function_ = dumper(luaObject); function_ = dumper(luaObject);
} }
@ -69,7 +68,7 @@ private:
class TableHolder : public BaseHolder { class TableHolder : public BaseHolder {
public: public:
template<typename SolType> template <typename SolType>
TableHolder(const SolType& luaObject) { TableHolder(const SolType& luaObject) {
assert(luaObject.template is<SharedTable>()); assert(luaObject.template is<SharedTable>());
handle_ = luaObject.template as<SharedTable>().handle(); handle_ = luaObject.template as<SharedTable>().handle();
@ -79,7 +78,7 @@ public:
TableHolder(GCObjectHandle handle) TableHolder(GCObjectHandle handle)
: handle_(handle) {} : handle_(handle) {}
bool rawCompare(const BaseHolder *other) const final { bool rawCompare(const BaseHolder* other) const final {
return handle_ < static_cast<const TableHolder*>(other)->handle_; return handle_ < static_cast<const TableHolder*>(other)->handle_;
} }
@ -87,7 +86,7 @@ public:
return sol::make_object(state, *static_cast<SharedTable*>(getGC().get(handle_))); return sol::make_object(state, *static_cast<SharedTable*>(getGC().get(handle_)));
} }
GCObjectHandle gcHandle() const override { return handle_; } GCObjectHandle gcHandle() const override { return handle_; }
private: private:
GCObjectHandle handle_; GCObjectHandle handle_;
@ -103,7 +102,7 @@ void dumpTable(SharedTable* target, sol::table luaTable, SolTableToShared& visit
StoredObject makeStoredObject(sol::object luaObject, SolTableToShared& visited) { StoredObject makeStoredObject(sol::object luaObject, SolTableToShared& visited) {
if (luaObject.get_type() == sol::type::table) { if (luaObject.get_type() == sol::type::table) {
sol::table luaTable = luaObject; sol::table luaTable = luaObject;
auto comparator = [&luaTable](const std::pair<sol::table, GCObjectHandle>& element){ auto comparator = [&luaTable](const std::pair<sol::table, GCObjectHandle>& element) {
return element.first == luaTable; return element.first == luaTable;
}; };
auto st = std::find_if(visited.begin(), visited.end(), comparator); auto st = std::find_if(visited.begin(), visited.end(), comparator);
@ -122,14 +121,14 @@ StoredObject makeStoredObject(sol::object luaObject, SolTableToShared& visited)
} }
void dumpTable(SharedTable* target, sol::table luaTable, SolTableToShared& visited) { void dumpTable(SharedTable* target, sol::table luaTable, SolTableToShared& visited) {
for(auto& row : luaTable) { for (auto& row : luaTable) {
target->set(makeStoredObject(row.first, visited), makeStoredObject(row.second, visited)); target->set(makeStoredObject(row.first, visited), makeStoredObject(row.second, visited));
} }
} }
template<typename SolObject> template <typename SolObject>
StoredObject fromSolObject(const SolObject& luaObject) { StoredObject fromSolObject(const SolObject& luaObject) {
switch(luaObject.get_type()) { switch (luaObject.get_type()) {
case sol::type::nil: case sol::type::nil:
break; break;
case sol::type::boolean: case sol::type::boolean:
@ -142,8 +141,7 @@ StoredObject fromSolObject(const SolObject& luaObject) {
return std::make_unique<TableHolder>(luaObject); return std::make_unique<TableHolder>(luaObject);
case sol::type::function: case sol::type::function:
return std::make_unique<FunctionHolder>(luaObject); return std::make_unique<FunctionHolder>(luaObject);
case sol::type::table: case sol::type::table: {
{
sol::table luaTable = luaObject; sol::table luaTable = luaObject;
// Tables pool is used to store tables. // Tables pool is used to store tables.
// Right now not defiantly clear how ownership between states works. // Right now not defiantly clear how ownership between states works.
@ -164,31 +162,21 @@ StoredObject fromSolObject(const SolObject& luaObject) {
} // namespace } // namespace
StoredObject createStoredObject(bool value) { StoredObject createStoredObject(bool value) { return std::make_unique<PrimitiveHolder<bool>>(value); }
return std::make_unique<PrimitiveHolder<bool>>(value);
}
StoredObject createStoredObject(double value) { StoredObject createStoredObject(double value) { return std::make_unique<PrimitiveHolder<double>>(value); }
return std::make_unique<PrimitiveHolder<double>>(value);
}
StoredObject createStoredObject(const std::string& value) { StoredObject createStoredObject(const std::string& value) {
return std::make_unique<PrimitiveHolder<std::string>>(value); return std::make_unique<PrimitiveHolder<std::string>>(value);
} }
StoredObject createStoredObject(const sol::object &object) { StoredObject createStoredObject(const sol::object& object) { return fromSolObject(object); }
return fromSolObject(object);
}
StoredObject createStoredObject(const sol::stack_object &object) { StoredObject createStoredObject(const sol::stack_object& object) { return fromSolObject(object); }
return fromSolObject(object);
}
StoredObject createStoredObject(GCObjectHandle handle) { StoredObject createStoredObject(GCObjectHandle handle) { return std::make_unique<TableHolder>(handle); }
return std::make_unique<TableHolder>(handle);
}
template<typename DataType> template <typename DataType>
sol::optional<DataType> getPrimitiveHolderData(const StoredObject& sobj) { sol::optional<DataType> getPrimitiveHolderData(const StoredObject& sobj) {
auto ptr = dynamic_cast<PrimitiveHolder<DataType>*>(sobj.get()); auto ptr = dynamic_cast<PrimitiveHolder<DataType>*>(sobj.get());
if (ptr) if (ptr)
@ -196,13 +184,9 @@ sol::optional<DataType> getPrimitiveHolderData(const StoredObject& sobj) {
return sol::optional<DataType>(); return sol::optional<DataType>();
} }
sol::optional<bool> storedObjectToBool(const StoredObject& sobj) { sol::optional<bool> storedObjectToBool(const StoredObject& sobj) { return getPrimitiveHolderData<bool>(sobj); }
return getPrimitiveHolderData<bool>(sobj);
}
sol::optional<double> storedObjectToDouble(const StoredObject& sobj) { sol::optional<double> storedObjectToDouble(const StoredObject& sobj) { return getPrimitiveHolderData<double>(sobj); }
return getPrimitiveHolderData<double>(sobj);
}
sol::optional<std::string> storedObjectToString(const StoredObject& sobj) { sol::optional<std::string> storedObjectToString(const StoredObject& sobj) {
return getPrimitiveHolderData<std::string>(sobj); return getPrimitiveHolderData<std::string>(sobj);

View File

@ -13,7 +13,7 @@ public:
bool compare(const BaseHolder* other) const { bool compare(const BaseHolder* other) const {
if (typeid(*this) == typeid(*other)) if (typeid(*this) == typeid(*other))
return rawCompare(other); return rawCompare(other);
return typeid(*this).before(typeid(*other)); return typeid(*this).before(typeid(*other));
} }
@ -30,17 +30,15 @@ private:
typedef std::unique_ptr<BaseHolder> StoredObject; typedef std::unique_ptr<BaseHolder> StoredObject;
struct StoredObjectLess { struct StoredObjectLess {
bool operator()(const StoredObject& lhs, const StoredObject& rhs) const { bool operator()(const StoredObject& lhs, const StoredObject& rhs) const { return lhs->compare(rhs.get()); }
return lhs->compare(rhs.get());
}
}; };
StoredObject createStoredObject(bool); StoredObject createStoredObject(bool);
StoredObject createStoredObject(double); StoredObject createStoredObject(double);
StoredObject createStoredObject(const std::string&); StoredObject createStoredObject(const std::string&);
StoredObject createStoredObject(GCObjectHandle); StoredObject createStoredObject(GCObjectHandle);
StoredObject createStoredObject(const sol::object &); StoredObject createStoredObject(const sol::object&);
StoredObject createStoredObject(const sol::stack_object &); StoredObject createStoredObject(const sol::stack_object&);
sol::optional<bool> storedObjectToBool(const StoredObject&); sol::optional<bool> storedObjectToBool(const StoredObject&);
sol::optional<double> storedObjectToDouble(const StoredObject&); sol::optional<double> storedObjectToDouble(const StoredObject&);

View File

@ -7,20 +7,15 @@ namespace effil {
class LuaHookStopException : public std::exception {}; class LuaHookStopException : public std::exception {};
std::string threadId() std::string threadId() {
{
std::stringstream ss; std::stringstream ss;
ss << std::this_thread::get_id(); ss << std::this_thread::get_id();
return ss.str(); return ss.str();
} }
void yield() void yield() { std::this_thread::yield(); }
{
std::this_thread::yield();
}
void sleep(int64_t time, sol::optional<std::string> period) void sleep(int64_t time, sol::optional<std::string> period) {
{
std::string metric = period ? period.value() : "s"; std::string metric = period ? period.value() : "s";
if (metric == "ms") if (metric == "ms")
std::this_thread::sleep_for(std::chrono::milliseconds(time)); std::this_thread::sleep_for(std::chrono::milliseconds(time));
@ -36,14 +31,15 @@ thread_local LuaThread::ThreadData* LuaThread::pThreadLocalData = NULL;
// class LuaThread // class LuaThread
LuaThread::LuaThread(std::shared_ptr<ThreadData> threadData, const std::string& function, const sol::variadic_args& args) { LuaThread::LuaThread(std::shared_ptr<ThreadData> threadData, const std::string& function,
const sol::variadic_args& args) {
pThreadData_ = threadData; pThreadData_ = threadData;
assert(pThreadData_); assert(pThreadData_);
pThreadData_->command = ThreadCommand::Nothing; pThreadData_->command = ThreadCommand::Nothing;
pThreadData_->status = ThreadStatus::Running; pThreadData_->status = ThreadStatus::Running;
std::vector<sol::object> arguments; std::vector<sol::object> arguments;
for(const auto& iter: args) { for (const auto& iter : args) {
StoredObject store = createStoredObject(iter.get<sol::object>()); StoredObject store = createStoredObject(iter.get<sol::object>());
arguments.push_back(store->unpack(sol::this_state{pThreadData_->luaState})); arguments.push_back(store->unpack(sol::this_state{pThreadData_->luaState}));
} }
@ -53,57 +49,52 @@ LuaThread::LuaThread(std::shared_ptr<ThreadData> threadData, const std::string&
pThread_->detach(); pThread_->detach();
} }
void LuaThread::luaHook(lua_State*, lua_Debug*) void LuaThread::luaHook(lua_State*, lua_Debug*) {
{ if (pThreadLocalData) {
if (pThreadLocalData) switch (pThreadLocalData->command) {
{ case ThreadCommand::Pause: {
switch (pThreadLocalData->command) pThreadLocalData->status = ThreadStatus::Paused;
{ ThreadCommand cmd = pThreadLocalData->command;
case ThreadCommand::Pause: while (cmd == ThreadCommand::Pause) {
{ std::this_thread::yield();
pThreadLocalData->status = ThreadStatus::Paused; cmd = pThreadLocalData->command;
ThreadCommand cmd = pThreadLocalData->command; }
while (cmd == ThreadCommand::Pause) { assert(cmd != ThreadCommand::Nothing);
std::this_thread::yield(); if (cmd == ThreadCommand::Resume) {
cmd = pThreadLocalData->command; pThreadLocalData->status = ThreadStatus::Running;
break; // Just go out of the function
} else { /* HOOK_STOP - do nothing and go to the next case */
}
} }
assert(cmd != ThreadCommand::Nothing); case ThreadCommand::Cancel:
if (cmd == ThreadCommand::Resume) throw LuaHookStopException();
{ default:
pThreadLocalData->status = ThreadStatus::Running; case ThreadCommand::Nothing:
break; // Just go out of the function break;
}
else { /* HOOK_STOP - do nothing and go to the next case */}
}
case ThreadCommand::Cancel:
throw LuaHookStopException();
default:
case ThreadCommand::Nothing:
break;
} }
} }
} }
void LuaThread::work(std::shared_ptr<ThreadData> threadData, const std::string strFunction, std::vector<sol::object>&& arguments) { void LuaThread::work(std::shared_ptr<ThreadData> threadData, const std::string strFunction,
std::vector<sol::object>&& arguments) {
try { try {
pThreadLocalData = threadData.get(); pThreadLocalData = threadData.get();
assert(threadData); assert(threadData);
const sol::object& stringLoader = threadData->luaState["loadstring"]; const sol::object& stringLoader = threadData->luaState["loadstring"];
REQUIRE(stringLoader.valid() && stringLoader.get_type() == sol::type::function) << "Invalid loadstring function"; REQUIRE(stringLoader.valid() && stringLoader.get_type() == sol::type::function)
<< "Invalid loadstring function";
sol::function userFuncObj = static_cast<const sol::function&>(stringLoader)(strFunction); sol::function userFuncObj = static_cast<const sol::function&>(stringLoader)(strFunction);
sol::function_result results = userFuncObj(sol::as_args(arguments)); sol::function_result results = userFuncObj(sol::as_args(arguments));
(void)results; // TODO: try to avoid use of useless sol::function_result here (void)results; // TODO: try to avoid use of useless sol::function_result here
sol::variadic_args args(threadData->luaState, -lua_gettop(threadData->luaState)); sol::variadic_args args(threadData->luaState, -lua_gettop(threadData->luaState));
for(const auto& iter: args) { for (const auto& iter : args) {
StoredObject store = createStoredObject(iter.get<sol::object>()); StoredObject store = createStoredObject(iter.get<sol::object>());
threadData->results.emplace_back(std::move(store)); threadData->results.emplace_back(std::move(store));
} }
threadData->status = ThreadStatus::Completed; threadData->status = ThreadStatus::Completed;
} } catch (const LuaHookStopException&) {
catch (const LuaHookStopException&) {
threadData->status = ThreadStatus::Canceled; threadData->status = ThreadStatus::Canceled;
} } catch (const sol::error& err) {
catch (const sol::error& err) {
threadData->status = ThreadStatus::Failed; threadData->status = ThreadStatus::Failed;
sol::stack::push(threadData->luaState, err.what()); sol::stack::push(threadData->luaState, err.what());
StoredObject store = createStoredObject(sol::stack::pop<sol::object>(threadData->luaState)); StoredObject store = createStoredObject(sol::stack::pop<sol::object>(threadData->luaState));
@ -111,23 +102,13 @@ void LuaThread::work(std::shared_ptr<ThreadData> threadData, const std::string s
} }
} }
void LuaThread::cancel() void LuaThread::cancel() { pThreadData_->command = ThreadCommand::Cancel; }
{
pThreadData_->command = ThreadCommand::Cancel;
}
void LuaThread::pause() void LuaThread::pause() { pThreadData_->command = ThreadCommand::Pause; }
{
pThreadData_->command = ThreadCommand::Pause;
}
void LuaThread::resume() void LuaThread::resume() { pThreadData_->command = ThreadCommand::Resume; }
{
pThreadData_->command = ThreadCommand::Resume;
}
std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const {
{
ThreadStatus stat = pThreadData_->status; ThreadStatus stat = pThreadData_->status;
while (stat == ThreadStatus::Running) { while (stat == ThreadStatus::Running) {
@ -135,52 +116,49 @@ std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const
stat = pThreadData_->status; stat = pThreadData_->status;
} }
sol::table returns = sol::state_view(state).create_table(); sol::table returns = sol::state_view(state).create_table();
if (stat == ThreadStatus::Completed) if (stat == ThreadStatus::Completed) {
{ for (const StoredObject& obj : pThreadData_->results) {
for (const StoredObject& obj: pThreadData_->results)
{
returns.add(obj->unpack(state)); returns.add(obj->unpack(state));
} }
} }
return std::make_tuple(sol::make_object(state, threadStatusToString(stat)), std::move(returns)); return std::make_tuple(sol::make_object(state, threadStatusToString(stat)), std::move(returns));
} }
std::string LuaThread::threadStatusToString(ThreadStatus stat) const std::string LuaThread::threadStatusToString(ThreadStatus stat) const {
{ switch (stat) {
switch(stat) case ThreadStatus::Running:
{ return "running";
case ThreadStatus::Running: return "running"; case ThreadStatus::Paused:
case ThreadStatus::Paused: return "paused"; return "paused";
case ThreadStatus::Canceled: return "canceled"; case ThreadStatus::Canceled:
case ThreadStatus::Completed: return "completed"; return "canceled";
case ThreadStatus::Failed: return "failed"; case ThreadStatus::Completed:
return "completed";
case ThreadStatus::Failed:
return "failed";
} }
assert(false); assert(false);
return "unknown"; return "unknown";
} }
std::string LuaThread::status() const std::string LuaThread::status() const { return threadStatusToString(pThreadData_->status); }
{
return threadStatusToString(pThreadData_->status);
}
sol::object LuaThread::getUserType(sol::state_view &lua) sol::object LuaThread::getUserType(sol::state_view& lua) {
{ static sol::usertype<LuaThread> type("new", sol::no_constructor, //
static sol::usertype<LuaThread> type( "cancel", &LuaThread::cancel, //
"new", sol::no_constructor, // "pause", &LuaThread::pause, //
"cancel", &LuaThread::cancel, // "resume", &LuaThread::resume, //
"pause", &LuaThread::pause, // "status", &LuaThread::status, //
"resume", &LuaThread::resume, // "wait", &LuaThread::wait);
"status", &LuaThread::status, //
"wait", &LuaThread::wait
);
sol::stack::push(lua, type); sol::stack::push(lua, type);
return sol::stack::pop<sol::object>(lua); return sol::stack::pop<sol::object>(lua);
} }
// class ThreadFactory // class ThreadFactory
ThreadFactory::ThreadFactory(const sol::function& func) : stepwise_(false), step_(100U) { ThreadFactory::ThreadFactory(const sol::function& func)
: stepwise_(false)
, step_(100U) {
sol::state_view lua(func.lua_state()); sol::state_view lua(func.lua_state());
const sol::object& dumper = lua["string"]["dump"]; const sol::object& dumper = lua["string"]["dump"];
REQUIRE(dumper.valid() && dumper.get_type() == sol::type::function) << "Unable to get string.dump()"; REQUIRE(dumper.valid() && dumper.get_type() == sol::type::function) << "Unable to get string.dump()";
@ -194,10 +172,8 @@ ThreadFactory::ThreadFactory(const sol::function& func) : stepwise_(false), step
std::unique_ptr<LuaThread> ThreadFactory::runThread(const sol::variadic_args& args) { std::unique_ptr<LuaThread> ThreadFactory::runThread(const sol::variadic_args& args) {
std::shared_ptr<LuaThread::ThreadData> threadData = std::make_shared<LuaThread::ThreadData>(); std::shared_ptr<LuaThread::ThreadData> threadData = std::make_shared<LuaThread::ThreadData>();
assert(threadData.get()); assert(threadData.get());
threadData->luaState.open_libraries( threadData->luaState.open_libraries(sol::lib::base, sol::lib::string, sol::lib::package, sol::lib::io,
sol::lib::base, sol::lib::string, sol::lib::os);
sol::lib::package, sol::lib::io, sol::lib::os
);
if (stepwise_) if (stepwise_)
lua_sethook(threadData->luaState, LuaThread::luaHook, LUA_MASKCOUNT, step_); lua_sethook(threadData->luaState, LuaThread::luaHook, LUA_MASKCOUNT, step_);
@ -213,48 +189,42 @@ std::unique_ptr<LuaThread> ThreadFactory::runThread(const sol::variadic_args& ar
return std::make_unique<LuaThread>(threadData, strFunction_, args); return std::make_unique<LuaThread>(threadData, strFunction_, args);
} }
bool ThreadFactory::stepwise(const sol::optional<bool>& value) bool ThreadFactory::stepwise(const sol::optional<bool>& value) {
{ bool ret = stepwise_;
bool ret = stepwise_ ;
if (value) if (value)
stepwise_ = value.value(); stepwise_ = value.value();
return ret; return ret;
} }
unsigned int ThreadFactory::step(const sol::optional<unsigned int>& value) unsigned int ThreadFactory::step(const sol::optional<unsigned int>& value) {
{
bool ret = step_; bool ret = step_;
if (value) if (value)
step_ = value.value(); step_ = value.value();
return ret; return ret;
} }
std::string ThreadFactory::packagePath(const sol::optional<std::string>& value) std::string ThreadFactory::packagePath(const sol::optional<std::string>& value) {
{
std::string& ret = packagePath_; std::string& ret = packagePath_;
if (value) if (value)
packagePath_ = value.value(); packagePath_ = value.value();
return ret; return ret;
} }
std::string ThreadFactory::packageCPath(const sol::optional<std::string>& value) std::string ThreadFactory::packageCPath(const sol::optional<std::string>& value) {
{
std::string& ret = packageCPath_; std::string& ret = packageCPath_;
if (value) if (value)
packageCPath_ = value.value(); packageCPath_ = value.value();
return ret; return ret;
} }
sol::object ThreadFactory::getUserType(sol::state_view &lua) sol::object ThreadFactory::getUserType(sol::state_view& lua) {
{ static sol::usertype<ThreadFactory> type("new", sol::no_constructor, //
static sol::usertype<ThreadFactory> type( sol::meta_function::call, &ThreadFactory::runThread, //
"new", sol::no_constructor, // "stepwise", &ThreadFactory::stepwise, //
sol::meta_function::call, &ThreadFactory::runThread,// "step", &ThreadFactory::step, //
"stepwise", &ThreadFactory::stepwise, // "package_path", &ThreadFactory::packagePath, //
"step", &ThreadFactory::step, // "package_cpath", &ThreadFactory::packageCPath //
"package_path", &ThreadFactory::packagePath, // );
"package_cpath", &ThreadFactory::packageCPath //
);
sol::stack::push(lua, type); sol::stack::push(lua, type);
return sol::stack::pop<sol::object>(lua); return sol::stack::pop<sol::object>(lua);
} }

View File

@ -23,15 +23,14 @@ public:
Failed, Failed,
}; };
enum class ThreadCommand enum class ThreadCommand {
{
Nothing = 1, Nothing = 1,
Cancel, Cancel,
Pause, Pause,
Resume, Resume,
}; };
struct ThreadData{ struct ThreadData {
sol::state luaState; sol::state luaState;
std::atomic<ThreadStatus> status; std::atomic<ThreadStatus> status;
std::atomic<ThreadCommand> command; std::atomic<ThreadCommand> command;
@ -39,7 +38,7 @@ public:
}; };
LuaThread(std::shared_ptr<ThreadData> threadData, const std::string& function, const sol::variadic_args& args); LuaThread(std::shared_ptr<ThreadData> threadData, const std::string& function, const sol::variadic_args& args);
static sol::object getUserType(sol::state_view &lua); static sol::object getUserType(sol::state_view& lua);
static void luaHook(lua_State*, lua_Debug*); static void luaHook(lua_State*, lua_Debug*);
/* Public lua methods*/ /* Public lua methods*/
@ -54,7 +53,8 @@ private:
LuaThread& operator=(const LuaThread&) = delete; LuaThread& operator=(const LuaThread&) = delete;
std::string threadStatusToString(ThreadStatus stat) const; std::string threadStatusToString(ThreadStatus stat) const;
static void work(std::shared_ptr<ThreadData> threadData, const std::string strFunction, std::vector<sol::object>&& arguments); static void work(std::shared_ptr<ThreadData> threadData, const std::string strFunction,
std::vector<sol::object>&& arguments);
std::shared_ptr<ThreadData> pThreadData_; std::shared_ptr<ThreadData> pThreadData_;
std::shared_ptr<std::thread> pThread_; std::shared_ptr<std::thread> pThread_;
@ -65,7 +65,7 @@ private:
class ThreadFactory { class ThreadFactory {
public: public:
ThreadFactory(const sol::function& func); ThreadFactory(const sol::function& func);
static sol::object getUserType(sol::state_view &lua); static sol::object getUserType(sol::state_view& lua);
/* Public lua methods*/ /* Public lua methods*/
std::unique_ptr<LuaThread> runThread(const sol::variadic_args& args); std::unique_ptr<LuaThread> runThread(const sol::variadic_args& args);

View File

@ -9,9 +9,10 @@ namespace effil {
class Exception : public sol::error { class Exception : public sol::error {
public: public:
Exception() noexcept : sol::error("") {} Exception() noexcept
: sol::error("") {}
template<typename T> template <typename T>
Exception& operator<<(const T& value) { Exception& operator<<(const T& value) {
std::stringstream ss; std::stringstream ss;
ss << value; ss << value;
@ -19,9 +20,7 @@ public:
return *this; return *this;
} }
virtual const char* what() const noexcept override { virtual const char* what() const noexcept override { return message_.c_str(); }
return message_.c_str();
}
private: private:
std::string message_; std::string message_;
@ -29,10 +28,14 @@ private:
} // effil } // effil
#define REQUIRE(cond) if (!cond) throw effil::Exception() #define REQUIRE(cond) \
if (!cond) \
throw effil::Exception()
#ifdef NDEBUG #ifdef NDEBUG
# define DEBUG if (false) std::cout #define DEBUG \
if (false) \
std::cout
#else #else
# define DEBUG std::cout #define DEBUG std::cout
#endif #endif

View File

@ -29,8 +29,10 @@ TEST(gc, collect) {
ASSERT_EQ(getGC().size(), (size_t)0); ASSERT_EQ(getGC().size(), (size_t)0);
{ {
GCObject o1 = getGC().create<GCObject>();; GCObject o1 = getGC().create<GCObject>();
GCObject o2 = getGC().create<GCObject>();; ;
GCObject o2 = getGC().create<GCObject>();
;
} }
EXPECT_EQ(getGC().size(), (size_t)2); EXPECT_EQ(getGC().size(), (size_t)2);
getGC().cleanup(); getGC().cleanup();
@ -42,7 +44,6 @@ namespace {
struct Dummy : public GCObject { struct Dummy : public GCObject {
void add(GCObjectHandle ref) { refs_->insert(ref); } void add(GCObjectHandle ref) { refs_->insert(ref); }
}; };
} }
TEST(gc, withRefs) { TEST(gc, withRefs) {
@ -52,14 +53,14 @@ TEST(gc, withRefs) {
{ {
Dummy orphan = getGC().create<Dummy>(); Dummy orphan = getGC().create<Dummy>();
for(size_t i = 0; i < 3; i++) { for (size_t i = 0; i < 3; i++) {
Dummy child = getGC().create<Dummy>(); Dummy child = getGC().create<Dummy>();
root.add(child.handle()); root.add(child.handle());
} }
} }
EXPECT_EQ(getGC().size(), (size_t) 5); EXPECT_EQ(getGC().size(), (size_t)5);
getGC().cleanup(); getGC().cleanup();
EXPECT_EQ(getGC().size(), (size_t) 4); EXPECT_EQ(getGC().size(), (size_t)4);
} }
getGC().cleanup(); getGC().cleanup();
EXPECT_EQ(getGC().size(), (size_t)0); EXPECT_EQ(getGC().size(), (size_t)0);
@ -69,13 +70,14 @@ TEST(gc, autoCleanup) {
std::vector<std::thread> threads; std::vector<std::thread> threads;
size_t objectsPerThread = 1000; size_t objectsPerThread = 1000;
for(size_t i = 0; i < 5; i++) for (size_t i = 0; i < 5; i++)
threads.emplace_back([=]{ threads.emplace_back([=] {
for(size_t i = 0; i < objectsPerThread; i++) for (size_t i = 0; i < objectsPerThread; i++)
getGC().create<GCObject>(); getGC().create<GCObject>();
}); });
for(auto& thread : threads) thread.join(); for (auto& thread : threads)
thread.join();
EXPECT_LT(getGC().size(), getGC().step()); EXPECT_LT(getGC().size(), getGC().step());
} }
@ -92,7 +94,7 @@ end
)"); )");
EXPECT_EQ(getGC().size(), (size_t)1001); EXPECT_EQ(getGC().size(), (size_t)1001);
lua.script(R"( lua.script(R"(
for i=1,1000 do for i=1,1000 do
st[i] = nil st[i] = nil
end end

View File

@ -80,16 +80,17 @@ TEST(sharedTable, multipleThreads) {
std::vector<std::thread> threads; std::vector<std::thread> threads;
threads.emplace_back([=](){ threads.emplace_back([=]() {
sol::state lua; sol::state lua;
bootstrapState(lua);; bootstrapState(lua);
;
lua["st"] = st; lua["st"] = st;
lua.script(R"( lua.script(R"(
while not st.ready do end while not st.ready do end
st.fst = true)"); st.fst = true)");
}); });
threads.emplace_back([=](){ threads.emplace_back([=]() {
sol::state lua; sol::state lua;
bootstrapState(lua); bootstrapState(lua);
lua["st"] = st; lua["st"] = st;
@ -98,7 +99,7 @@ while not st.ready do end
st.snd = true)"); st.snd = true)");
}); });
threads.emplace_back([=](){ threads.emplace_back([=]() {
sol::state lua; sol::state lua;
bootstrapState(lua); bootstrapState(lua);
lua["st"] = st; lua["st"] = st;
@ -112,7 +113,9 @@ st.thr = true)");
lua["st"] = st; lua["st"] = st;
lua.script("st.ready = true"); lua.script("st.ready = true");
for(auto& thread : threads) { thread.join(); } for (auto& thread : threads) {
thread.join();
}
EXPECT_EQ(lua["st"]["fst"], true); EXPECT_EQ(lua["st"]["fst"], true);
EXPECT_EQ(lua["st"]["snd"], true); EXPECT_EQ(lua["st"]["snd"], true);
@ -235,7 +238,7 @@ TEST(sharedTable, stressWithThreads) {
const size_t threadCount = 10; const size_t threadCount = 10;
std::vector<std::thread> threads; std::vector<std::thread> threads;
for(size_t i = 0; i < threadCount; i++) { for (size_t i = 0; i < threadCount; i++) {
threads.emplace_back([=] { threads.emplace_back([=] {
sol::state lua; sol::state lua;
bootstrapState(lua); bootstrapState(lua);
@ -243,20 +246,21 @@ TEST(sharedTable, stressWithThreads) {
std::stringstream ss; std::stringstream ss;
ss << "st[" << i << "] = 1" << std::endl; ss << "st[" << i << "] = 1" << std::endl;
ss << "for i = 1, 100000 do" << std::endl; ss << "for i = 1, 100000 do" << std::endl;
ss << " st[" << i << "] = " << "st[" << i << "] + 1" << std::endl; ss << " st[" << i << "] = "
<< "st[" << i << "] + 1" << std::endl;
ss << "end" << std::endl; ss << "end" << std::endl;
lua.script(ss.str()); lua.script(ss.str());
}); });
} }
for(auto& thread : threads) { for (auto& thread : threads) {
thread.join(); thread.join();
} }
sol::state lua; sol::state lua;
bootstrapState(lua); bootstrapState(lua);
lua["st"] = st; lua["st"] = st;
for(size_t i = 0; i < threadCount; i++) { for (size_t i = 0; i < threadCount; i++) {
EXPECT_TRUE(lua["st"][i] == 100'001) << (double)lua["st"][i] << std::endl; EXPECT_TRUE(lua["st"][i] == 100'001) << (double)lua["st"][i] << std::endl;
} }
} }

View File

@ -1,6 +1,6 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
int main(int argc, char **argv) { int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

View File

@ -6,11 +6,7 @@
namespace effil { namespace effil {
inline void bootstrapState(sol::state& lua) { inline void bootstrapState(sol::state& lua) {
lua.open_libraries( lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::table);
sol::lib::base,
sol::lib::string,
sol::lib::table
);
SharedTable::getUserType(lua); SharedTable::getUserType(lua);
} }