Fix codestyle
This commit is contained in:
parent
78f2306657
commit
e8bbb5d293
@ -8,9 +8,9 @@
|
||||
namespace effil {
|
||||
|
||||
GarbageCollector::GarbageCollector()
|
||||
: state_(GCState::Idle),
|
||||
lastCleanup_(0),
|
||||
step_(200) {}
|
||||
: state_(GCState::Idle)
|
||||
, lastCleanup_(0)
|
||||
, step_(200) {}
|
||||
|
||||
GCObject* GarbageCollector::get(GCObjectHandle handle) {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
@ -32,30 +32,30 @@ bool GarbageCollector::has(GCObjectHandle handle) const {
|
||||
void GarbageCollector::cleanup() {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
|
||||
if (state_ == GCState::Stopped) return;
|
||||
if (state_ == GCState::Stopped)
|
||||
return;
|
||||
assert(state_ != GCState::Running);
|
||||
state_ = GCState::Running;
|
||||
|
||||
std::vector<GCObjectHandle> grey;
|
||||
std::map<GCObjectHandle, std::shared_ptr<GCObject>> black;
|
||||
|
||||
for(const auto& handleAndObject : objects_)
|
||||
for (const auto& handleAndObject : objects_)
|
||||
if (handleAndObject.second->instances() > 1)
|
||||
grey.push_back(handleAndObject.first);
|
||||
|
||||
while(!grey.empty()) {
|
||||
while (!grey.empty()) {
|
||||
GCObjectHandle handle = grey.back();
|
||||
grey.pop_back();
|
||||
|
||||
auto object = objects_[handle];
|
||||
black[handle] = object;
|
||||
for(GCObjectHandle refHandle : object->refers())
|
||||
for (GCObjectHandle refHandle : object->refers())
|
||||
if (black.find(refHandle) == black.end())
|
||||
grey.push_back(refHandle);
|
||||
}
|
||||
|
||||
DEBUG << "Removing " << (objects_.size() - black.size())
|
||||
<< " out of " << objects_.size() << std::endl;
|
||||
DEBUG << "Removing " << (objects_.size() - black.size()) << " out of " << objects_.size() << std::endl;
|
||||
// Sweep phase
|
||||
objects_ = std::move(black);
|
||||
|
||||
@ -80,7 +80,6 @@ void GarbageCollector::resume() {
|
||||
state_ = GCState::Idle;
|
||||
}
|
||||
|
||||
|
||||
GarbageCollector& getGC() {
|
||||
static GarbageCollector pool;
|
||||
return pool;
|
||||
|
||||
@ -18,7 +18,8 @@ static const GCObjectHandle GCNull = nullptr;
|
||||
// Child has to care about storing data and concurrent access.
|
||||
class GCObject {
|
||||
public:
|
||||
GCObject() noexcept : refs_(new std::set<GCObjectHandle>) {}
|
||||
GCObject() noexcept
|
||||
: refs_(new std::set<GCObjectHandle>) {}
|
||||
GCObject(const GCObject& init) = default;
|
||||
GCObject(GCObject&& init) = default;
|
||||
virtual ~GCObject() = default;
|
||||
@ -31,11 +32,7 @@ protected:
|
||||
std::shared_ptr<std::set<GCObjectHandle>> refs_;
|
||||
};
|
||||
|
||||
enum class GCState {
|
||||
Idle,
|
||||
Running,
|
||||
Stopped
|
||||
};
|
||||
enum class GCState { Idle, Running, Stopped };
|
||||
|
||||
class GarbageCollector {
|
||||
public:
|
||||
@ -43,9 +40,10 @@ public:
|
||||
~GarbageCollector() = default;
|
||||
|
||||
// This method is used to create all managed objects.
|
||||
template<typename ObjectType,typename... Args>
|
||||
template <typename ObjectType, typename... 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)...);
|
||||
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
@ -75,7 +73,6 @@ private:
|
||||
GarbageCollector(const GarbageCollector&) = delete;
|
||||
};
|
||||
|
||||
|
||||
GarbageCollector& getGC();
|
||||
|
||||
} // effil
|
||||
@ -12,19 +12,16 @@ sol::object createThreadFactory(sol::this_state lua, const sol::function& func)
|
||||
return sol::make_object(lua, std::make_unique<ThreadFactory>(func));
|
||||
}
|
||||
|
||||
sol::object createShare(sol::this_state lua) {
|
||||
return sol::make_object(lua, getGC().create<SharedTable>());
|
||||
}
|
||||
sol::object createShare(sol::this_state lua) { return sol::make_object(lua, getGC().create<SharedTable>()); }
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int luaopen_libeffil(lua_State *L) {
|
||||
extern "C" int luaopen_libeffil(lua_State* L) {
|
||||
sol::state_view lua(L);
|
||||
effil::LuaThread::getUserType(lua);
|
||||
SharedTable::getUserType(lua);
|
||||
ThreadFactory::getUserType(lua);
|
||||
sol::table public_api = lua.create_table_with(
|
||||
"thread", createThreadFactory, //
|
||||
sol::table public_api = lua.create_table_with("thread", createThreadFactory, //
|
||||
"thread_id", threadId, //
|
||||
"sleep", sleep, //
|
||||
"yield", yield, //
|
||||
@ -33,4 +30,3 @@ extern "C" int luaopen_libeffil(lua_State *L) {
|
||||
sol::stack::push(lua, public_api);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -8,21 +8,18 @@
|
||||
namespace effil {
|
||||
|
||||
SharedTable::SharedTable()
|
||||
: GCObject(),
|
||||
data_(std::make_shared<SharedData>()) {
|
||||
}
|
||||
: GCObject()
|
||||
, data_(std::make_shared<SharedData>()) {}
|
||||
|
||||
SharedTable::SharedTable(const SharedTable& init)
|
||||
: GCObject(init),
|
||||
data_(init.data_) {
|
||||
}
|
||||
: GCObject(init)
|
||||
, data_(init.data_) {}
|
||||
|
||||
sol::object SharedTable::getUserType(sol::state_view &lua) {
|
||||
static sol::usertype<SharedTable> type(
|
||||
"new", sol::no_constructor, //
|
||||
sol::meta_function::new_index, &SharedTable::luaSet,//
|
||||
sol::meta_function::index, &SharedTable::luaGet,//
|
||||
sol::meta_function::length, &SharedTable::length,//
|
||||
sol::object SharedTable::getUserType(sol::state_view& lua) {
|
||||
static sol::usertype<SharedTable> type("new", sol::no_constructor, //
|
||||
sol::meta_function::new_index, &SharedTable::luaSet, //
|
||||
sol::meta_function::index, &SharedTable::luaGet, //
|
||||
sol::meta_function::length, &SharedTable::length, //
|
||||
"__pairs", &SharedTable::pairs, //
|
||||
"__ipairs", &SharedTable::ipairs //
|
||||
);
|
||||
@ -33,8 +30,10 @@ sol::object SharedTable::getUserType(sol::state_view &lua) {
|
||||
void SharedTable::set(StoredObject&& key, StoredObject&& value) {
|
||||
std::lock_guard<SpinMutex> g(data_->lock);
|
||||
|
||||
if (key->gcHandle()) refs_->insert(key->gcHandle());
|
||||
if (value->gcHandle()) refs_->insert(value->gcHandle());
|
||||
if (key->gcHandle())
|
||||
refs_->insert(key->gcHandle());
|
||||
if (value->gcHandle())
|
||||
refs_->insert(value->gcHandle());
|
||||
|
||||
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
|
||||
auto it = data_->entries.find(key);
|
||||
if (it != data_->entries.end()) {
|
||||
if (it->first->gcHandle()) refs_->erase(it->first->gcHandle());
|
||||
if (it->second->gcHandle()) refs_->erase(it->second->gcHandle());
|
||||
if (it->first->gcHandle())
|
||||
refs_->erase(it->first->gcHandle());
|
||||
if (it->second->gcHandle())
|
||||
refs_->erase(it->second->gcHandle());
|
||||
data_->entries.erase(it);
|
||||
}
|
||||
|
||||
@ -85,14 +86,12 @@ size_t SharedTable::length() const {
|
||||
size_t len = 0u;
|
||||
sol::optional<double> value;
|
||||
auto iter = data_->entries.find(createStoredObject(static_cast<double>(1)));
|
||||
if (iter != data_->entries.end())
|
||||
{
|
||||
do
|
||||
{
|
||||
if (iter != data_->entries.end()) {
|
||||
do {
|
||||
++len;
|
||||
++iter;
|
||||
}
|
||||
while ((iter != data_->entries.end()) && (value = storedObjectToDouble(iter->first)) && (static_cast<size_t>(value.value()) == len + 1));
|
||||
} while ((iter != data_->entries.end()) && (value = storedObjectToDouble(iter->first)) &&
|
||||
(static_cast<size_t>(value.value()) == len + 1));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@ -104,8 +103,7 @@ SharedTable::PairsIterator SharedTable::getNext(const sol::object& key, sol::thi
|
||||
auto upper = data_->entries.upper_bound(obj);
|
||||
if (upper != data_->entries.end())
|
||||
return std::tuple<sol::object, sol::object>(upper->first->unpack(lua), upper->second->unpack(lua));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!data_->entries.empty()) {
|
||||
const auto& begin = data_->entries.begin();
|
||||
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 {
|
||||
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>(
|
||||
sol::make_object(lua, std::function<PairsIterator(sol::this_state lua, SharedTable table, sol::stack_object key)>(next)).as<sol::function>(),
|
||||
sol::make_object(lua, *this)
|
||||
);
|
||||
sol::make_object(
|
||||
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;
|
||||
auto objKey = createStoredObject(static_cast<double>(index));
|
||||
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 {
|
||||
return std::tuple<sol::function, sol::object>(
|
||||
sol::make_object(lua, ipairsNext).as<sol::function>(),
|
||||
sol::make_object(lua, *this)
|
||||
);
|
||||
return std::tuple<sol::function, sol::object>(sol::make_object(lua, ipairsNext).as<sol::function>(),
|
||||
sol::make_object(lua, *this));
|
||||
}
|
||||
|
||||
} // effil
|
||||
|
||||
@ -22,7 +22,7 @@ public:
|
||||
SharedTable(const SharedTable& init);
|
||||
virtual ~SharedTable() = default;
|
||||
|
||||
static sol::object getUserType(sol::state_view &lua);
|
||||
static sol::object getUserType(sol::state_view& lua);
|
||||
void set(StoredObject&&, StoredObject&&);
|
||||
sol::object get(const StoredObject& key, const sol::this_state& state) const;
|
||||
PairsIterator getNext(const sol::object& key, sol::this_state lua);
|
||||
@ -36,7 +36,6 @@ public:
|
||||
PairsIterator ipairs(sol::this_state) const;
|
||||
|
||||
private:
|
||||
|
||||
struct SharedData {
|
||||
SpinMutex lock;
|
||||
DataEntries entries;
|
||||
@ -46,4 +45,3 @@ private:
|
||||
};
|
||||
|
||||
} // effil
|
||||
|
||||
|
||||
@ -8,14 +8,12 @@ namespace effil {
|
||||
class SpinMutex {
|
||||
public:
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
lock_.clear(std::memory_order_release);
|
||||
}
|
||||
void unlock() noexcept { lock_.clear(std::memory_order_release); }
|
||||
|
||||
private:
|
||||
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
|
||||
|
||||
@ -13,7 +13,7 @@ namespace effil {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename StoredType>
|
||||
template <typename StoredType>
|
||||
class PrimitiveHolder : public BaseHolder {
|
||||
public:
|
||||
PrimitiveHolder(const sol::stack_object& luaObject) noexcept
|
||||
@ -29,9 +29,7 @@ public:
|
||||
return data_ < static_cast<const PrimitiveHolder<StoredType>*>(other)->data_;
|
||||
}
|
||||
|
||||
sol::object unpack(sol::this_state state) const final {
|
||||
return sol::make_object(state, data_);
|
||||
}
|
||||
sol::object unpack(sol::this_state state) const final { return sol::make_object(state, data_); }
|
||||
|
||||
StoredType getData() { return data_; }
|
||||
|
||||
@ -41,11 +39,12 @@ private:
|
||||
|
||||
class FunctionHolder : public BaseHolder {
|
||||
public:
|
||||
template<typename SolObject>
|
||||
template <typename SolObject>
|
||||
FunctionHolder(SolObject luaObject) noexcept {
|
||||
sol::state_view lua(luaObject.lua_state());
|
||||
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);
|
||||
}
|
||||
|
||||
@ -69,7 +68,7 @@ private:
|
||||
|
||||
class TableHolder : public BaseHolder {
|
||||
public:
|
||||
template<typename SolType>
|
||||
template <typename SolType>
|
||||
TableHolder(const SolType& luaObject) {
|
||||
assert(luaObject.template is<SharedTable>());
|
||||
handle_ = luaObject.template as<SharedTable>().handle();
|
||||
@ -79,7 +78,7 @@ public:
|
||||
TableHolder(GCObjectHandle 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_;
|
||||
}
|
||||
|
||||
@ -103,7 +102,7 @@ void dumpTable(SharedTable* target, sol::table luaTable, SolTableToShared& visit
|
||||
StoredObject makeStoredObject(sol::object luaObject, SolTableToShared& visited) {
|
||||
if (luaObject.get_type() == sol::type::table) {
|
||||
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;
|
||||
};
|
||||
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) {
|
||||
for(auto& row : luaTable) {
|
||||
for (auto& row : luaTable) {
|
||||
target->set(makeStoredObject(row.first, visited), makeStoredObject(row.second, visited));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename SolObject>
|
||||
template <typename SolObject>
|
||||
StoredObject fromSolObject(const SolObject& luaObject) {
|
||||
switch(luaObject.get_type()) {
|
||||
switch (luaObject.get_type()) {
|
||||
case sol::type::nil:
|
||||
break;
|
||||
case sol::type::boolean:
|
||||
@ -142,8 +141,7 @@ StoredObject fromSolObject(const SolObject& luaObject) {
|
||||
return std::make_unique<TableHolder>(luaObject);
|
||||
case sol::type::function:
|
||||
return std::make_unique<FunctionHolder>(luaObject);
|
||||
case sol::type::table:
|
||||
{
|
||||
case sol::type::table: {
|
||||
sol::table luaTable = luaObject;
|
||||
// Tables pool is used to store tables.
|
||||
// Right now not defiantly clear how ownership between states works.
|
||||
@ -164,31 +162,21 @@ StoredObject fromSolObject(const SolObject& luaObject) {
|
||||
|
||||
} // namespace
|
||||
|
||||
StoredObject createStoredObject(bool value) {
|
||||
return std::make_unique<PrimitiveHolder<bool>>(value);
|
||||
}
|
||||
StoredObject createStoredObject(bool value) { return std::make_unique<PrimitiveHolder<bool>>(value); }
|
||||
|
||||
StoredObject createStoredObject(double value) {
|
||||
return std::make_unique<PrimitiveHolder<double>>(value);
|
||||
}
|
||||
StoredObject createStoredObject(double value) { return std::make_unique<PrimitiveHolder<double>>(value); }
|
||||
|
||||
StoredObject createStoredObject(const std::string& value) {
|
||||
return std::make_unique<PrimitiveHolder<std::string>>(value);
|
||||
}
|
||||
|
||||
StoredObject createStoredObject(const sol::object &object) {
|
||||
return fromSolObject(object);
|
||||
}
|
||||
StoredObject createStoredObject(const sol::object& object) { return fromSolObject(object); }
|
||||
|
||||
StoredObject createStoredObject(const sol::stack_object &object) {
|
||||
return fromSolObject(object);
|
||||
}
|
||||
StoredObject createStoredObject(const sol::stack_object& object) { return fromSolObject(object); }
|
||||
|
||||
StoredObject createStoredObject(GCObjectHandle handle) {
|
||||
return std::make_unique<TableHolder>(handle);
|
||||
}
|
||||
StoredObject createStoredObject(GCObjectHandle handle) { return std::make_unique<TableHolder>(handle); }
|
||||
|
||||
template<typename DataType>
|
||||
template <typename DataType>
|
||||
sol::optional<DataType> getPrimitiveHolderData(const StoredObject& sobj) {
|
||||
auto ptr = dynamic_cast<PrimitiveHolder<DataType>*>(sobj.get());
|
||||
if (ptr)
|
||||
@ -196,13 +184,9 @@ sol::optional<DataType> getPrimitiveHolderData(const StoredObject& sobj) {
|
||||
return sol::optional<DataType>();
|
||||
}
|
||||
|
||||
sol::optional<bool> storedObjectToBool(const StoredObject& sobj) {
|
||||
return getPrimitiveHolderData<bool>(sobj);
|
||||
}
|
||||
sol::optional<bool> storedObjectToBool(const StoredObject& sobj) { return getPrimitiveHolderData<bool>(sobj); }
|
||||
|
||||
sol::optional<double> storedObjectToDouble(const StoredObject& sobj) {
|
||||
return getPrimitiveHolderData<double>(sobj);
|
||||
}
|
||||
sol::optional<double> storedObjectToDouble(const StoredObject& sobj) { return getPrimitiveHolderData<double>(sobj); }
|
||||
|
||||
sol::optional<std::string> storedObjectToString(const StoredObject& sobj) {
|
||||
return getPrimitiveHolderData<std::string>(sobj);
|
||||
|
||||
@ -30,17 +30,15 @@ private:
|
||||
typedef std::unique_ptr<BaseHolder> StoredObject;
|
||||
|
||||
struct StoredObjectLess {
|
||||
bool operator()(const StoredObject& lhs, const StoredObject& rhs) const {
|
||||
return lhs->compare(rhs.get());
|
||||
}
|
||||
bool operator()(const StoredObject& lhs, const StoredObject& rhs) const { return lhs->compare(rhs.get()); }
|
||||
};
|
||||
|
||||
StoredObject createStoredObject(bool);
|
||||
StoredObject createStoredObject(double);
|
||||
StoredObject createStoredObject(const std::string&);
|
||||
StoredObject createStoredObject(GCObjectHandle);
|
||||
StoredObject createStoredObject(const sol::object &);
|
||||
StoredObject createStoredObject(const sol::stack_object &);
|
||||
StoredObject createStoredObject(const sol::object&);
|
||||
StoredObject createStoredObject(const sol::stack_object&);
|
||||
|
||||
sol::optional<bool> storedObjectToBool(const StoredObject&);
|
||||
sol::optional<double> storedObjectToDouble(const StoredObject&);
|
||||
|
||||
@ -7,20 +7,15 @@ namespace effil {
|
||||
|
||||
class LuaHookStopException : public std::exception {};
|
||||
|
||||
std::string threadId()
|
||||
{
|
||||
std::string threadId() {
|
||||
std::stringstream ss;
|
||||
ss << std::this_thread::get_id();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void yield()
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
void 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";
|
||||
if (metric == "ms")
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(time));
|
||||
@ -36,14 +31,15 @@ thread_local LuaThread::ThreadData* LuaThread::pThreadLocalData = NULL;
|
||||
|
||||
// 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;
|
||||
assert(pThreadData_);
|
||||
pThreadData_->command = ThreadCommand::Nothing;
|
||||
pThreadData_->status = ThreadStatus::Running;
|
||||
|
||||
std::vector<sol::object> arguments;
|
||||
for(const auto& iter: args) {
|
||||
for (const auto& iter : args) {
|
||||
StoredObject store = createStoredObject(iter.get<sol::object>());
|
||||
arguments.push_back(store->unpack(sol::this_state{pThreadData_->luaState}));
|
||||
}
|
||||
@ -53,14 +49,10 @@ LuaThread::LuaThread(std::shared_ptr<ThreadData> threadData, const std::string&
|
||||
pThread_->detach();
|
||||
}
|
||||
|
||||
void LuaThread::luaHook(lua_State*, lua_Debug*)
|
||||
{
|
||||
if (pThreadLocalData)
|
||||
{
|
||||
switch (pThreadLocalData->command)
|
||||
{
|
||||
case ThreadCommand::Pause:
|
||||
{
|
||||
void LuaThread::luaHook(lua_State*, lua_Debug*) {
|
||||
if (pThreadLocalData) {
|
||||
switch (pThreadLocalData->command) {
|
||||
case ThreadCommand::Pause: {
|
||||
pThreadLocalData->status = ThreadStatus::Paused;
|
||||
ThreadCommand cmd = pThreadLocalData->command;
|
||||
while (cmd == ThreadCommand::Pause) {
|
||||
@ -68,12 +60,11 @@ void LuaThread::luaHook(lua_State*, lua_Debug*)
|
||||
cmd = pThreadLocalData->command;
|
||||
}
|
||||
assert(cmd != ThreadCommand::Nothing);
|
||||
if (cmd == ThreadCommand::Resume)
|
||||
{
|
||||
if (cmd == ThreadCommand::Resume) {
|
||||
pThreadLocalData->status = ThreadStatus::Running;
|
||||
break; // Just go out of the function
|
||||
} else { /* HOOK_STOP - do nothing and go to the next case */
|
||||
}
|
||||
else { /* HOOK_STOP - do nothing and go to the next case */}
|
||||
}
|
||||
case ThreadCommand::Cancel:
|
||||
throw LuaHookStopException();
|
||||
@ -84,26 +75,26 @@ void LuaThread::luaHook(lua_State*, lua_Debug*)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
pThreadLocalData = threadData.get();
|
||||
assert(threadData);
|
||||
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_result results = userFuncObj(sol::as_args(arguments));
|
||||
(void)results; // TODO: try to avoid use of useless sol::function_result here
|
||||
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>());
|
||||
threadData->results.emplace_back(std::move(store));
|
||||
}
|
||||
threadData->status = ThreadStatus::Completed;
|
||||
}
|
||||
catch (const LuaHookStopException&) {
|
||||
} catch (const LuaHookStopException&) {
|
||||
threadData->status = ThreadStatus::Canceled;
|
||||
}
|
||||
catch (const sol::error& err) {
|
||||
} catch (const sol::error& err) {
|
||||
threadData->status = ThreadStatus::Failed;
|
||||
sol::stack::push(threadData->luaState, err.what());
|
||||
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()
|
||||
{
|
||||
pThreadData_->command = ThreadCommand::Cancel;
|
||||
}
|
||||
void LuaThread::cancel() { pThreadData_->command = ThreadCommand::Cancel; }
|
||||
|
||||
void LuaThread::pause()
|
||||
{
|
||||
pThreadData_->command = ThreadCommand::Pause;
|
||||
}
|
||||
void LuaThread::pause() { pThreadData_->command = ThreadCommand::Pause; }
|
||||
|
||||
void LuaThread::resume()
|
||||
{
|
||||
pThreadData_->command = ThreadCommand::Resume;
|
||||
}
|
||||
void LuaThread::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;
|
||||
while (stat == ThreadStatus::Running) {
|
||||
@ -135,52 +116,49 @@ std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const
|
||||
stat = pThreadData_->status;
|
||||
}
|
||||
sol::table returns = sol::state_view(state).create_table();
|
||||
if (stat == ThreadStatus::Completed)
|
||||
{
|
||||
for (const StoredObject& obj: pThreadData_->results)
|
||||
{
|
||||
if (stat == ThreadStatus::Completed) {
|
||||
for (const StoredObject& obj : pThreadData_->results) {
|
||||
returns.add(obj->unpack(state));
|
||||
}
|
||||
}
|
||||
return std::make_tuple(sol::make_object(state, threadStatusToString(stat)), std::move(returns));
|
||||
}
|
||||
|
||||
std::string LuaThread::threadStatusToString(ThreadStatus stat) const
|
||||
{
|
||||
switch(stat)
|
||||
{
|
||||
case ThreadStatus::Running: return "running";
|
||||
case ThreadStatus::Paused: return "paused";
|
||||
case ThreadStatus::Canceled: return "canceled";
|
||||
case ThreadStatus::Completed: return "completed";
|
||||
case ThreadStatus::Failed: return "failed";
|
||||
std::string LuaThread::threadStatusToString(ThreadStatus stat) const {
|
||||
switch (stat) {
|
||||
case ThreadStatus::Running:
|
||||
return "running";
|
||||
case ThreadStatus::Paused:
|
||||
return "paused";
|
||||
case ThreadStatus::Canceled:
|
||||
return "canceled";
|
||||
case ThreadStatus::Completed:
|
||||
return "completed";
|
||||
case ThreadStatus::Failed:
|
||||
return "failed";
|
||||
}
|
||||
assert(false);
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string LuaThread::status() const
|
||||
{
|
||||
return threadStatusToString(pThreadData_->status);
|
||||
}
|
||||
std::string LuaThread::status() const { return threadStatusToString(pThreadData_->status); }
|
||||
|
||||
sol::object LuaThread::getUserType(sol::state_view &lua)
|
||||
{
|
||||
static sol::usertype<LuaThread> type(
|
||||
"new", sol::no_constructor, //
|
||||
sol::object LuaThread::getUserType(sol::state_view& lua) {
|
||||
static sol::usertype<LuaThread> type("new", sol::no_constructor, //
|
||||
"cancel", &LuaThread::cancel, //
|
||||
"pause", &LuaThread::pause, //
|
||||
"resume", &LuaThread::resume, //
|
||||
"status", &LuaThread::status, //
|
||||
"wait", &LuaThread::wait
|
||||
);
|
||||
"wait", &LuaThread::wait);
|
||||
sol::stack::push(lua, type);
|
||||
return sol::stack::pop<sol::object>(lua);
|
||||
}
|
||||
|
||||
// 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());
|
||||
const sol::object& dumper = lua["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::shared_ptr<LuaThread::ThreadData> threadData = std::make_shared<LuaThread::ThreadData>();
|
||||
assert(threadData.get());
|
||||
threadData->luaState.open_libraries(
|
||||
sol::lib::base, sol::lib::string,
|
||||
sol::lib::package, sol::lib::io, sol::lib::os
|
||||
);
|
||||
threadData->luaState.open_libraries(sol::lib::base, sol::lib::string, sol::lib::package, sol::lib::io,
|
||||
sol::lib::os);
|
||||
|
||||
if (stepwise_)
|
||||
lua_sethook(threadData->luaState, LuaThread::luaHook, LUA_MASKCOUNT, step_);
|
||||
@ -213,43 +189,37 @@ std::unique_ptr<LuaThread> ThreadFactory::runThread(const sol::variadic_args& ar
|
||||
return std::make_unique<LuaThread>(threadData, strFunction_, args);
|
||||
}
|
||||
|
||||
bool ThreadFactory::stepwise(const sol::optional<bool>& value)
|
||||
{
|
||||
bool ret = stepwise_ ;
|
||||
bool ThreadFactory::stepwise(const sol::optional<bool>& value) {
|
||||
bool ret = stepwise_;
|
||||
if (value)
|
||||
stepwise_ = value.value();
|
||||
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_;
|
||||
if (value)
|
||||
step_ = value.value();
|
||||
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_;
|
||||
if (value)
|
||||
packagePath_ = value.value();
|
||||
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_;
|
||||
if (value)
|
||||
packageCPath_ = value.value();
|
||||
return ret;
|
||||
}
|
||||
|
||||
sol::object ThreadFactory::getUserType(sol::state_view &lua)
|
||||
{
|
||||
static sol::usertype<ThreadFactory> type(
|
||||
"new", sol::no_constructor, //
|
||||
sol::meta_function::call, &ThreadFactory::runThread,//
|
||||
sol::object ThreadFactory::getUserType(sol::state_view& lua) {
|
||||
static sol::usertype<ThreadFactory> type("new", sol::no_constructor, //
|
||||
sol::meta_function::call, &ThreadFactory::runThread, //
|
||||
"stepwise", &ThreadFactory::stepwise, //
|
||||
"step", &ThreadFactory::step, //
|
||||
"package_path", &ThreadFactory::packagePath, //
|
||||
|
||||
@ -23,15 +23,14 @@ public:
|
||||
Failed,
|
||||
};
|
||||
|
||||
enum class ThreadCommand
|
||||
{
|
||||
enum class ThreadCommand {
|
||||
Nothing = 1,
|
||||
Cancel,
|
||||
Pause,
|
||||
Resume,
|
||||
};
|
||||
|
||||
struct ThreadData{
|
||||
struct ThreadData {
|
||||
sol::state luaState;
|
||||
std::atomic<ThreadStatus> status;
|
||||
std::atomic<ThreadCommand> command;
|
||||
@ -39,7 +38,7 @@ public:
|
||||
};
|
||||
|
||||
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*);
|
||||
|
||||
/* Public lua methods*/
|
||||
@ -54,7 +53,8 @@ private:
|
||||
LuaThread& operator=(const LuaThread&) = delete;
|
||||
|
||||
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<std::thread> pThread_;
|
||||
@ -65,7 +65,7 @@ private:
|
||||
class ThreadFactory {
|
||||
public:
|
||||
ThreadFactory(const sol::function& func);
|
||||
static sol::object getUserType(sol::state_view &lua);
|
||||
static sol::object getUserType(sol::state_view& lua);
|
||||
|
||||
/* Public lua methods*/
|
||||
std::unique_ptr<LuaThread> runThread(const sol::variadic_args& args);
|
||||
|
||||
@ -9,9 +9,10 @@ namespace effil {
|
||||
|
||||
class Exception : public sol::error {
|
||||
public:
|
||||
Exception() noexcept : sol::error("") {}
|
||||
Exception() noexcept
|
||||
: sol::error("") {}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
Exception& operator<<(const T& value) {
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
@ -19,9 +20,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual const char* what() const noexcept override {
|
||||
return message_.c_str();
|
||||
}
|
||||
virtual const char* what() const noexcept override { return message_.c_str(); }
|
||||
|
||||
private:
|
||||
std::string message_;
|
||||
@ -29,10 +28,14 @@ private:
|
||||
|
||||
} // effil
|
||||
|
||||
#define REQUIRE(cond) if (!cond) throw effil::Exception()
|
||||
#define REQUIRE(cond) \
|
||||
if (!cond) \
|
||||
throw effil::Exception()
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define DEBUG if (false) std::cout
|
||||
#define DEBUG \
|
||||
if (false) \
|
||||
std::cout
|
||||
#else
|
||||
# define DEBUG std::cout
|
||||
#define DEBUG std::cout
|
||||
#endif
|
||||
|
||||
@ -29,8 +29,10 @@ TEST(gc, collect) {
|
||||
ASSERT_EQ(getGC().size(), (size_t)0);
|
||||
|
||||
{
|
||||
GCObject o1 = getGC().create<GCObject>();;
|
||||
GCObject o2 = getGC().create<GCObject>();;
|
||||
GCObject o1 = getGC().create<GCObject>();
|
||||
;
|
||||
GCObject o2 = getGC().create<GCObject>();
|
||||
;
|
||||
}
|
||||
EXPECT_EQ(getGC().size(), (size_t)2);
|
||||
getGC().cleanup();
|
||||
@ -42,7 +44,6 @@ namespace {
|
||||
struct Dummy : public GCObject {
|
||||
void add(GCObjectHandle ref) { refs_->insert(ref); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(gc, withRefs) {
|
||||
@ -52,14 +53,14 @@ TEST(gc, withRefs) {
|
||||
|
||||
{
|
||||
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>();
|
||||
root.add(child.handle());
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(getGC().size(), (size_t) 5);
|
||||
EXPECT_EQ(getGC().size(), (size_t)5);
|
||||
getGC().cleanup();
|
||||
EXPECT_EQ(getGC().size(), (size_t) 4);
|
||||
EXPECT_EQ(getGC().size(), (size_t)4);
|
||||
}
|
||||
getGC().cleanup();
|
||||
EXPECT_EQ(getGC().size(), (size_t)0);
|
||||
@ -69,13 +70,14 @@ TEST(gc, autoCleanup) {
|
||||
std::vector<std::thread> threads;
|
||||
size_t objectsPerThread = 1000;
|
||||
|
||||
for(size_t i = 0; i < 5; i++)
|
||||
threads.emplace_back([=]{
|
||||
for(size_t i = 0; i < objectsPerThread; i++)
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
threads.emplace_back([=] {
|
||||
for (size_t i = 0; i < objectsPerThread; i++)
|
||||
getGC().create<GCObject>();
|
||||
});
|
||||
|
||||
for(auto& thread : threads) thread.join();
|
||||
for (auto& thread : threads)
|
||||
thread.join();
|
||||
|
||||
EXPECT_LT(getGC().size(), getGC().step());
|
||||
}
|
||||
@ -92,7 +94,7 @@ end
|
||||
)");
|
||||
EXPECT_EQ(getGC().size(), (size_t)1001);
|
||||
|
||||
lua.script(R"(
|
||||
lua.script(R"(
|
||||
for i=1,1000 do
|
||||
st[i] = nil
|
||||
end
|
||||
|
||||
@ -80,16 +80,17 @@ TEST(sharedTable, multipleThreads) {
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
threads.emplace_back([=](){
|
||||
threads.emplace_back([=]() {
|
||||
sol::state lua;
|
||||
bootstrapState(lua);;
|
||||
bootstrapState(lua);
|
||||
;
|
||||
lua["st"] = st;
|
||||
lua.script(R"(
|
||||
while not st.ready do end
|
||||
st.fst = true)");
|
||||
});
|
||||
|
||||
threads.emplace_back([=](){
|
||||
threads.emplace_back([=]() {
|
||||
sol::state lua;
|
||||
bootstrapState(lua);
|
||||
lua["st"] = st;
|
||||
@ -98,7 +99,7 @@ while not st.ready do end
|
||||
st.snd = true)");
|
||||
});
|
||||
|
||||
threads.emplace_back([=](){
|
||||
threads.emplace_back([=]() {
|
||||
sol::state lua;
|
||||
bootstrapState(lua);
|
||||
lua["st"] = st;
|
||||
@ -112,7 +113,9 @@ st.thr = true)");
|
||||
lua["st"] = st;
|
||||
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"]["snd"], true);
|
||||
@ -235,7 +238,7 @@ TEST(sharedTable, stressWithThreads) {
|
||||
|
||||
const size_t threadCount = 10;
|
||||
std::vector<std::thread> threads;
|
||||
for(size_t i = 0; i < threadCount; i++) {
|
||||
for (size_t i = 0; i < threadCount; i++) {
|
||||
threads.emplace_back([=] {
|
||||
sol::state lua;
|
||||
bootstrapState(lua);
|
||||
@ -243,20 +246,21 @@ TEST(sharedTable, stressWithThreads) {
|
||||
std::stringstream ss;
|
||||
ss << "st[" << i << "] = 1" << 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;
|
||||
lua.script(ss.str());
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& thread : threads) {
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
sol::state lua;
|
||||
bootstrapState(lua);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@ -6,11 +6,7 @@
|
||||
namespace effil {
|
||||
|
||||
inline void bootstrapState(sol::state& lua) {
|
||||
lua.open_libraries(
|
||||
sol::lib::base,
|
||||
sol::lib::string,
|
||||
sol::lib::table
|
||||
);
|
||||
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::table);
|
||||
SharedTable::getUserType(lua);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user