Fix codestyle
This commit is contained in:
parent
78f2306657
commit
e8bbb5d293
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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&);
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user