fix context leak by yielding LuaJIT thread

This commit is contained in:
falsycat 2022-11-15 19:47:11 +09:00
parent 5b566acd10
commit de0f2a4a8a
4 changed files with 27 additions and 10 deletions

View File

@ -390,7 +390,7 @@ void PushNodeRootLambda(
}).template Catch<nf7::Exception>(nullptr, [L, th](nf7::Exception&) {
th->ExecResume(L);
});
return th->Yield(L);
return th->Yield(L, la);
}
});
lua_setfield(L, -2, "recv");

View File

@ -48,12 +48,15 @@ void Thread::Resume(lua_State* L, int narg) noexcept {
lua_setfield(L, -2, "nf7");
lua_pop(L, 1);
state_ = kRunning;
k.unlock();
state_ = kRunning;
active_ = true;
yield_ctx_.reset();
k.unlock();
const auto ret = lua_resume(L, narg);
active_ = false;
k.lock();
active_ = false;
if (state_ == kAborted) return;
switch (ret) {
case 0:
@ -67,13 +70,24 @@ void Thread::Resume(lua_State* L, int narg) noexcept {
th_ref_ = std::nullopt;
state_ = kAborted;
}
if (!std::exchange(skip_handle_, false)) {
if (!std::exchange(skip_handler_, false)) {
k.unlock();
handler_(*this, L);
}
}
void Thread::Abort() noexcept {
std::unique_lock<std::mutex> k(mtx_);
state_ = kAborted;
state_ = kAborted;
th_ref_ = std::nullopt;
auto wctx = std::move(yield_ctx_);
yield_ctx_.reset();
k.unlock();
if (auto ctx = wctx.lock()) {
if (ctx.get() != this) {
ctx->Abort();
}
}
}

View File

@ -97,8 +97,9 @@ class Thread final : public nf7::Context,
// must be called on luajit thread
// handler_ won't be called on this yielding
int Yield(lua_State* L) {
skip_handle_ = true;
int Yield(lua_State* L, const std::shared_ptr<nf7::Context>& ctx = nullptr) {
yield_ctx_ = ctx;
skip_handler_ = true;
return lua_yield(L, 0);
}
@ -153,8 +154,9 @@ class Thread final : public nf7::Context,
// mutable params
bool active_ = false; // true while executing lua_resume
bool skip_handle_ = false; // handler_ won't be called on next yield
bool active_ = false; // true while executing lua_resume
bool skip_handler_ = false;
std::weak_ptr<nf7::Context> yield_ctx_;
};

View File

@ -77,6 +77,7 @@ class NodeRootLambda : public nf7::Node::Lambda,
void Abort() noexcept override {
target_->Abort();
pro_ = std::nullopt;
}
private: