-
Notifications
You must be signed in to change notification settings - Fork 6
/
alloc.h
136 lines (116 loc) · 3.59 KB
/
alloc.h
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
#ifndef GASSYFS_ALLOC_H_
#define GASSYFS_ALLOC_H_
/*
* Adapted from:
* https://github.com/StanfordLegion/legion/blob/stable/runtime/realm/mem_impl.cc
*
* This might not be the best allocation strategy, but it should work for the
* time being.
*/
#include <cassert>
#include <deque>
#include <map>
#include <errno.h>
class Allocator {
public:
explicit Allocator(size_t size) {
alignment = 0;
free_blocks[0] = size;
}
off_t alloc(size_t size) {
assert(size);
if (alignment > 0) {
assert(0);
off_t leftover = size % alignment;
if (leftover > 0) {
size += (alignment - leftover);
}
}
// HACK: pad the size by a bit to see if we have people falling off
// the end of their allocations
size += 0;
if (free_blocks.empty())
return -ENOMEM;
std::map<off_t, off_t>::iterator it = free_blocks.end();
do {
--it;
if (it->second == (off_t)size) {
off_t retval = it->first;
free_blocks.erase(it);
return retval;
}
if (it->second > (off_t)size) {
off_t leftover = it->second - size;
off_t retval = it->first + leftover;
it->second = leftover;
return retval;
}
} while (it != free_blocks.begin());
return -ENOMEM;
}
void free(off_t offset, size_t size) {
assert(size);
if (alignment > 0) {
off_t leftover = size % alignment;
if (leftover > 0) {
size += (alignment - leftover);
}
}
if (!free_blocks.empty()) {
// find the first existing block that comes _after_ us
std::map<off_t, off_t>::iterator after = free_blocks.lower_bound(offset);
if (after != free_blocks.end()) {
// found one - is it the first one?
if (after == free_blocks.begin()) {
// yes, so no "before"
assert((offset + (off_t)size) <= after->first); // no overlap!
if((offset + (off_t)size) == after->first) {
// merge the ranges by eating the "after"
size += after->second;
free_blocks.erase(after);
}
free_blocks[offset] = size;
} else {
// no, get range that comes before us too
std::map<off_t, off_t>::iterator before = after;
before--;
// if we're adjacent to the after, merge with it
assert((offset + (off_t)size) <= after->first); // no overlap!
if((offset + (off_t)size) == after->first) {
// merge the ranges by eating the "after"
size += after->second;
free_blocks.erase(after);
}
// if we're adjacent with the before, grow it instead of adding
// a new range
assert((before->first + before->second) <= offset);
if((before->first + before->second) == offset) {
before->second += size;
} else {
free_blocks[offset] = size;
}
}
} else {
// nothing's after us, so just see if we can merge with the range
// that's before us
std::map<off_t, off_t>::iterator before = after;
before--;
// if we're adjacent with the before, grow it instead of adding
// a new range
assert((before->first + before->second) <= offset);
if((before->first + before->second) == offset) {
before->second += size;
} else {
free_blocks[offset] = size;
}
}
} else {
// easy case - nothing was free, so now just our block is
free_blocks[offset] = size;
}
}
private:
size_t alignment;
std::map<off_t, off_t> free_blocks;
};
#endif