diff options
author | Jan Huwald <jh@sotun.de> | 2012-05-07 20:01:51 (GMT) |
---|---|---|
committer | Jan Huwald <jh@sotun.de> | 2012-05-07 20:01:51 (GMT) |
commit | 420d2ef464d4a741028e132e662d5626806a41f5 (patch) | |
tree | 1aca6eb512e4ed0fb5f3c10c528cb998b6ffd695 /core/mempool.hpp |
Diffstat (limited to 'core/mempool.hpp')
-rw-r--r-- | core/mempool.hpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/core/mempool.hpp b/core/mempool.hpp new file mode 100644 index 0000000..a5ac07b --- /dev/null +++ b/core/mempool.hpp @@ -0,0 +1,156 @@ +#ifndef qEzyOXbTTD6KlhKDUsawdWmx6c0 +#define qEzyOXbTTD6KlhKDUsawdWmx6c0 + +#include <assert.h> +#include <fcntl.h> +#include <malloc.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string> + +#include <boost/utility.hpp> + +using std::string; + +struct MemPool : boost::noncopyable { + explicit MemPool(size_t size); // anonymous in-memory-pool + MemPool(size_t size, int fd); // mmap()ed memory pool + MemPool(size_t size, const string filename); // mmap()ed memory pool + MemPool(MemPool &&src); // move ctor + MemPool& operator=(MemPool&&); + MemPool& operator=(MemPool&) = delete; + MemPool& operator=(MemPool) = delete; + + ~MemPool(); + + inline void* operator() () const; // return memory region; TODO: pure attr + inline size_t getSize() const; + void sync() const; // call msync() + void advise(size_t start, size_t len, int adv); + +protected: + void *base; + size_t size; + bool isMMap; + + void doMMap(int fd, size_t size); + int openMMappableFile(const string filename, size_t size); + +private: + static char* global_offset; + MemPool() = delete; + MemPool(const MemPool&) = delete; +}; + +char* MemPool::global_offset = (char*) (void*) 0x2fffff000000; + +inline void* MemPool::operator() () const { + return base; +} + +inline size_t MemPool::getSize() const { + return size; +} + +MemPool::MemPool(size_t size) : size(size), isMMap(false) { + if (size == 0) { + base = NULL; + }else{ + base = malloc(size); + assert(base != NULL); + } +} + +MemPool::MemPool(size_t size, int fd) : size(size),isMMap(true) { + if (size == 0) { + base = NULL; + }else{ + doMMap(fd, size); + } +} + +MemPool::MemPool(size_t size, const string filename) : size(size), isMMap(true) { + if (size == 0) { + base = NULL; + }else{ + doMMap(openMMappableFile(filename, size), size); + } +} + +MemPool::MemPool(MemPool &&src) : base(src.base), size(src.size), isMMap(src.isMMap) { + // std::cout << "Mempool " << base << " moved via copy" << std::endl; + src.base = NULL; + src.size = 0; +} + +MemPool& MemPool::operator= (MemPool &&src) { + // std::cout << "Mempool " << base << " moved via assignment" << std::endl; + base = src.base; + size = src.size; + isMMap = src.isMMap; + src.base = NULL; + src.size = 0; + return *this; +} + +MemPool::~MemPool() { + // std::cout << "Mempool " << base << " terminated"; + if (size == 0 or base == NULL) { + // std::cout << " from move" << std::endl; + return; + }else{ + // std::cout << std::endl; + } + if (isMMap) { + sync(); + munmap(base, size); + }else{ + free(base); + } +} + +void MemPool::sync() const { + if (isMMap) + msync(base, size, MS_SYNC); +} + +void MemPool::advise(size_t start, size_t len, int adv) { + // adjust region to page boundary (defensive) + if (start & 4095) { + len -= 4096 - (start & 4095); + len &= ~4095; + start &= 4095; + start +=1; + } + // detect underflow and to large len + if (len < size) { + assert(madvise((char*) base + start, len, adv) == 0); + } +} + +void MemPool::doMMap(int fd, size_t size) { + base = (void*) mmap((void*) global_offset, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NONBLOCK, fd, 0); + assert(base != MAP_FAILED); + assert(base == (void*) global_offset); + global_offset += ((size / 4096 + 1) * 4096) + 1024 * 4096; +} + +int MemPool::openMMappableFile(const string filename, size_t size) { + int fd = open(filename.c_str(), O_RDWR | O_CREAT | O_LARGEFILE | O_NOATIME, 0644); + assert(fd != -1); + + // check if the file size is correct + struct stat st; + fstat(fd, &st); + if ((size_t) st.st_size < size) { + // write one byte at the end of the file to make it big enough for the later mmap call (mmap does not increase file size) + assert(lseek64(fd, size-1, SEEK_SET) != (off_t) -1); + char c(0); + assert(write(fd, &c, 1) == 1); + } + + return fd; +} + +#endif // qEzyOXbTTD6KlhKDUsawdWmx6c0 |