make thread safety a compile-time toggle
This commit is contained in:
parent
b430cf7c83
commit
dc507f80dd
|
@ -23,6 +23,18 @@
|
|||
# include <span>
|
||||
#endif
|
||||
|
||||
#ifndef LIBCUBESCRIPT_CONF_THREAD_SAFE
|
||||
/** @brief Controls thread safety of the implementation.
|
||||
*
|
||||
* By default, libcubescript is thread safe. That means using locking where
|
||||
* necessary as well as atomic variables where necessary. If you do not need
|
||||
* that, you can disable this by overriding this macro to 0 in your user
|
||||
* configuration. This does not make any difference in behavior when used
|
||||
* in single-threaded scenarios, other than possibly better performance.
|
||||
*/
|
||||
#define LIBCUBESCRIPT_CONF_THREAD_SAFE 1
|
||||
#endif
|
||||
|
||||
namespace cubescript {
|
||||
#if !defined(LIBCUBESCRIPT_CONF_USER_INTEGER)
|
||||
/** @brief The integer type used.
|
||||
|
|
|
@ -12,14 +12,14 @@ namespace cubescript {
|
|||
|
||||
template<typename T>
|
||||
static inline T var_load(unsigned char const *base) noexcept {
|
||||
std::atomic<T> const *p{};
|
||||
atomic_type<T> const *p{};
|
||||
std::memcpy(&p, &base, sizeof(void *));
|
||||
return p->load();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void var_store(unsigned char *base, T v) noexcept {
|
||||
std::atomic<T> *p{};
|
||||
atomic_type<T> *p{};
|
||||
std::memcpy(&p, &base, sizeof(void *));
|
||||
p->store(v);
|
||||
}
|
||||
|
@ -29,24 +29,24 @@ static inline void var_store(unsigned char *base, T v) noexcept {
|
|||
*/
|
||||
|
||||
var_value::var_value(integer_type v): p_type{value_type::INTEGER} {
|
||||
new (p_stor) std::atomic<integer_type>{v};
|
||||
new (p_ostor) std::atomic<integer_type>{0};
|
||||
new (p_stor) atomic_type<integer_type>{v};
|
||||
new (p_ostor) atomic_type<integer_type>{0};
|
||||
}
|
||||
|
||||
var_value::var_value(float_type v): p_type{value_type::FLOAT} {
|
||||
FS vs{};
|
||||
std::memcpy(&vs, &v, sizeof(v));
|
||||
new (p_stor) std::atomic<FS>{vs};
|
||||
new (p_ostor) std::atomic<FS>{0};
|
||||
new (p_stor) atomic_type<FS>{vs};
|
||||
new (p_ostor) atomic_type<FS>{0};
|
||||
}
|
||||
|
||||
var_value::var_value(std::string_view const &v, state &cs):
|
||||
p_type{value_type::STRING}
|
||||
{
|
||||
new (p_stor) std::atomic<char const *>{
|
||||
new (p_stor) atomic_type<char const *>{
|
||||
state_p{cs}.ts().istate->strman->add(v)
|
||||
};
|
||||
new (p_ostor) std::atomic<char const *>{nullptr};
|
||||
new (p_ostor) atomic_type<char const *>{nullptr};
|
||||
}
|
||||
|
||||
var_value::~var_value() {
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
#include <cubescript/cubescript.hh>
|
||||
|
||||
#include "cs_lock.hh"
|
||||
|
||||
#include <bitset>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
namespace cubescript {
|
||||
|
@ -46,9 +47,9 @@ struct var_value {
|
|||
|
||||
private:
|
||||
using VU = union {
|
||||
std::atomic<integer_type> i;
|
||||
std::atomic<FS> f;
|
||||
std::atomic<char const *> s;
|
||||
atomic_type<integer_type> i;
|
||||
atomic_type<FS> f;
|
||||
atomic_type<char const *> s;
|
||||
};
|
||||
|
||||
/* fixed upon creation */
|
||||
|
|
54
src/cs_lock.hh
Normal file
54
src/cs_lock.hh
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef LIBCUBESCRIPT_LOCK_HH
|
||||
#define LIBCUBESCRIPT_LOCK_HH
|
||||
|
||||
#include <cubescript/cubescript.hh>
|
||||
|
||||
#if LIBCUBESCRIPT_CONF_THREAD_SAFE
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
#if ! LIBCUBESCRIPT_CONF_THREAD_SAFE
|
||||
|
||||
struct mutex_type {
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_type {
|
||||
T p_v;
|
||||
|
||||
T load() const {
|
||||
return p_v;
|
||||
}
|
||||
void store(T v) {
|
||||
p_v = v;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
using mutex_type = std::mutex;
|
||||
template<typename T>
|
||||
using atomic_type = std::atomic<T>;
|
||||
|
||||
#endif
|
||||
|
||||
struct mtx_guard {
|
||||
mtx_guard(mutex_type &m): p_m{m} {
|
||||
m.lock();
|
||||
}
|
||||
|
||||
~mtx_guard() {
|
||||
p_m.unlock();
|
||||
}
|
||||
|
||||
mutex_type &p_m;
|
||||
};
|
||||
|
||||
} /* namespace cubescript */
|
||||
|
||||
#endif
|
|
@ -9,6 +9,7 @@
|
|||
#include "cs_vm.hh"
|
||||
#include "cs_parser.hh"
|
||||
#include "cs_error.hh"
|
||||
#include "cs_lock.hh"
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
|
@ -48,7 +49,7 @@ ident *internal_state::lookup_ident(std::size_t idx) {
|
|||
if (idx < MAX_ARGUMENTS) {
|
||||
return argmap[idx];
|
||||
}
|
||||
std::lock_guard<std::mutex> l{ident_mtx};
|
||||
mtx_guard l{ident_mtx};
|
||||
return identmap[idx];
|
||||
}
|
||||
|
||||
|
@ -56,12 +57,12 @@ ident const *internal_state::lookup_ident(std::size_t idx) const {
|
|||
if (idx < MAX_ARGUMENTS) {
|
||||
return argmap[idx];
|
||||
}
|
||||
std::lock_guard<std::mutex> l{ident_mtx};
|
||||
mtx_guard l{ident_mtx};
|
||||
return identmap[idx];
|
||||
}
|
||||
|
||||
std::size_t internal_state::get_identnum() const {
|
||||
std::lock_guard<std::mutex> l{ident_mtx};
|
||||
mtx_guard l{ident_mtx};
|
||||
return identmap.size();
|
||||
}
|
||||
|
||||
|
@ -70,7 +71,7 @@ void internal_state::foreach_ident(void (*f)(ident *, void *), void *data) {
|
|||
for (std::size_t i = 0; i < nids; ++i) {
|
||||
ident *id;
|
||||
{
|
||||
std::lock_guard<std::mutex> l{ident_mtx};
|
||||
mtx_guard l{ident_mtx};
|
||||
id = identmap[i];
|
||||
}
|
||||
f(id, data);
|
||||
|
@ -83,7 +84,7 @@ ident *internal_state::add_ident(ident *id, ident_impl *impl) {
|
|||
}
|
||||
ident_p{*id}.impl(impl);
|
||||
{
|
||||
std::lock_guard<std::mutex> l{ident_mtx};
|
||||
mtx_guard l{ident_mtx};
|
||||
idents[id->name()] = id;
|
||||
impl->p_index = int(identmap.size());
|
||||
identmap.push_back(id);
|
||||
|
@ -108,7 +109,7 @@ ident &internal_state::new_ident(state &cs, std::string_view name, int flags) {
|
|||
}
|
||||
|
||||
ident *internal_state::get_ident(std::string_view name) const {
|
||||
std::lock_guard<std::mutex> l{ident_mtx};
|
||||
mtx_guard l{ident_mtx};
|
||||
auto id = idents.find(name);
|
||||
if (id == idents.end()) {
|
||||
return nullptr;
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
|
||||
#include "cs_bcode.hh"
|
||||
#include "cs_ident.hh"
|
||||
#include "cs_lock.hh"
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
|
@ -52,7 +52,7 @@ struct internal_state {
|
|||
> idents;
|
||||
std::vector<ident *, std_allocator<ident *>> identmap;
|
||||
std::array<ident *, MAX_ARGUMENTS> argmap;
|
||||
mutable std::mutex ident_mtx;
|
||||
mutable mutex_type ident_mtx;
|
||||
|
||||
string_pool *strman;
|
||||
empty_block *empty;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "cs_strman.hh"
|
||||
#include "cs_thread.hh"
|
||||
#include "cs_lock.hh"
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
|
@ -21,7 +22,7 @@ inline string_ref_state *get_ref_state(char const *ptr) {
|
|||
|
||||
char const *string_pool::add(std::string_view str) {
|
||||
{
|
||||
std::lock_guard<std::mutex> l{p_mtx};
|
||||
mtx_guard l{p_mtx};
|
||||
auto it = counts.find(str);
|
||||
/* already present: just increment ref */
|
||||
if (it != counts.end()) {
|
||||
|
@ -43,7 +44,7 @@ char const *string_pool::add(std::string_view str) {
|
|||
memcpy(strp, str.data(), ss);
|
||||
/* store it */
|
||||
{
|
||||
std::lock_guard<std::mutex> l{p_mtx};
|
||||
mtx_guard l{p_mtx};
|
||||
counts.emplace(std::string_view{strp, ss}, get_ref_state(strp));
|
||||
}
|
||||
return strp;
|
||||
|
@ -52,7 +53,7 @@ char const *string_pool::add(std::string_view str) {
|
|||
char const *string_pool::internal_ref(char const *ptr) {
|
||||
auto *ss = get_ref_state(ptr);
|
||||
{
|
||||
std::lock_guard<std::mutex> l{p_mtx};
|
||||
mtx_guard l{p_mtx};
|
||||
++ss->refcount;
|
||||
}
|
||||
return ptr;
|
||||
|
@ -63,7 +64,7 @@ string_ref string_pool::steal(char *ptr) {
|
|||
auto sr = std::string_view{ptr, ss->length};
|
||||
string_ref_state *st = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> l{p_mtx};
|
||||
mtx_guard l{p_mtx};
|
||||
/* much like add(), but we already have memory */
|
||||
auto it = counts.find(sr);
|
||||
if (it != counts.end()) {
|
||||
|
@ -78,7 +79,7 @@ string_ref string_pool::steal(char *ptr) {
|
|||
std::memcpy(&rp, &st, sizeof(rp));
|
||||
return string_ref{rp};
|
||||
} else {
|
||||
std::lock_guard<std::mutex> l{p_mtx};
|
||||
mtx_guard l{p_mtx};
|
||||
ss->refcount = 0; /* string_ref will increment it */
|
||||
counts.emplace(sr, ss);
|
||||
}
|
||||
|
@ -87,7 +88,7 @@ string_ref string_pool::steal(char *ptr) {
|
|||
|
||||
void string_pool::internal_unref(char const *ptr) {
|
||||
auto *ss = get_ref_state(ptr);
|
||||
if (std::lock_guard<std::mutex> l{p_mtx}; !--ss->refcount) {
|
||||
if (mtx_guard l{p_mtx}; !--ss->refcount) {
|
||||
/* refcount zero, so ditch it
|
||||
* this path is a little slow...
|
||||
*/
|
||||
|
@ -113,7 +114,7 @@ void string_pool::internal_unref(char const *ptr) {
|
|||
char const *string_pool::find(std::string_view str) const {
|
||||
string_ref_state *sp;
|
||||
{
|
||||
std::lock_guard<std::mutex> l{p_mtx};
|
||||
mtx_guard l{p_mtx};
|
||||
auto it = counts.find(str);
|
||||
if (it == counts.end()) {
|
||||
return nullptr;
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <mutex>
|
||||
|
||||
#include "cs_std.hh"
|
||||
#include "cs_state.hh"
|
||||
#include "cs_lock.hh"
|
||||
|
||||
namespace cubescript {
|
||||
|
||||
|
@ -83,7 +83,7 @@ struct string_pool {
|
|||
char *alloc_buf(std::size_t len) const;
|
||||
|
||||
internal_state *cstate;
|
||||
mutable std::mutex p_mtx{};
|
||||
mutable mutex_type p_mtx{};
|
||||
std::unordered_map<
|
||||
std::string_view, string_ref_state *,
|
||||
std::hash<std::string_view>,
|
||||
|
|
Loading…
Reference in a new issue