Permalink
Browse files

Pulled ccutil into libcoz. Refs #48

  • Loading branch information...
ccurtsinger committed Nov 23, 2016
1 parent 61bb482 commit 3470416c67d77d6e369b62ed1193bab85af70ce1
Showing with 348 additions and 14 deletions.
  1. +0 −11 deps.mk
  2. +2 −3 libcoz/Makefile
  3. +82 −0 libcoz/ccutil/log.h
  4. +34 −0 libcoz/ccutil/spinlock.h
  5. +73 −0 libcoz/ccutil/static_map.h
  6. +10 −0 libcoz/ccutil/thread.h
  7. +85 −0 libcoz/ccutil/timer.h
  8. +62 −0 libcoz/ccutil/wrapped_array.h
View
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
View
@@ -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
View
@@ -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
View
@@ -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
@@ -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
View
@@ -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
View
@@ -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
@@ -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

0 comments on commit 3470416

Please sign in to comment.