Cancel in yield 2 (#50)

This commit is contained in:
Ilia 2017-06-12 14:50:00 +03:00 committed by GitHub
parent 265b12370b
commit 6b77d9f9ec
6 changed files with 56 additions and 27 deletions

View File

@ -24,7 +24,7 @@ endif()
add_library(effil SHARED ${SOURCES}) add_library(effil SHARED ${SOURCES})
target_link_libraries(effil -lpthread ${LUA_LIBRARY}) target_link_libraries(effil -lpthread ${LUA_LIBRARY})
set(GENERAL "-std=c++14") set(GENERAL "-std=c++14 -DSOL_EXCEPTIONS_SAFE_PROPAGATION")
set(ENABLE_WARNINGS "-Wall -Wextra -pedantic") set(ENABLE_WARNINGS "-Wall -Wextra -pedantic")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GENERAL} ${ENABLE_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GENERAL} ${ENABLE_WARNINGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror -O0 -g -UNDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror -O0 -g -UNDEBUG")

View File

@ -12,11 +12,10 @@ namespace {
sol::object createThread(const sol::this_state& lua, sol::object createThread(const sol::this_state& lua,
const std::string& path, const std::string& path,
const std::string& cpath, const std::string& cpath,
bool stepwise, int step,
unsigned int step,
const sol::function& function, const sol::function& function,
const sol::variadic_args& args) { const sol::variadic_args& args) {
return sol::make_object(lua, std::make_shared<Thread>(path, cpath, stepwise, step, function, args)); return sol::make_object(lua, std::make_shared<Thread>(path, cpath, step, function, args));
} }
sol::object createTable(sol::this_state lua) { sol::object createTable(sol::this_state lua) {

View File

@ -49,11 +49,8 @@ enum class Command {
} // namespace } // namespace
class ThreadHandle { class ThreadHandle {
public: public:
const bool managed;
Status status; Status status;
StoredArray result; StoredArray result;
@ -64,9 +61,8 @@ public:
Notifier syncPause; Notifier syncPause;
public: public:
ThreadHandle(bool isManaged) ThreadHandle()
: managed(isManaged) : status(Status::Running)
, status(Status::Running)
, command_(Command::Run) , command_(Command::Run)
, lua_(std::make_unique<sol::state>()) { , lua_(std::make_unique<sol::state>()) {
luaL_openlibs(*lua_); luaL_openlibs(*lua_);
@ -171,7 +167,11 @@ std::string threadId() {
return ss.str(); return ss.str();
} }
void yield() { std::this_thread::yield(); } void yield() {
if (thisThreadHandle)
luaHook(nullptr, nullptr);
std::this_thread::yield();
}
void sleep(const sol::optional<int>& duration, const sol::optional<std::string>& period) { void sleep(const sol::optional<int>& duration, const sol::optional<std::string>& period) {
if (duration) if (duration)
@ -182,17 +182,16 @@ void sleep(const sol::optional<int>& duration, const sol::optional<std::string>&
Thread::Thread(const std::string& path, Thread::Thread(const std::string& path,
const std::string& cpath, const std::string& cpath,
bool managed, int step,
unsigned int step,
const sol::function& function, const sol::function& function,
const sol::variadic_args& variadicArgs) const sol::variadic_args& variadicArgs)
: handle_(std::make_shared<ThreadHandle>(managed)) { : handle_(std::make_shared<ThreadHandle>()) {
handle_->lua()["package"]["path"] = path; handle_->lua()["package"]["path"] = path;
handle_->lua()["package"]["cpath"] = cpath; handle_->lua()["package"]["cpath"] = cpath;
handle_->lua().script("require 'effil'"); handle_->lua().script("require 'effil'");
if (managed) if (step != 0)
lua_sethook(handle_->lua(), luaHook, LUA_MASKCOUNT, step); lua_sethook(handle_->lua(), luaHook, LUA_MASKCOUNT, step);
std::string strFunction = dumpFunction(function); std::string strFunction = dumpFunction(function);
@ -264,8 +263,6 @@ StoredArray Thread::get(const sol::optional<int>& duration,
bool Thread::cancel(const sol::this_state&, bool Thread::cancel(const sol::this_state&,
const sol::optional<int>& duration, const sol::optional<int>& duration,
const sol::optional<std::string>& period) { const sol::optional<std::string>& period) {
REQUIRE(handle_->managed) << "Unable to cancel: unmanaged thread";
handle_->command(Command::Cancel); handle_->command(Command::Cancel);
handle_->pause.notify(); handle_->pause.notify();
@ -280,8 +277,6 @@ bool Thread::cancel(const sol::this_state&,
bool Thread::pause(const sol::this_state&, bool Thread::pause(const sol::this_state&,
const sol::optional<int>& duration, const sol::optional<int>& duration,
const sol::optional<std::string>& period) { const sol::optional<std::string>& period) {
REQUIRE(handle_->managed) << "Unable to pause: unmanaged thread";
handle_->pause.reset(); handle_->pause.reset();
handle_->command(Command::Pause); handle_->command(Command::Pause);
@ -294,8 +289,6 @@ bool Thread::pause(const sol::this_state&,
} }
void Thread::resume() { void Thread::resume() {
REQUIRE(handle_->managed) << "Unable to resume: unmanaged thread";
handle_->command(Command::Run); handle_->command(Command::Run);
handle_->syncPause.reset(); handle_->syncPause.reset();
handle_->pause.notify(); handle_->pause.notify();

View File

@ -16,8 +16,7 @@ class Thread {
public: public:
Thread(const std::string& path, Thread(const std::string& path,
const std::string& cpath, const std::string& cpath,
bool managed, int step,
unsigned int step,
const sol::function& function, const sol::function& function,
const sol::variadic_args& args); const sol::variadic_args& args);

View File

@ -37,21 +37,19 @@ api.type = function (something)
end end
local function run_thread(config, f, ...) local function run_thread(config, f, ...)
return capi.thread(config.path, config.cpath, config.managed, config.step, f, ...) return capi.thread(config.path, config.cpath, config.step, f, ...)
end end
-- Creates thread runner with given function -- Creates thread runner with given function
-- configurable parameters: -- configurable parameters:
-- path - lua modules search path in child thread -- path - lua modules search path in child thread
-- cpath - lua libs search path in child thread -- cpath - lua libs search path in child thread
-- stepwise - is thread resumable
-- step - who fast reacte on state changing -- step - who fast reacte on state changing
-- __call - run thread, can be invoked multiple times -- __call - run thread, can be invoked multiple times
api.thread = function (f) api.thread = function (f)
local thread_config = { local thread_config = {
path = package.path, path = package.path,
cpath = package.cpath, cpath = package.cpath,
managed = true,
step = 200 } step = 200 }
setmetatable(thread_config, {__call = function(c, ...) return run_thread(c, f, ...) end}) setmetatable(thread_config, {__call = function(c, ...) return run_thread(c, f, ...) end})
return thread_config return thread_config

View File

@ -279,5 +279,45 @@ test.this_thread.functions = function ()
test.is_string(share["child.id"]) test.is_string(share["child.id"])
test.is_number(tonumber(share["child.id"])) test.is_number(tonumber(share["child.id"]))
test.not_equal(share["child.id"], effil.thread_id()) test.not_equal(share["child.id"], effil.thread_id())
effil.yield() -- just call it end
test.this_thread.cancel_with_yield = function ()
local share = effil.table()
local spec = effil.thread(function (share)
require('effil').sleep(1)
for i=1,10000 do
-- Just waiting
end
share.done = true
require("effil").yield()
share.afet_yield = true
end)
spec.step = 0
local thr = spec(share)
test.is_true(thr:cancel())
test.equal(thr:status(), "canceled")
test.is_true(share.done)
test.is_nil(share.afet_yield)
end
test.this_thread.pause_with_yield = function ()
local share = effil.table()
local spec = effil.thread(function (share)
for i=1,10000 do
require("effil").yield()
end
share.done = true
return true
end)
spec.step = 0
local thr = spec(share)
thr:pause()
test.is_nil(share.done)
test.equal(thr:status(), "paused")
thr:resume()
test.is_true(thr:get())
test.is_true(share.done)
end end