Use shared locks to read from SharedTable (#99)
This commit is contained in:
parent
0f1bef4300
commit
e5b4e1722f
@ -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");
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user