From dc507f80dd03f4d78a2af1349dbc0438481dd379 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Thu, 21 Apr 2022 04:54:47 +0200 Subject: [PATCH] make thread safety a compile-time toggle --- include/cubescript/cubescript_conf.hh | 12 ++++++ src/cs_ident.cc | 16 ++++---- src/cs_ident.hh | 9 +++-- src/cs_lock.hh | 54 +++++++++++++++++++++++++++ src/cs_state.cc | 13 ++++--- src/cs_state.hh | 4 +- src/cs_strman.cc | 15 ++++---- src/cs_strman.hh | 4 +- 8 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 src/cs_lock.hh diff --git a/include/cubescript/cubescript_conf.hh b/include/cubescript/cubescript_conf.hh index 22b87ba..49907bd 100644 --- a/include/cubescript/cubescript_conf.hh +++ b/include/cubescript/cubescript_conf.hh @@ -23,6 +23,18 @@ # include #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. diff --git a/src/cs_ident.cc b/src/cs_ident.cc index 2f17eb7..27e475e 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -12,14 +12,14 @@ namespace cubescript { template static inline T var_load(unsigned char const *base) noexcept { - std::atomic const *p{}; + atomic_type const *p{}; std::memcpy(&p, &base, sizeof(void *)); return p->load(); } template static inline void var_store(unsigned char *base, T v) noexcept { - std::atomic *p{}; + atomic_type *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{v}; - new (p_ostor) std::atomic{0}; + new (p_stor) atomic_type{v}; + new (p_ostor) atomic_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{vs}; - new (p_ostor) std::atomic{0}; + new (p_stor) atomic_type{vs}; + new (p_ostor) atomic_type{0}; } var_value::var_value(std::string_view const &v, state &cs): p_type{value_type::STRING} { - new (p_stor) std::atomic{ + new (p_stor) atomic_type{ state_p{cs}.ts().istate->strman->add(v) }; - new (p_ostor) std::atomic{nullptr}; + new (p_ostor) atomic_type{nullptr}; } var_value::~var_value() { diff --git a/src/cs_ident.hh b/src/cs_ident.hh index 11c8f3a..8a3cd49 100644 --- a/src/cs_ident.hh +++ b/src/cs_ident.hh @@ -3,8 +3,9 @@ #include +#include "cs_lock.hh" + #include -#include #include namespace cubescript { @@ -46,9 +47,9 @@ struct var_value { private: using VU = union { - std::atomic i; - std::atomic f; - std::atomic s; + atomic_type i; + atomic_type f; + atomic_type s; }; /* fixed upon creation */ diff --git a/src/cs_lock.hh b/src/cs_lock.hh new file mode 100644 index 0000000..420f4c0 --- /dev/null +++ b/src/cs_lock.hh @@ -0,0 +1,54 @@ +#ifndef LIBCUBESCRIPT_LOCK_HH +#define LIBCUBESCRIPT_LOCK_HH + +#include + +#if LIBCUBESCRIPT_CONF_THREAD_SAFE +#include +#include +#endif + +namespace cubescript { + +#if ! LIBCUBESCRIPT_CONF_THREAD_SAFE + +struct mutex_type { + void lock() {} + void unlock() {} +}; + +template +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 +using atomic_type = std::atomic; + +#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 diff --git a/src/cs_state.cc b/src/cs_state.cc index dce45fd..51d97ae 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -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 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 l{ident_mtx}; + mtx_guard l{ident_mtx}; return identmap[idx]; } std::size_t internal_state::get_identnum() const { - std::lock_guard 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 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 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 l{ident_mtx}; + mtx_guard l{ident_mtx}; auto id = idents.find(name); if (id == idents.end()) { return nullptr; diff --git a/src/cs_state.hh b/src/cs_state.hh index 2e74acd..2cb363b 100644 --- a/src/cs_state.hh +++ b/src/cs_state.hh @@ -7,10 +7,10 @@ #include #include #include -#include #include "cs_bcode.hh" #include "cs_ident.hh" +#include "cs_lock.hh" namespace cubescript { @@ -52,7 +52,7 @@ struct internal_state { > idents; std::vector> identmap; std::array argmap; - mutable std::mutex ident_mtx; + mutable mutex_type ident_mtx; string_pool *strman; empty_block *empty; diff --git a/src/cs_strman.cc b/src/cs_strman.cc index f80c4b1..52adc09 100644 --- a/src/cs_strman.cc +++ b/src/cs_strman.cc @@ -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 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 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 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 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 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 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 l{p_mtx}; + mtx_guard l{p_mtx}; auto it = counts.find(str); if (it == counts.end()) { return nullptr; diff --git a/src/cs_strman.hh b/src/cs_strman.hh index 4193c7e..df97af2 100644 --- a/src/cs_strman.hh +++ b/src/cs_strman.hh @@ -5,10 +5,10 @@ #include #include -#include #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,