mirror of
https://github.com/plasma-umass/coz.git
synced 2024-09-11 04:55:25 +03:00
Pulled ccutil into libcoz. Refs #48
This commit is contained in:
parent
61bb4824d4
commit
3470416c67
11
deps.mk
11
deps.mk
@ -2,17 +2,6 @@
|
||||
|
||||
GIT = git
|
||||
|
||||
# Get ccutil (header only)
|
||||
$(ROOT)/deps/ccutil:
|
||||
@echo $(LOG_PREFIX) Checking out ccutil includes $(LOG_SUFFIX)
|
||||
@mkdir -p $(ROOT)/deps
|
||||
@$(GIT) clone git://github.com/ccurtsinger/ccutil $(ROOT)/deps/ccutil
|
||||
|
||||
# Update build settings to use ccutil
|
||||
ifneq (,$(findstring ccutil,$(PREREQS)))
|
||||
CXXFLAGS += -I$(ROOT)/deps
|
||||
endif
|
||||
|
||||
# Get and build libelfin
|
||||
$(ROOT)/deps/libelfin: $(ROOT)/deps/libelfin/elf/libelf++.a
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
ROOT := ..
|
||||
TARGETS := libcoz.so
|
||||
LIBS := dl rt pthread
|
||||
CXXFLAGS := --std=c++11 -g -O2 -fPIC -I$(ROOT)/include
|
||||
#LDFLAGS := -L$(ROOT)/deps/libelfin/elf -L$(ROOT)/deps/libelfin/dwarf -Wl,--whole-archive -lelf++ -ldwarf++ -Wl,--no-whole-archive
|
||||
PREREQS := $(ROOT)/deps/ccutil $(ROOT)/deps/libelfin
|
||||
CXXFLAGS := --std=c++11 -g -O2 -fPIC -I$(ROOT)/include -I.
|
||||
PREREQS := $(ROOT)/deps/libelfin
|
||||
|
||||
include $(ROOT)/common.mk
|
||||
|
||||
|
82
libcoz/ccutil/log.h
Normal file
82
libcoz/ccutil/log.h
Normal file
@ -0,0 +1,82 @@
|
||||
#if !defined(CCUTIL_LOG_H)
|
||||
#define CCUTIL_LOG_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace ccutil {
|
||||
static const char* InfoColor = "\033[01;34m";
|
||||
static const char* WarningColor = "\033[01;33m";
|
||||
static const char* FatalColor = "\033[01;31m";
|
||||
static const char* SourceColor = "\033[34m";
|
||||
static const char* EndColor = "\033[0m";
|
||||
|
||||
class logger_base {
|
||||
public:
|
||||
logger_base indent(size_t n, size_t tab_size = 2) {
|
||||
return logger_base();
|
||||
}
|
||||
|
||||
template<typename T> logger_base operator<<(T t) {
|
||||
return logger_base();
|
||||
}
|
||||
};
|
||||
|
||||
class logger : public logger_base {
|
||||
private:
|
||||
bool _done;
|
||||
bool _exit;
|
||||
public:
|
||||
logger(bool exit = false, bool done = true) : _exit(exit), _done(done) {}
|
||||
|
||||
logger(logger&& other) {
|
||||
_exit = other._exit;
|
||||
_done = other._done;
|
||||
other._done = false;
|
||||
}
|
||||
|
||||
~logger() {
|
||||
if(_done) {
|
||||
std::cerr << EndColor << "\n";
|
||||
if(_exit) abort();
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(logger&& other) {
|
||||
_exit = other._exit;
|
||||
_done = other._done;
|
||||
other._done = false;
|
||||
}
|
||||
|
||||
logger&& indent(size_t n, size_t tab_size = 2) {
|
||||
for(size_t i=0; i<n; i++) {
|
||||
for(size_t j=0; j<tab_size; j++) {
|
||||
std::cerr << " ";
|
||||
}
|
||||
}
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template<typename T> logger&& operator<<(T t) {
|
||||
std::cerr << t;
|
||||
return std::move(*this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# define LOG(color, exit) (ccutil::logger(exit) << color)
|
||||
# define INFO (ccutil::logger_base())
|
||||
# define ASSERT(cond) (ccutil::logger_base())
|
||||
#else
|
||||
# define LOG(color, exit) (ccutil::logger(exit) << ccutil::SourceColor << "[" << __FILE__ << ":" << __LINE__ << "] " << color)
|
||||
# define INFO LOG(ccutil::InfoColor, false)
|
||||
# define ASSERT(cond) (cond) ? ccutil::logger_base() : FATAL
|
||||
#endif
|
||||
|
||||
#define WARNING LOG(ccutil::WarningColor, false)
|
||||
#define PREFER(cond) (cond) ? ccutil::logger_base() : WARNING
|
||||
|
||||
#define FATAL LOG(ccutil::FatalColor, true)
|
||||
#define REQUIRE(cond) (cond) ? ccutil::logger_base() : FATAL
|
||||
|
||||
#endif
|
34
libcoz/ccutil/spinlock.h
Normal file
34
libcoz/ccutil/spinlock.h
Normal file
@ -0,0 +1,34 @@
|
||||
#if !defined(CCUTIL_SPINLOCK_H)
|
||||
#define CCUTIL_SPINLOCK_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class spinlock {
|
||||
public:
|
||||
inline void lock() {
|
||||
while(_flag.test_and_set()) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/*
|
||||
* NOTE: "rep nop" works on all Intel architectures and has the same
|
||||
* encoding as "pause" on the newer ones.
|
||||
*/
|
||||
__asm__ __volatile__ ("rep nop");
|
||||
#else
|
||||
/* nothing */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline bool trylock() {
|
||||
return !_flag.test_and_set();
|
||||
}
|
||||
|
||||
inline void unlock() {
|
||||
_flag.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_flag _flag = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
#endif
|
73
libcoz/ccutil/static_map.h
Normal file
73
libcoz/ccutil/static_map.h
Normal file
@ -0,0 +1,73 @@
|
||||
#if !defined(CCUTIL_STATIC_MAP_H)
|
||||
#define CCUTIL_STATIC_MAP_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
template<typename K, typename V, K NullKey=0, size_t MapSize=4096>
|
||||
class static_map {
|
||||
public:
|
||||
V* insert(K key) {
|
||||
size_t bucket = get_bucket(key);
|
||||
size_t offset = 0;
|
||||
while(offset < MapSize) {
|
||||
K empty_key = NullKey;
|
||||
size_t index = (bucket + offset) % MapSize;
|
||||
if(_entries[index]._tag.compare_exchange_weak(empty_key, key)) {
|
||||
// Successfully tagged the entry
|
||||
return &_entries[index]._value;
|
||||
}
|
||||
// Advance to the next bucket
|
||||
offset++;
|
||||
}
|
||||
|
||||
// TODO: Could just keep probing until a slot opens, but livelock would be possible...
|
||||
WARNING << "Thread state map is full!";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
V* find(K key) {
|
||||
size_t bucket = get_bucket(key);
|
||||
size_t offset = 0;
|
||||
while(offset < MapSize) {
|
||||
size_t index = (bucket + offset) % MapSize;
|
||||
if(_entries[index]._tag.load() == key) {
|
||||
return &_entries[index]._value;
|
||||
}
|
||||
// Advance to the next bucket
|
||||
offset++;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void remove(K key) {
|
||||
size_t bucket = get_bucket(key);
|
||||
size_t offset = 0;
|
||||
while(offset < MapSize) {
|
||||
size_t index = (bucket + offset) % MapSize;
|
||||
if(_entries[index]._tag.load() == key) {
|
||||
_entries[index]._tag.store(NullKey);
|
||||
return;
|
||||
}
|
||||
// Advance to the next bucket
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t get_bucket(K key) {
|
||||
// TODO: Support hash function parameter if this class is reused
|
||||
return key % MapSize;
|
||||
}
|
||||
|
||||
struct entry {
|
||||
std::atomic<K> _tag;
|
||||
V _value;
|
||||
};
|
||||
|
||||
entry _entries[MapSize];
|
||||
};
|
||||
|
||||
#endif
|
10
libcoz/ccutil/thread.h
Normal file
10
libcoz/ccutil/thread.h
Normal file
@ -0,0 +1,10 @@
|
||||
#if !defined(CCUTIL_THREAD_H)
|
||||
#define CCUTIL_THREAD_H
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
static inline pid_t gettid() {
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
#endif
|
85
libcoz/ccutil/timer.h
Normal file
85
libcoz/ccutil/timer.h
Normal file
@ -0,0 +1,85 @@
|
||||
#if !defined(CCUTIL_TIMER_H)
|
||||
#define CCUTIL_TIMER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "thread.h"
|
||||
|
||||
class timer {
|
||||
public:
|
||||
timer() : _initialized(false) {}
|
||||
|
||||
timer(int sig) {
|
||||
struct sigevent ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.sigev_notify = SIGEV_THREAD_ID;
|
||||
ev.sigev_signo = sig;
|
||||
ev._sigev_un._tid = gettid();
|
||||
|
||||
REQUIRE(timer_create(CLOCK_THREAD_CPUTIME_ID, &ev, &_timer) == 0)
|
||||
<< "Failed to create timer!";
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
timer(timer&& other) {
|
||||
_timer = other._timer;
|
||||
_initialized = other._initialized;
|
||||
other._initialized = false;
|
||||
}
|
||||
|
||||
~timer() {
|
||||
if(_initialized) {
|
||||
REQUIRE(timer_delete(_timer) == 0) << "Failed to delete timer!";
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(timer&& other) {
|
||||
_timer = other._timer;
|
||||
_initialized = other._initialized;
|
||||
other._initialized = false;
|
||||
}
|
||||
|
||||
void start_interval(size_t time_ns) {
|
||||
ASSERT(_initialized) << "Can't start an uninitialized timer";
|
||||
|
||||
long ns = time_ns % 1000000000;
|
||||
time_t s = (time_ns - ns) / 1000000000;
|
||||
|
||||
struct itimerspec ts;
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
ts.it_interval.tv_sec = s;
|
||||
ts.it_interval.tv_nsec = ns;
|
||||
ts.it_value.tv_sec = s;
|
||||
ts.it_value.tv_nsec = ns;
|
||||
|
||||
REQUIRE(timer_settime(_timer, 0, &ts, NULL) == 0) << "Failed to start interval timer";
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
void start_oneshot(size_t time_ns) {
|
||||
ASSERT(_initialized) << "Can't start an uninitialized timer";
|
||||
|
||||
long ns = time_ns % 1000000000;
|
||||
time_t s = (time_ns - ns) / 1000000000;
|
||||
|
||||
struct itimerspec ts;
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
ts.it_value.tv_sec = s;
|
||||
ts.it_value.tv_nsec = ns;
|
||||
|
||||
REQUIRE(timer_settime(_timer, 0, &ts, NULL) == 0) << "Failed to start one-shot timer";
|
||||
}
|
||||
|
||||
private:
|
||||
timer(const timer&) = delete;
|
||||
void operator=(const timer&) = delete;
|
||||
|
||||
timer_t _timer;
|
||||
bool _initialized;
|
||||
};
|
||||
|
||||
#endif
|
62
libcoz/ccutil/wrapped_array.h
Normal file
62
libcoz/ccutil/wrapped_array.h
Normal file
@ -0,0 +1,62 @@
|
||||
#if !defined(CCUTIL_WRAPPED_ARRAY_H)
|
||||
#define CCUTIL_WRAPPED_ARRAY_H
|
||||
|
||||
namespace ccutil {
|
||||
template<class T> class wrapped_array {
|
||||
private:
|
||||
T* _base;
|
||||
size_t _size;
|
||||
public:
|
||||
// Construct an array wrapper from a base pointer and array size
|
||||
wrapped_array(T* base, size_t size) : _base(base), _size(size) {}
|
||||
wrapped_array(const wrapped_array& other) : _base(other._base), _size(other._size) {}
|
||||
|
||||
// Get the size of the wrapped array
|
||||
size_t size() { return _size; }
|
||||
|
||||
// Access an element by index
|
||||
T& operator[](size_t i) { return _base[i]; }
|
||||
|
||||
// Get a slice of this array, from a start index (inclusive) to end index (exclusive)
|
||||
wrapped_array<T> slice(size_t start, size_t end) {
|
||||
return wrapped_array<T>(&_base[start], end - start);
|
||||
}
|
||||
|
||||
operator T*() {
|
||||
return _base;
|
||||
}
|
||||
|
||||
// Iterator class for convenient range-based for loop support
|
||||
class iterator {
|
||||
private:
|
||||
T* _p;
|
||||
public:
|
||||
// Start the iterator at a given pointer
|
||||
iterator(T* p) : _p(p) {}
|
||||
|
||||
// Advance to the next element
|
||||
void operator++() { ++_p; }
|
||||
void operator++(int) { _p++; }
|
||||
|
||||
// Get the current element
|
||||
T& operator*() const { return *_p; }
|
||||
|
||||
// Compare iterators
|
||||
bool operator==(const iterator& other) const { return _p == other._p; }
|
||||
bool operator!=(const iterator& other) const { return _p != other._p; }
|
||||
};
|
||||
|
||||
// Get an iterator positioned at the beginning of the wrapped array
|
||||
iterator begin() { return iterator(_base); }
|
||||
|
||||
// Get an iterator positioned at the end of the wrapped array
|
||||
iterator end() { return iterator(&_base[_size]); }
|
||||
};
|
||||
|
||||
// Function for automatic template argument deduction
|
||||
template<class A> wrapped_array<A> wrap_array(A* base, size_t size) {
|
||||
return wrapped_array<A>(base, size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user