From f77391baa53c0e0f6252b4c6fee3c12754cb8cb9 Mon Sep 17 00:00:00 2001 From: mihacooper Date: Wed, 18 Oct 2017 10:15:33 +0300 Subject: [PATCH] hold strong ref for returned objects (#91) --- src/cpp/channel.cpp | 4 +++- src/cpp/stored-object.cpp | 6 ++++++ src/cpp/stored-object.h | 1 + tests/lua/channel-stress.lua | 23 ++++++++++++++++++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/cpp/channel.cpp b/src/cpp/channel.cpp index f690502..bb25cbe 100644 --- a/src/cpp/channel.cpp +++ b/src/cpp/channel.cpp @@ -63,8 +63,10 @@ StoredArray Channel::pop(const sol::optional& duration, } auto ret = data_->channel_.front(); - for (const auto& obj: ret) + for (const auto& obj: ret) { + obj->holdStrongReference(); removeReference(obj->gcHandle()); + } data_->channel_.pop(); return ret; diff --git a/src/cpp/stored-object.cpp b/src/cpp/stored-object.cpp index 793ad4f..50cf564 100644 --- a/src/cpp/stored-object.cpp +++ b/src/cpp/stored-object.cpp @@ -97,6 +97,12 @@ public: strongRef_ = sol::nullopt; } + void holdStrongReference() override { + if (!strongRef_) { + strongRef_ = GC::instance().get(handle_); + } + } + private: GCObjectHandle handle_; sol::optional strongRef_; diff --git a/src/cpp/stored-object.h b/src/cpp/stored-object.h index 49e5156..ef21fbd 100644 --- a/src/cpp/stored-object.h +++ b/src/cpp/stored-object.h @@ -24,6 +24,7 @@ public: virtual sol::object unpack(sol::this_state state) const = 0; virtual GCObjectHandle gcHandle() const { return GCNull; } virtual void releaseStrongReference() { } + virtual void holdStrongReference() { } private: BaseHolder(const BaseHolder&) = delete; diff --git a/tests/lua/channel-stress.lua b/tests/lua/channel-stress.lua index b17e784..0770bb0 100644 --- a/tests/lua/channel-stress.lua +++ b/tests/lua/channel-stress.lua @@ -68,4 +68,25 @@ if not os.getenv("APPVEYOR") then test.equal(chan:pop(10), "hello!") test.is_true(os.time() < start_time + 10) end -end \ No newline at end of file +end + +-- regress for channel returns +test.channel_stress.retun_tables = function () + local function worker() + local effil = require "effil" + local ch = effil.channel() + for i = 1, 1000 do + ch:push(effil.table()) + local ret = { ch:pop() } + end + end + + local threads = {} + + for i = 1, 20 do + table.insert(threads, effil.thread(worker)()) + end + for _, thr in ipairs(threads) do + thr:wait() + end +end