Use shared locks to read from SharedTable (#99)

This commit is contained in:
mihacooper 2018-03-07 12:49:34 +03:00 committed by Ilia
parent 0f1bef4300
commit e5b4e1722f
2 changed files with 43 additions and 15 deletions

View File

@ -2,13 +2,16 @@
#include "utils.h"
#include <mutex>
#include <cassert>
#include <shared_mutex>
namespace effil {
namespace {
typedef std::unique_lock<SpinMutex> UniqueLock;
typedef std::shared_lock<SpinMutex> SharedLock;
template<typename SolObject>
bool isSharedTable(const SolObject& obj) {
return obj.valid() && obj.get_type() == sol::type::userdata && obj.template is<SharedTable>();
@ -47,7 +50,7 @@ void SharedTable::exportAPI(sol::state_view& lua) {
}
void SharedTable::set(StoredObject&& key, StoredObject&& value) {
std::lock_guard<SpinMutex> g(ctx_->lock);
UniqueLock g(ctx_->lock);
ctx_->addReference(key->gcHandle());
ctx_->addReference(value->gcHandle());
@ -59,7 +62,7 @@ void SharedTable::set(StoredObject&& key, StoredObject&& value) {
}
sol::object SharedTable::get(const StoredObject& key, sol::this_state state) const {
std::lock_guard<SpinMutex> g(ctx_->lock);
SharedLock g(ctx_->lock);
auto val = ctx_->entries.find(key);
if (val == ctx_->entries.end()) {
return sol::nil;
@ -73,7 +76,7 @@ void SharedTable::rawSet(const sol::stack_object& luaKey, const sol::stack_objec
StoredObject key = createStoredObject(luaKey);
if (luaValue.get_type() == sol::type::nil) {
std::lock_guard<SpinMutex> g(ctx_->lock);
UniqueLock g(ctx_->lock);
// in this case object is not obligatory to own data
auto it = ctx_->entries.find(key);
@ -100,7 +103,7 @@ sol::object SharedTable::rawGet(const sol::stack_object& luaKey, sol::this_state
#define DEFFINE_METAMETHOD_CALL_0(methodName) DEFFINE_METAMETHOD_CALL(methodName, *this)
#define DEFFINE_METAMETHOD_CALL(methodName, ...) \
{ \
std::unique_lock<SpinMutex> lock(ctx_->lock); \
SharedLock lock(ctx_->lock); \
if (ctx_->metatable != GCNull) { \
auto tableHolder = GC::instance().get<SharedTable>(ctx_->metatable); \
lock.unlock(); \
@ -156,7 +159,7 @@ sol::object SharedTable::luaUnm(sol::this_state state) {
void SharedTable::luaNewIndex(const sol::stack_object& luaKey, const sol::stack_object& luaValue, sol::this_state state) {
{
std::unique_lock<SpinMutex> lock(ctx_->lock);
SharedLock lock(ctx_->lock);
if (ctx_->metatable != GCNull) {
auto tableHolder = GC::instance().get<SharedTable>(ctx_->metatable);
lock.unlock();
@ -180,7 +183,7 @@ sol::object SharedTable::luaIndex(const sol::stack_object& luaKey, sol::this_sta
}
StoredArray SharedTable::luaCall(sol::this_state state, const sol::variadic_args& args) {
std::unique_lock<SpinMutex> lock(ctx_->lock);
SharedLock lock(ctx_->lock);
if (ctx_->metatable != GCNull) {
auto metatable = GC::instance().get<SharedTable>(ctx_->metatable);
sol::function handler = metatable.get(createStoredObject(std::string("__call")), state);
@ -208,7 +211,7 @@ sol::object SharedTable::luaToString(sol::this_state state) {
sol::object SharedTable::luaLength(sol::this_state state) {
DEFFINE_METAMETHOD_CALL_0("__len");
std::lock_guard<SpinMutex> g(ctx_->lock);
SharedLock g(ctx_->lock);
size_t len = 0u;
sol::optional<LUA_INDEX_TYPE> value;
auto iter = ctx_->entries.find(createStoredObject(static_cast<LUA_INDEX_TYPE>(1)));
@ -223,7 +226,7 @@ sol::object SharedTable::luaLength(sol::this_state state) {
}
SharedTable::PairsIterator SharedTable::getNext(const sol::object& key, sol::this_state lua) {
std::lock_guard<SpinMutex> g(ctx_->lock);
SharedLock g(ctx_->lock);
if (key) {
auto obj = createStoredObject(key);
auto upper = ctx_->entries.upper_bound(obj);
@ -271,7 +274,7 @@ SharedTable SharedTable::luaSetMetatable(const sol::stack_object& tbl, const sol
SharedTable stable = GC::instance().get<SharedTable>(createStoredObject(tbl)->gcHandle());
std::lock_guard<SpinMutex> lock(stable.ctx_->lock);
UniqueLock lock(stable.ctx_->lock);
if (stable.ctx_->metatable != GCNull) {
stable.ctx_->removeReference(stable.ctx_->metatable);
stable.ctx_->metatable = GCNull;
@ -287,7 +290,7 @@ sol::object SharedTable::luaGetMetatable(const sol::stack_object& tbl, sol::this
REQUIRE(isSharedTable(tbl)) << "bad argument #1 to 'effil.getmetatable' (effil.table expected, got " << luaTypename(tbl) << ")";
auto& stable = tbl.as<SharedTable>();
std::lock_guard<SpinMutex> lock(stable.ctx_->lock);
SharedLock lock(stable.ctx_->lock);
return stable.ctx_->metatable == GCNull ? sol::nil :
sol::make_object(state, GC::instance().get<SharedTable>(stable.ctx_->metatable));
}
@ -312,7 +315,7 @@ size_t SharedTable::luaSize(const sol::stack_object& tbl) {
REQUIRE(isSharedTable(tbl)) << "bad argument #1 to 'effil.size' (effil.table expected, got " << luaTypename(tbl) << ")";
try {
auto& stable = tbl.as<SharedTable>();
std::lock_guard<SpinMutex> g(stable.ctx_->lock);
SharedLock g(stable.ctx_->lock);
return stable.ctx_->entries.size();
} RETHROW_WITH_PREFIX("effil.size");
}

View File

@ -8,15 +8,40 @@ namespace effil {
class SpinMutex {
public:
void lock() noexcept {
while (lock_.test_and_set(std::memory_order_acquire)) {
while (lock_.exchange(true, std::memory_order_acquire)) {
std::this_thread::yield();
}
while (counter_ != 0) {
std::this_thread::yield();
}
}
void unlock() noexcept { lock_.clear(std::memory_order_release); }
void unlock() noexcept {
lock_.exchange(false, std::memory_order_release);
}
void lock_shared() noexcept {
while (true) {
while (lock_) {
std::this_thread::yield();
}
counter_.fetch_add(1, std::memory_order_acquire);
if (lock_)
counter_.fetch_sub(1, std::memory_order_release);
else
return;
}
}
void unlock_shared() noexcept {
counter_.fetch_sub(1, std::memory_order_release);
}
private:
std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
std::atomic_int counter_ {0};
std::atomic_bool lock_ {false};
};
} // effil