nf7/core/luajit/thread.hh

102 lines
2.2 KiB
C++

// No copyright
#pragma once
#include <cassert>
#include <functional>
#include <memory>
#include <utility>
#include <lua.hpp>
#include "iface/common/leak_detector.hh"
#include "core/luajit/context.hh"
namespace nf7::core::luajit {
class Thread :
public std::enable_shared_from_this<Thread>,
private LeakDetector<Thread> {
public:
struct DoNotCallConstructorDirectly { };
enum State : uint8_t {
kPaused,
kRunning,
kExited,
kAborted,
};
public:
template <typename T = Thread>
static std::shared_ptr<T> Make(
TaskContext& lua, const std::shared_ptr<Value>& func) {
DoNotCallConstructorDirectly key;
auto th = std::make_shared<T>(lua, key);
th->taskContext(lua).Query(*func);
return th;
}
public:
Thread(TaskContext& t, DoNotCallConstructorDirectly&) noexcept
: context_(t.context()), th_(lua_newthread(*t)) {
assert(th_);
}
public:
// if this finished with state_ kPaused,
// a responsibility to resume is on one who yielded
template <typename... Args>
void Resume(TaskContext& lua, Args&&... args) noexcept {
assert(lua.context() == context_);
if (kExited == state_ || kAborted == state_) {
return;
}
assert(kPaused == state_);
SetUpThread();
auto thlua = taskContext(lua);
const auto narg = thlua.PushAll(std::forward<Args>(args)...);
state_ = kRunning;
const auto ret = lua_resume(*thlua, narg);
switch (ret) {
case 0:
state_ = kExited;
onExited(thlua);
return;
case LUA_YIELD:
state_ = kPaused;
return;
default:
state_ = kAborted;
onAborted(thlua);
return;
}
}
const std::shared_ptr<Context>& context() const noexcept { return context_; }
State state() const noexcept { return state_; }
protected:
virtual void onExited(TaskContext&) noexcept { }
virtual void onAborted(TaskContext&) noexcept { }
private:
void SetUpThread() noexcept;
TaskContext taskContext(const TaskContext& t) const noexcept {
assert(t.context() == context_);
return TaskContext {context_, th_};
}
private:
const std::shared_ptr<Context> context_;
lua_State* const th_;
State state_ = kPaused;
};
} // namespace nf7::core::luajit