forked from apitrace/apitrace
/
mmap_allocator.hpp
143 lines (117 loc) · 3.09 KB
/
mmap_allocator.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#pragma once
#include <cstddef>
#include <string>
#include <iostream>
#include <memory>
#include <list>
#ifdef __unix__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#define ALLOC_CHUNK_SIZE 64 * 1024 * 1024L
/*
* Allocator that backs up memory with mmaped file
* File is grown by ALLOC_CHUNK_SIZE, this new region is mmaped then
* Nothing is deallocated
*/
class MmapedFileBuffer
{
private:
int fd;
off_t curChunkSize;
const size_t chunkSize;
std::list<void*> mmaps;
void* vptr;
std::string fileName;
MmapedFileBuffer(MmapedFileBuffer const&) = delete;
void operator=(MmapedFileBuffer const&) = delete;
void newMmap() {
ftruncate(fd, chunkSize * (mmaps.size() + 1));
vptr = mmap(NULL, chunkSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
chunkSize * mmaps.size());
mmaps.push_front(vptr);
curChunkSize = 0;
}
public:
MmapedFileBuffer()
: curChunkSize(0),
chunkSize(ALLOC_CHUNK_SIZE & ~(sysconf(_SC_PAGE_SIZE) - 1))
{
char templ[] = ".pbtmpXXXXXX";
fd = mkstemp(templ);
fileName = templ;
newMmap();
}
~MmapedFileBuffer() {
close(fd);
for (auto &m : mmaps) {
munmap(m, chunkSize);
}
unlink(fileName.c_str());
}
void* allocate(size_t size) {
if ((curChunkSize + size) > chunkSize) {
newMmap();
}
void* addr = static_cast<char*>(vptr) + curChunkSize;
curChunkSize += size;
return addr;
}
};
template <class T>
class MmapAllocator
{
private:
std::shared_ptr<MmapedFileBuffer> file;
void* vptr;
template<class U>
friend class MmapAllocator;
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
MmapAllocator()
{
file = std::make_shared<MmapedFileBuffer>();
};
~MmapAllocator() {
};
template <class U> MmapAllocator(const MmapAllocator<U>& other)
: file(other.file), vptr(other.vptr) {
};
T* allocate(std::size_t n) {
return reinterpret_cast<T*>(file->allocate(n * sizeof(T)));
};
void deallocate(T* p, std::size_t n) {};
template <typename U, typename... Args>
void construct(U* p, Args&&... args) {::new (static_cast<void*>(p) ) U (std::forward<Args> (args)...);}
template <typename U>
void destroy(U* p) {p->~U();}
size_type max_size() const {
return ALLOC_CHUNK_SIZE / sizeof(T);
}
template<typename U>
struct rebind
{
typedef MmapAllocator<U> other;
};
};
template <class T, class U>
bool operator==(const MmapAllocator<T>&, const MmapAllocator<U>&) {
return true;
}
template <class T, class U>
bool operator!=(const MmapAllocator<T>& a, const MmapAllocator<U>& b) {
return !(a==b);
}
#else
// default allocator
template<class T>
using MmapAllocator = std::allocator<T>;
#endif