Skip to content

Commit

Permalink
Replace volatile with relaxed_atomic.
Browse files Browse the repository at this point in the history
  • Loading branch information
kohler committed Oct 10, 2023
1 parent 92593a9 commit 0a3c4ca
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 53 deletions.
4 changes: 2 additions & 2 deletions GNUmakefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ AR = ar
CC = @CC@
CXX = @CXX@
CPPFLAGS = @CPPFLAGS@
CXXFLAGS = @CXXFLAGS@
CXXFLAGS = @CXXFLAGS@ -pthread
RANLIB = @RANLIB@
DEPSDIR := .deps
DEPCFLAGS = -MD -MF $(DEPSDIR)/$*.d -MP
Expand All @@ -18,7 +18,7 @@ endif
ifneq ($(strip $(NOSUPERPAGE)), )
CPPFLAGS += -DNOSUPERPAGE
endif
LIBS = @LIBS@ -lpthread -lm
LIBS = @LIBS@ -lm
LDFLAGS = @LDFLAGS@

all: test_atomics mtd mtclient mttest
Expand Down
26 changes: 26 additions & 0 deletions compiler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#if HAVE_TYPE_TRAITS
#include <type_traits>
#endif
#include <atomic>

#define arraysize(a) (sizeof(a) / sizeof((a)[0]))

Expand Down Expand Up @@ -1190,4 +1191,29 @@ template <> struct has_fast_int_multiply<unsigned long long> : public mass::true

struct uninitialized_type {};


template <typename T>
struct relaxed_atomic {
public:
relaxed_atomic() : _v() {
}
relaxed_atomic(T v) : _v(v) {
}

T load() const {
return _v.load(std::memory_order_relaxed);
}
relaxed_atomic<T>& store(T v) {
_v.store(v, std::memory_order_relaxed);
return *this;
}

relaxed_atomic(const relaxed_atomic<T>&) = delete;
relaxed_atomic(relaxed_atomic<T>&&) = delete;
relaxed_atomic<T>& operator=(const relaxed_atomic<T>&) = delete;
relaxed_atomic<T>& operator=(relaxed_atomic<T>&&) = delete;
private:
std::atomic<T> _v;
};

#endif
6 changes: 3 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script.

AC_INIT([masstree-beta], [0.1])
AC_PREREQ(2.60)
AC_INIT([masstree-beta],[0.1])
AC_PREREQ([2.71])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([GNUmakefile])
AC_SUBST(ac_configure_args)
Expand All @@ -11,7 +11,7 @@ if test "${CXXFLAGS+y}" != y; then CXXFLAGS="-g -W -Wall -O3"; fi

AC_PROG_CC
AC_PROG_CXX
AC_LANG_CPLUSPLUS
AC_LANG([C++])
AC_PROG_RANLIB

AC_DEFINE([WORDS_BIGENDIAN_SET], [1], [Define if WORDS_BIGENDIAN has been set.])
Expand Down
2 changes: 1 addition & 1 deletion kvthread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void threadinfo::hard_rcu_quiesce() {
limbo_group* empty_tail = nullptr;
unsigned count = rcu_free_count;

mrcu_epoch_type epoch_bound = active_epoch - 1;
mrcu_epoch_type epoch_bound = active_epoch.load() - 1;
if (limbo_head_->head_ == limbo_head_->tail_
|| mrcu_signed_epoch_type(epoch_bound - limbo_head_->first_epoch()) < 0)
goto done;
Expand Down
17 changes: 9 additions & 8 deletions kvthread.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class loginfo;
typedef uint64_t mrcu_epoch_type;
typedef int64_t mrcu_signed_epoch_type;

extern volatile mrcu_epoch_type globalepoch; // global epoch, updated regularly
extern volatile mrcu_epoch_type active_epoch;
extern relaxed_atomic<mrcu_epoch_type> globalepoch; // global epoch, updated regularly
extern relaxed_atomic<mrcu_epoch_type> active_epoch;

struct limbo_group {
typedef mrcu_epoch_type epoch_type;
Expand Down Expand Up @@ -261,17 +261,18 @@ class threadinfo {
// RCU
enum { rcu_free_count = 128 }; // max # of entries to free per rcu_quiesce() call
void rcu_start() {
if (gc_epoch_ != globalepoch)
gc_epoch_ = globalepoch;
auto ge = globalepoch.load();
if (gc_epoch_ != ge)
gc_epoch_ = ge;
}
void rcu_stop() {
if (perform_gc_epoch_ != active_epoch)
if (perform_gc_epoch_ != active_epoch.load())
hard_rcu_quiesce();
gc_epoch_ = 0;
}
void rcu_quiesce() {
rcu_start();
if (perform_gc_epoch_ != active_epoch)
if (perform_gc_epoch_ != active_epoch.load())
hard_rcu_quiesce();
}
typedef ::mrcu_callback mrcu_callback;
Expand Down Expand Up @@ -339,7 +340,7 @@ class threadinfo {
void record_rcu(void* ptr, memtag tag) {
if (limbo_tail_->tail_ + 2 > limbo_tail_->capacity)
refill_rcu();
uint64_t epoch = globalepoch;
auto epoch = globalepoch.load();
limbo_tail_->push_back(ptr, tag, epoch);
}

Expand All @@ -365,7 +366,7 @@ class threadinfo {
};

inline mrcu_epoch_type threadinfo::min_active_epoch() {
mrcu_epoch_type ae = globalepoch;
auto ae = globalepoch.load();
for (threadinfo* ti = allthreads; ti; ti = ti->next()) {
prefetch((const void*) ti->next());
mrcu_epoch_type te = ti->gc_epoch_;
Expand Down
8 changes: 4 additions & 4 deletions mtd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ static std::vector<int> cores;
static bool logging = true;
static bool pinthreads = false;
static bool recovery_only = false;
volatile uint64_t globalepoch = 1; // global epoch, updated by main thread regularly
volatile uint64_t active_epoch = 1;
relaxed_atomic<mrcu_epoch_type> globalepoch(1); // global epoch, updated by main thread regularly
relaxed_atomic<mrcu_epoch_type> active_epoch(1);
static int port = 2117;
static uint64_t test_limit = ~uint64_t(0);
static int doprint = 0;
Expand Down Expand Up @@ -930,8 +930,8 @@ canceling(void *)
void
epochinc(int)
{
globalepoch += 2;
active_epoch = threadinfo::min_active_epoch();
globalepoch.store(globalepoch.load() + 2);
active_epoch.store(threadinfo::min_active_epoch());
}

// Return 1 if success, -1 if I/O error or protocol unmatch
Expand Down
16 changes: 9 additions & 7 deletions mttest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ static bool json_stats = false;
static String gnuplot_yrange;
static bool pinthreads = false;
static nodeversion32 global_epoch_lock(false);
volatile mrcu_epoch_type globalepoch = 1; // global epoch, updated by main thread regularly
volatile mrcu_epoch_type active_epoch = 1;
relaxed_atomic<mrcu_epoch_type> globalepoch(1); // global epoch, updated by main thread regularly
relaxed_atomic<mrcu_epoch_type> active_epoch(1);
kvepoch_t global_log_epoch = 0;
static int port = 2117;
static int rscale_ncores = 0;
Expand Down Expand Up @@ -123,9 +123,9 @@ void test_timeout(int) {

void set_global_epoch(mrcu_epoch_type e) {
global_epoch_lock.lock();
if (mrcu_signed_epoch_type(e - globalepoch) > 0) {
globalepoch = e;
active_epoch = threadinfo::min_active_epoch();
if (mrcu_signed_epoch_type(e - globalepoch.load()) > 0) {
globalepoch.store(e);
active_epoch.store(threadinfo::min_active_epoch());
}
global_epoch_lock.unlock();
}
Expand Down Expand Up @@ -296,7 +296,7 @@ struct kvtest_client {
}
void rcu_quiesce() {
mrcu_epoch_type e = timestamp() >> 16;
if (e != globalepoch)
if (e != globalepoch.load())
set_global_epoch(e);
ti_->rcu_quiesce();
}
Expand Down Expand Up @@ -1096,7 +1096,9 @@ Try 'mttest --help' for options.\n");
static void run_one_test_body(int trial, const char *treetype, const char *test) {
threadinfo *main_ti = threadinfo::make(threadinfo::TI_MAIN, -1);
main_ti->pthread() = pthread_self();
globalepoch = active_epoch = timestamp() >> 16;
auto e = timestamp() >> 16;
globalepoch.store(e);
active_epoch.store(e);
for (int i = 0; i < (int) arraysize(test_thread_map); ++i)
if (strcmp(test_thread_map[i].treetype, treetype) == 0) {
current_test_name = test;
Expand Down
32 changes: 17 additions & 15 deletions string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ bool String_generic::glob_match(const char* sbegin, int slen,
/** @cond never */
#if HAVE_STRING_PROFILING
void String::memo_type::account_new() {
int bucket = profile_memo_size_bucket(this->dirty, this->capacity);
int bucket = profile_memo_size_bucket(this->dirty.load(), this->capacity);
++memo_sizes[bucket];
++live_memo_sizes[bucket];
live_memo_bytes[bucket] += this->capacity;
Expand All @@ -497,7 +497,7 @@ void String::memo_type::account_new() {
}

void String::memo_type::account_destroy() {
int bucket = profile_memo_size_bucket(this->dirty, this->capacity);
int bucket = profile_memo_size_bucket(this->dirty.load(), this->capacity);
--live_memo_sizes[bucket];
live_memo_bytes[bucket] -= this->capacity;
--live_memo_count;
Expand All @@ -521,7 +521,7 @@ void
String::delete_memo(memo_type *memo)
{
assert(memo->capacity > 0);
assert(memo->capacity >= memo->dirty);
assert(memo->capacity >= memo->dirty.load());
memo->account_destroy();
delete[] reinterpret_cast<char*>(memo);
}
Expand All @@ -548,8 +548,8 @@ String::one_profile_report(StringAccum &sa, int i, int examples)
if (examples) {
# if HAVE_STRING_PROFILING > 1
for (memo_type *m = live_memos[i]; m; m = m->next) {
sa << " [" << m->dirty << "] ";
uint32_t dirty = m->dirty;
auto dirty = m->dirty.load();
sa << " [" << dirty << "] ";
if (dirty > 0 && m->real_data[dirty - 1] == '\0')
--dirty;
sa.append(m->real_data, dirty > 128 ? 128 : dirty);
Expand Down Expand Up @@ -736,18 +736,20 @@ String::append_uninitialized(int len)
// If we can, append into unused space. First, we check that there's
// enough unused space for 'len' characters to fit; then, we check
// that the unused space immediately follows the data in '*this'.
uint32_t dirty;
memo_type* m = _r.memo();
if (m && ((dirty = m->dirty), m->capacity > dirty + len)) {
char *real_dirty = m->real_data + dirty;
if (real_dirty == _r.data + _r.length) {
m->dirty = dirty + len;
_r.length += len;
assert(m->dirty < m->capacity);
if (m) {
auto dirty = m->dirty.load();
if (m->capacity > dirty + len) {
char *real_dirty = m->real_data + dirty;
if (real_dirty == _r.data + _r.length) {
assert(dirty + len < m->capacity);
m->dirty.store(dirty + len);
_r.length += len;
#if HAVE_STRING_PROFILING
profile_update_memo_dirty(m, dirty, dirty + len, m->capacity);
profile_update_memo_dirty(m, dirty, dirty + len, m->capacity);
#endif
return real_dirty;
return real_dirty;
}
}
}

Expand Down Expand Up @@ -846,7 +848,7 @@ String::hard_c_str() const
// exists. Otherwise must check that _data[_length] exists.
const char *end_data = _r.data + _r.length;
memo_type* m = _r.memo();
if ((m && end_data >= m->real_data + m->dirty)
if ((m && end_data >= m->real_data + m->dirty.load())
|| *end_data != '\0') {
if (char *x = const_cast<String *>(this)->append_uninitialized(1)) {
*x = '\0';
Expand Down
Loading

0 comments on commit 0a3c4ca

Please sign in to comment.