Robust exception handling
This commit is contained in:
parent
9f5267e23b
commit
3310901ce3
@ -7,12 +7,12 @@
|
||||
|
||||
namespace effil {
|
||||
|
||||
GarbageCollector::GarbageCollector() noexcept
|
||||
GarbageCollector::GarbageCollector()
|
||||
: state_(GCState::Idle),
|
||||
lastCleanup_(0),
|
||||
step_(200) {}
|
||||
|
||||
GCObject* GarbageCollector::get(GCObjectHandle handle) noexcept {
|
||||
GCObject* GarbageCollector::get(GCObjectHandle handle) {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
auto it = objects_.find(handle);
|
||||
if (it == objects_.end()) {
|
||||
@ -22,7 +22,7 @@ GCObject* GarbageCollector::get(GCObjectHandle handle) noexcept {
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
bool GarbageCollector::has(GCObjectHandle handle) const noexcept {
|
||||
bool GarbageCollector::has(GCObjectHandle handle) const {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
return objects_.find(handle) != objects_.end();
|
||||
}
|
||||
@ -63,25 +63,25 @@ void GarbageCollector::cleanup() {
|
||||
lastCleanup_.store(0);
|
||||
}
|
||||
|
||||
size_t GarbageCollector::size() const noexcept {
|
||||
size_t GarbageCollector::size() const {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
return objects_.size();
|
||||
}
|
||||
|
||||
void GarbageCollector::stop() noexcept {
|
||||
void GarbageCollector::stop() {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
assert(state_ == GCState::Idle || state_ == GCState::Stopped);
|
||||
state_ = GCState::Stopped;
|
||||
}
|
||||
|
||||
void GarbageCollector::resume() noexcept {
|
||||
void GarbageCollector::resume() {
|
||||
std::lock_guard<std::mutex> g(lock_);
|
||||
assert(state_ == GCState::Idle || state_ == GCState::Stopped);
|
||||
state_ = GCState::Idle;
|
||||
}
|
||||
|
||||
|
||||
GarbageCollector& getGC() noexcept {
|
||||
GarbageCollector& getGC() {
|
||||
static GarbageCollector pool;
|
||||
return pool;
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ enum class GCState {
|
||||
|
||||
class GarbageCollector {
|
||||
public:
|
||||
GarbageCollector() noexcept;
|
||||
GarbageCollector();
|
||||
~GarbageCollector() = default;
|
||||
|
||||
// This method is used to create all managed objects.
|
||||
@ -53,15 +53,15 @@ public:
|
||||
return *object;
|
||||
}
|
||||
|
||||
GCObject* get(GCObjectHandle handle) noexcept;
|
||||
bool has(GCObjectHandle handle) const noexcept;
|
||||
GCObject* get(GCObjectHandle handle);
|
||||
bool has(GCObjectHandle handle) const;
|
||||
void cleanup();
|
||||
size_t size() const noexcept;
|
||||
void stop() noexcept;
|
||||
void resume() noexcept;
|
||||
size_t step() const noexcept { return step_; }
|
||||
void step(size_t newStep) noexcept { step_ = newStep; }
|
||||
GCState state() const noexcept { return state_; }
|
||||
size_t size() const;
|
||||
void stop();
|
||||
void resume();
|
||||
size_t step() const { return step_; }
|
||||
void step(size_t newStep) { step_ = newStep; }
|
||||
GCState state() const { return state_; }
|
||||
|
||||
private:
|
||||
mutable std::mutex lock_;
|
||||
@ -76,6 +76,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
GarbageCollector& getGC() noexcept;
|
||||
GarbageCollector& getGC();
|
||||
|
||||
} // effil
|
||||
@ -7,17 +7,17 @@
|
||||
|
||||
namespace effil {
|
||||
|
||||
SharedTable::SharedTable() noexcept
|
||||
SharedTable::SharedTable()
|
||||
: GCObject(),
|
||||
data_(std::make_shared<SharedData>()) {
|
||||
}
|
||||
|
||||
SharedTable::SharedTable(const SharedTable& init) noexcept
|
||||
SharedTable::SharedTable(const SharedTable& init)
|
||||
: GCObject(init),
|
||||
data_(init.data_) {
|
||||
}
|
||||
|
||||
sol::object SharedTable::getUserType(sol::state_view &lua) noexcept {
|
||||
sol::object SharedTable::getUserType(sol::state_view &lua) {
|
||||
static sol::usertype<SharedTable> type(
|
||||
"new", sol::no_constructor,
|
||||
sol::meta_function::new_index, &SharedTable::luaSet,
|
||||
@ -28,7 +28,7 @@ sol::object SharedTable::getUserType(sol::state_view &lua) noexcept {
|
||||
return sol::stack::pop<sol::object>(lua);
|
||||
}
|
||||
|
||||
void SharedTable::set(StoredObject&& key, StoredObject&& value) noexcept {
|
||||
void SharedTable::set(StoredObject&& key, StoredObject&& value) {
|
||||
std::lock_guard<SpinMutex> g(data_->lock);
|
||||
|
||||
if (key->gcHandle()) refs_->insert(key->gcHandle());
|
||||
@ -38,7 +38,7 @@ void SharedTable::set(StoredObject&& key, StoredObject&& value) noexcept {
|
||||
}
|
||||
|
||||
void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue) {
|
||||
ASSERT(luaKey.valid()) << "Invalid table index";
|
||||
REQUIRE(luaKey.valid()) << "Indexing by nil";
|
||||
|
||||
StoredObject key = createStoredObject(luaKey);
|
||||
if (luaValue.get_type() == sol::type::nil) {
|
||||
@ -57,12 +57,12 @@ void SharedTable::luaSet(const sol::stack_object& luaKey, const sol::stack_objec
|
||||
}
|
||||
}
|
||||
|
||||
sol::object SharedTable::luaGet(const sol::stack_object& key, const sol::this_state& state) const {
|
||||
ASSERT(key.valid());
|
||||
sol::object SharedTable::luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const {
|
||||
REQUIRE(luaKey.valid()) << "Indexing by nil";
|
||||
|
||||
StoredObject cppKey = createStoredObject(key);
|
||||
StoredObject key = createStoredObject(luaKey);
|
||||
std::lock_guard<SpinMutex> g(data_->lock);
|
||||
auto val = data_->entries.find(cppKey);
|
||||
auto val = data_->entries.find(key);
|
||||
if (val == data_->entries.end()) {
|
||||
return sol::nil;
|
||||
} else {
|
||||
@ -70,7 +70,7 @@ sol::object SharedTable::luaGet(const sol::stack_object& key, const sol::this_st
|
||||
}
|
||||
}
|
||||
|
||||
size_t SharedTable::size() const noexcept {
|
||||
size_t SharedTable::size() const {
|
||||
std::lock_guard<SpinMutex> g(data_->lock);
|
||||
return data_->entries.size();
|
||||
}
|
||||
|
||||
@ -13,18 +13,18 @@ namespace effil {
|
||||
|
||||
class SharedTable : public GCObject {
|
||||
public:
|
||||
SharedTable() noexcept;
|
||||
SharedTable();
|
||||
SharedTable(SharedTable&&) = default;
|
||||
SharedTable(const SharedTable& init) noexcept;
|
||||
SharedTable(const SharedTable& init);
|
||||
virtual ~SharedTable() = default;
|
||||
|
||||
static sol::object getUserType(sol::state_view &lua) noexcept;
|
||||
void set(StoredObject&&, StoredObject&&) noexcept;
|
||||
static sol::object getUserType(sol::state_view &lua);
|
||||
void set(StoredObject&&, StoredObject&&);
|
||||
|
||||
// These functions could be invoked from lua scripts
|
||||
void luaSet(const sol::stack_object& luaKey, const sol::stack_object& luaValue);
|
||||
sol::object luaGet(const sol::stack_object& key, const sol::this_state& state) const;
|
||||
size_t size() const noexcept;
|
||||
sol::object luaGet(const sol::stack_object& luaKey, const sol::this_state& state) const;
|
||||
size_t size() const;
|
||||
|
||||
private:
|
||||
typedef std::unique_ptr<BaseHolder> StoredObject;
|
||||
|
||||
@ -47,7 +47,7 @@ public:
|
||||
FunctionHolder(SolObject luaObject) noexcept {
|
||||
sol::state_view lua(luaObject.lua_state());
|
||||
sol::function dumper = lua["string"]["dump"];
|
||||
ASSERT(dumper.valid());
|
||||
if (!dumper.valid()) throw Exception() << "Invalid string.dump()";
|
||||
function_ = dumper(luaObject);
|
||||
}
|
||||
|
||||
@ -62,9 +62,10 @@ public:
|
||||
sol::object unpack(sol::this_state state) const final {
|
||||
sol::state_view lua((lua_State*)state);
|
||||
sol::function loader = lua["loadstring"];
|
||||
ASSERT(loader.valid());
|
||||
REQUIRE(loader.valid()) << "Invalid loadstring()";
|
||||
sol::function result = loader(function_);
|
||||
ASSERT(result.valid()) << "Unable to restore function!\n" << "Content:\n" << function_;
|
||||
// The result of restaring always is valid function.
|
||||
assert(result.valid());
|
||||
return sol::make_object(state, result);
|
||||
}
|
||||
|
||||
@ -75,28 +76,28 @@ private:
|
||||
class TableHolder : public BaseHolder {
|
||||
public:
|
||||
template<typename SolType>
|
||||
TableHolder(const SolType& luaObject) noexcept {
|
||||
TableHolder(const SolType& luaObject) {
|
||||
assert(luaObject.template is<SharedTable>());
|
||||
handle_ = luaObject.template as<SharedTable>().handle();
|
||||
assert(getGC().has(handle_));
|
||||
}
|
||||
|
||||
TableHolder(GCObjectHandle handle) noexcept
|
||||
TableHolder(GCObjectHandle handle)
|
||||
: handle_(handle) {}
|
||||
|
||||
bool rawCompare(const BaseHolder *other) const noexcept final {
|
||||
bool rawCompare(const BaseHolder *other) const final {
|
||||
return static_cast<const TableHolder*>(other)->handle_ == handle_;
|
||||
}
|
||||
|
||||
std::size_t hash() const noexcept final {
|
||||
std::size_t hash() const final {
|
||||
return std::hash<GCObjectHandle>()(handle_);
|
||||
}
|
||||
|
||||
sol::object unpack(sol::this_state state) const noexcept final {
|
||||
sol::object unpack(sol::this_state state) const final {
|
||||
return sol::make_object(state, *static_cast<SharedTable*>(getGC().get(handle_)));
|
||||
}
|
||||
|
||||
GCObjectHandle gcHandle() const noexcept override { return handle_; }
|
||||
GCObjectHandle gcHandle() const override { return handle_; }
|
||||
private:
|
||||
GCObjectHandle handle_;
|
||||
};
|
||||
@ -165,7 +166,7 @@ StoredObject fromSolObject(const SolObject& luaObject) {
|
||||
return std::make_unique<TableHolder>(table.handle());
|
||||
}
|
||||
default:
|
||||
ERROR << "Unable to store object of that type: " << (int)luaObject.get_type() << "\n";
|
||||
throw Exception() << "Unable to store object of that type: " << (int)luaObject.get_type() << "\n";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -11,16 +11,16 @@ public:
|
||||
BaseHolder() = default;
|
||||
virtual ~BaseHolder() = default;
|
||||
|
||||
bool compare(const BaseHolder* other) const noexcept {
|
||||
bool compare(const BaseHolder* other) const {
|
||||
return typeid(*this) == typeid(*other) && rawCompare(other);
|
||||
}
|
||||
virtual bool rawCompare(const BaseHolder* other) const = 0;
|
||||
virtual const std::type_info& type() { return typeid(*this); }
|
||||
|
||||
virtual std::size_t hash() const noexcept = 0;
|
||||
virtual std::size_t hash() const = 0;
|
||||
virtual sol::object unpack(sol::this_state state) const = 0;
|
||||
|
||||
virtual GCObjectHandle gcHandle() const noexcept { return GCNull; }
|
||||
virtual GCObjectHandle gcHandle() const { return GCNull; }
|
||||
|
||||
private:
|
||||
BaseHolder(const BaseHolder&) = delete;
|
||||
|
||||
@ -7,19 +7,19 @@ namespace effil {
|
||||
|
||||
class LuaHookStopException : public std::exception {};
|
||||
|
||||
std::string threadId() noexcept
|
||||
std::string threadId()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::this_thread::get_id();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void yield() noexcept
|
||||
void yield()
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
void sleep(int64_t time, sol::optional<std::string> period) noexcept
|
||||
void sleep(int64_t time, sol::optional<std::string> period)
|
||||
{
|
||||
std::string metric = period ? period.value() : "s";
|
||||
if (metric == "ms")
|
||||
@ -38,7 +38,7 @@ thread_local LuaThread::ThreadData* LuaThread::pThreadLocalData = NULL;
|
||||
|
||||
LuaThread::LuaThread(std::shared_ptr<ThreadData> threadData, const std::string& function, const sol::variadic_args& args) {
|
||||
pThreadData_ = threadData;
|
||||
ASSERT(pThreadData_.get());
|
||||
assert(pThreadData_);
|
||||
pThreadData_->command = ThreadCommand::Nothing;
|
||||
pThreadData_->status = ThreadStatus::Running;
|
||||
|
||||
@ -49,7 +49,7 @@ LuaThread::LuaThread(std::shared_ptr<ThreadData> threadData, const std::string&
|
||||
}
|
||||
|
||||
pThread_.reset(new std::thread(&LuaThread::work, pThreadData_, function, std::move(arguments)));
|
||||
ASSERT(pThread_.get() != nullptr);
|
||||
assert(pThread_);
|
||||
pThread_->detach();
|
||||
}
|
||||
|
||||
@ -84,12 +84,12 @@ void LuaThread::luaHook(lua_State*, lua_Debug*)
|
||||
}
|
||||
}
|
||||
|
||||
void LuaThread::work(std::shared_ptr<ThreadData> threadData, const std::string strFunction, std::vector<sol::object>&& arguments) noexcept {
|
||||
void LuaThread::work(std::shared_ptr<ThreadData> threadData, const std::string strFunction, std::vector<sol::object>&& arguments) {
|
||||
try {
|
||||
pThreadLocalData = threadData.get();
|
||||
ASSERT(threadData.get()) << "invalid internal thread state\n";
|
||||
assert(threadData);
|
||||
const sol::object& stringLoader = threadData->luaState["loadstring"];
|
||||
ASSERT(stringLoader.valid() && stringLoader.get_type() == sol::type::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
|
||||
@ -111,22 +111,22 @@ void LuaThread::work(std::shared_ptr<ThreadData> threadData, const std::string s
|
||||
}
|
||||
}
|
||||
|
||||
void LuaThread::cancel() noexcept
|
||||
void LuaThread::cancel()
|
||||
{
|
||||
pThreadData_->command = ThreadCommand::Cancel;
|
||||
}
|
||||
|
||||
void LuaThread::pause() noexcept
|
||||
void LuaThread::pause()
|
||||
{
|
||||
pThreadData_->command = ThreadCommand::Pause;
|
||||
}
|
||||
|
||||
void LuaThread::resume() noexcept
|
||||
void LuaThread::resume()
|
||||
{
|
||||
pThreadData_->command = ThreadCommand::Resume;
|
||||
}
|
||||
|
||||
std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const noexcept
|
||||
std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const
|
||||
{
|
||||
|
||||
ThreadStatus stat = pThreadData_->status;
|
||||
@ -145,7 +145,7 @@ std::tuple<sol::object, sol::table> LuaThread::wait(sol::this_state state) const
|
||||
return std::make_tuple(sol::make_object(state, threadStatusToString(stat)), std::move(returns));
|
||||
}
|
||||
|
||||
std::string LuaThread::threadStatusToString(ThreadStatus stat) const noexcept
|
||||
std::string LuaThread::threadStatusToString(ThreadStatus stat) const
|
||||
{
|
||||
switch(stat)
|
||||
{
|
||||
@ -159,12 +159,12 @@ std::string LuaThread::threadStatusToString(ThreadStatus stat) const noexcept
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string LuaThread::status() const noexcept
|
||||
std::string LuaThread::status() const
|
||||
{
|
||||
return threadStatusToString(pThreadData_->status);
|
||||
}
|
||||
|
||||
sol::object LuaThread::getUserType(sol::state_view &lua) noexcept
|
||||
sol::object LuaThread::getUserType(sol::state_view &lua)
|
||||
{
|
||||
static sol::usertype<LuaThread> type(
|
||||
"new", sol::no_constructor,
|
||||
@ -183,8 +183,7 @@ sol::object LuaThread::getUserType(sol::state_view &lua) noexcept
|
||||
ThreadFactory::ThreadFactory(const sol::function& func) : stepwise_(false), step_(100U) {
|
||||
sol::state_view lua(func.lua_state());
|
||||
const sol::object& dumper = lua["string"]["dump"];
|
||||
ASSERT(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()";
|
||||
strFunction_ = static_cast<const sol::function&>(dumper)(func);
|
||||
|
||||
// Inherit all pathes from parent state by default
|
||||
@ -193,8 +192,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(new LuaThread::ThreadData);
|
||||
ASSERT(threadData.get());
|
||||
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
|
||||
@ -246,7 +245,7 @@ std::string ThreadFactory::packageCPath(const sol::optional<std::string>& value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sol::object ThreadFactory::getUserType(sol::state_view &lua) noexcept
|
||||
sol::object ThreadFactory::getUserType(sol::state_view &lua)
|
||||
{
|
||||
static sol::usertype<ThreadFactory> type(
|
||||
"new", sol::no_constructor,
|
||||
|
||||
@ -9,9 +9,9 @@
|
||||
namespace effil {
|
||||
|
||||
// Lua this thread API
|
||||
std::string threadId() noexcept;
|
||||
void yield() noexcept;
|
||||
void sleep(int64_t, sol::optional<std::string>) noexcept;
|
||||
std::string threadId();
|
||||
void yield();
|
||||
void sleep(int64_t, sol::optional<std::string>);
|
||||
|
||||
class LuaThread {
|
||||
public:
|
||||
@ -39,22 +39,22 @@ public:
|
||||
};
|
||||
|
||||
LuaThread(std::shared_ptr<ThreadData> threadData, const std::string& function, const sol::variadic_args& args);
|
||||
static sol::object getUserType(sol::state_view &lua) noexcept;
|
||||
static sol::object getUserType(sol::state_view &lua);
|
||||
static void luaHook(lua_State*, lua_Debug*);
|
||||
|
||||
/* Public lua methods*/
|
||||
void cancel() noexcept;
|
||||
void pause() noexcept;
|
||||
void resume() noexcept;
|
||||
std::string status() const noexcept;
|
||||
std::tuple<sol::object, sol::table> wait(sol::this_state state) const noexcept;
|
||||
void cancel();
|
||||
void pause();
|
||||
void resume();
|
||||
std::string status() const;
|
||||
std::tuple<sol::object, sol::table> wait(sol::this_state state) const;
|
||||
|
||||
private:
|
||||
LuaThread(const LuaThread&) = delete;
|
||||
LuaThread& operator=(const LuaThread&) = delete;
|
||||
|
||||
std::string threadStatusToString(ThreadStatus stat) const noexcept;
|
||||
static void work(std::shared_ptr<ThreadData> threadData, const std::string strFunction, std::vector<sol::object>&& arguments) noexcept;
|
||||
std::string threadStatusToString(ThreadStatus stat) const;
|
||||
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) noexcept;
|
||||
static sol::object getUserType(sol::state_view &lua);
|
||||
|
||||
/* Public lua methods*/
|
||||
std::unique_ptr<LuaThread> runThread(const sol::variadic_args& args);
|
||||
|
||||
@ -29,8 +29,7 @@ private:
|
||||
|
||||
} // effil
|
||||
|
||||
#define ERROR throw effil::Exception() << __FILE__ << ":" << __LINE__
|
||||
#define ASSERT(cond) if (!(cond)) ERROR << "In condition '" << #cond << "': "
|
||||
#define REQUIRE(cond) if (!cond) throw effil::Exception()
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define DEBUG if (false) std::cout
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user