1 #include "cado.h" // IWYU pragma: keep 2 #include <cstdio> 3 #include <string> // std::string 4 #include <exception> // std::terminate 5 6 #include <sys/mman.h> // for PROT_READ, mmap, munmap, MAP_SHARED, PROT_WRITE 7 #include <sys/stat.h> // for fstat, stat 8 #include <fcntl.h> // O_RDONLY etc // IWYU pragma: keep 9 #include <unistd.h> // for sysconf, _SC_PAGE_SIZE, close 10 11 #include "mmap_allocator.hpp" 12 13 14 /* This is inspired from https://github.com/johannesthoma/mmap_allocator 15 * License is LGPL. 16 * The version here has been trimmed down significantly, look for uptream 17 * version for more features */ 18 19 #define ALIGN_TO_PAGE(x) ((x) & ~(sysconf(_SC_PAGE_SIZE) - 1)) 20 #define UPPER_ALIGN_TO_PAGE(x) ALIGN_TO_PAGE((x)+(sysconf(_SC_PAGE_SIZE)-1)) 21 #define OFFSET_INTO_PAGE(x) ((x) & (sysconf(_SC_PAGE_SIZE) - 1)) 22 23 namespace mmap_allocator_details { mapping(const char * filename,access_mode amode,offset_type offset,size_type length)24 mmapped_file::mapping::mapping(const char * filename, access_mode amode, offset_type offset, size_type length) { 25 if (!filename || *filename == '\0') { 26 throw mmap_allocator_exception("mmapped_file not correctly initialized: filename is empty."); 27 } 28 int mode; 29 int prot; 30 int mmap_mode = 0; 31 32 switch (amode) { 33 case READ_ONLY: 34 mode = O_RDONLY; 35 prot = PROT_READ; 36 mmap_mode |= MAP_SHARED; 37 break; 38 case READ_WRITE_SHARED: 39 mode = O_RDWR; 40 prot = PROT_READ | PROT_WRITE; 41 mmap_mode |= MAP_SHARED; 42 break; 43 case READ_WRITE_PRIVATE: 44 mode = O_RDONLY; 45 prot = PROT_READ | PROT_WRITE; 46 mmap_mode |= MAP_PRIVATE; 47 break; 48 default: 49 throw mmap_allocator_exception("Internal error"); 50 break; 51 } 52 53 fd = open(filename, mode); 54 if (fd < 0) 55 throw mmap_allocator_exception(std::string("Error opening file ") + filename); 56 57 if (length == std::numeric_limits<size_type>::max()) { 58 /* well, we really want the file length, not more ! */ 59 struct stat sbuf[1]; 60 if (fstat(fd, sbuf) < 0) 61 throw mmap_allocator_exception("stat() error"); 62 length = sbuf->st_size; 63 } 64 offset_mapped = ALIGN_TO_PAGE(offset); 65 length_mapped = UPPER_ALIGN_TO_PAGE(length + offset - offset_mapped); 66 area = mmap(NULL, length_mapped, prot, mmap_mode, fd, offset_mapped); 67 } 68 ~mapping()69 mmapped_file::mapping::~mapping() { 70 if (munmap(area, length_mapped) < 0) 71 std::terminate(); /* munmap() error in dtor, fatal */ 72 if (close(fd) < 0) 73 std::terminate(); /* close() error in dtor, fatal */ 74 } 75 get(offset_type offset,size_type length)76 void * mmapped_file::mapping::get(offset_type offset, size_type length) { 77 if (offset >= offset_mapped && length + offset <= offset_mapped + length_mapped) { 78 return ((char*)area)+offset-offset_mapped; 79 } else { 80 throw mmap_allocator_exception("Cannot get range outside mapping bounds"); 81 } 82 } 83 put(void *,offset_type,size_type)84 void mmapped_file::mapping::put(void *, offset_type, size_type) 85 { 86 /* in fact, we do nothing. We _could_ imagine keeping track 87 * of things, but what for, really ? 88 */ 89 } 90 } 91