Pulled ccutil into libcoz. Refs #48

This commit is contained in:
Charlie Curtsinger 2016-11-22 18:47:24 -06:00
parent 61bb4824d4
commit 3470416c67
8 changed files with 348 additions and 14 deletions

11
deps.mk
View File

@ -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

View File

@ -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
View 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
View 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

View 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
View 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
View 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

View 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