1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM File System. |
3 |
|
|
* |
4 |
|
|
* Ensures that cvmfs aborts on out-of-memory errors. |
5 |
|
|
*/ |
6 |
|
|
|
7 |
|
|
#ifndef CVMFS_SMALLOC_H_ |
8 |
|
|
#define CVMFS_SMALLOC_H_ |
9 |
|
|
|
10 |
|
|
#include <stdint.h> |
11 |
|
|
#include <stdlib.h> |
12 |
|
|
#include <sys/mman.h> |
13 |
|
|
|
14 |
|
|
#include <cassert> |
15 |
|
|
// #include <cstdio> |
16 |
|
|
|
17 |
|
|
#include <limits> |
18 |
|
|
|
19 |
|
|
#ifdef __APPLE__ |
20 |
|
|
#define PLATFORM_MAP_ANONYMOUS MAP_ANON |
21 |
|
|
#else |
22 |
|
|
#define PLATFORM_MAP_ANONYMOUS MAP_ANONYMOUS |
23 |
|
|
#endif |
24 |
|
|
|
25 |
|
|
|
26 |
|
|
#ifdef CVMFS_NAMESPACE_GUARD |
27 |
|
|
namespace CVMFS_NAMESPACE_GUARD { |
28 |
|
|
#endif |
29 |
|
|
|
30 |
|
|
// Checkerboard marker (binary 101010...) |
31 |
|
|
const uint32_t kMemMarker = 0xAAAAAAAA; |
32 |
|
|
|
33 |
|
|
/** |
34 |
|
|
* Round up size to the next larger multiple of 8. This is used to enforce |
35 |
|
|
* 8-byte alignment. |
36 |
|
|
*/ |
37 |
|
|
static inline uint64_t RoundUp8(const uint64_t size) { |
38 |
|
|
return (size + 7) & ~static_cast<uint64_t>(7); |
39 |
|
|
} |
40 |
|
|
|
41 |
|
|
static inline void * __attribute__((used)) smalloc(size_t size) { |
42 |
|
|
void *mem = malloc(size); |
43 |
|
|
assert((mem || (size == 0)) && "Out Of Memory"); |
44 |
|
|
return mem; |
45 |
|
|
} |
46 |
|
|
|
47 |
|
|
static inline void * __attribute__((used)) srealloc(void *ptr, size_t size) { |
48 |
|
|
void *mem = realloc(ptr, size); |
49 |
|
|
assert((mem || (size == 0)) && "Out Of Memory"); |
50 |
|
|
return mem; |
51 |
|
|
} |
52 |
|
|
|
53 |
|
|
static inline void * __attribute__((used)) scalloc(size_t count, size_t size) { |
54 |
|
|
void *mem = calloc(count, size); |
55 |
|
|
assert((mem || ((count * size) == 0)) && "Out Of Memory"); |
56 |
|
|
return mem; |
57 |
|
|
} |
58 |
|
|
|
59 |
|
|
static inline void * __attribute__((used)) smmap(size_t size) { |
60 |
|
|
// TODO(reneme): make page size platform independent |
61 |
|
|
assert(size > 0); |
62 |
|
|
assert(size < std::numeric_limits<size_t>::max() - 4096); |
63 |
|
|
|
64 |
|
|
const int anonymous_fd = -1; |
65 |
|
|
const off_t offset = 0; |
66 |
|
|
size_t pages = ((size + 2*sizeof(size_t))+4095)/4096; // round to full page |
67 |
|
|
unsigned char *mem = static_cast<unsigned char *>( |
68 |
|
|
mmap(NULL, |
69 |
|
|
pages*4096, |
70 |
|
|
PROT_READ | PROT_WRITE, |
71 |
|
|
MAP_PRIVATE | PLATFORM_MAP_ANONYMOUS, |
72 |
|
|
anonymous_fd, |
73 |
|
|
offset)); |
74 |
|
|
// printf("SMMAP %d bytes at %p\n", pages*4096, mem); |
75 |
|
|
assert((mem != MAP_FAILED) && "Out Of Memory"); |
76 |
|
|
*(reinterpret_cast<size_t *>(mem)) = kMemMarker; |
77 |
|
|
*(reinterpret_cast<size_t *>(mem) + 1) = pages; |
78 |
|
|
return mem + 2*sizeof(size_t); |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
static inline void __attribute__((used)) smunmap(void *mem) { |
82 |
|
|
unsigned char *area = static_cast<unsigned char *>(mem); |
83 |
|
|
area = area - sizeof(size_t); |
84 |
|
|
size_t pages = *(reinterpret_cast<size_t *>(area)); |
85 |
|
|
int retval = munmap(area-sizeof(size_t), pages*4096); |
86 |
|
|
// printf("SUNMMAP %d bytes at %p\n", pages*4096, area); |
87 |
|
|
assert((retval == 0) && "Invalid umnmap"); |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
|
91 |
|
|
/** |
92 |
|
|
* Used when the caller remembers the size, so that it can call sxunmap later. |
93 |
|
|
*/ |
94 |
|
|
static inline void * __attribute__((used)) sxmmap(size_t size) { |
95 |
|
|
const int anonymous_fd = -1; |
96 |
|
|
const off_t offset = 0; |
97 |
|
|
void *mem = mmap(NULL, |
98 |
|
|
size, |
99 |
|
|
PROT_READ | PROT_WRITE, |
100 |
|
|
MAP_PRIVATE | PLATFORM_MAP_ANONYMOUS, |
101 |
|
|
anonymous_fd, |
102 |
|
|
offset); |
103 |
|
|
assert((mem != MAP_FAILED) && "Out Of Memory"); |
104 |
|
|
return mem; |
105 |
|
|
} |
106 |
|
|
|
107 |
|
|
|
108 |
|
|
/** |
109 |
|
|
* Free memory acquired by sxmmap. |
110 |
|
|
*/ |
111 |
|
|
static inline void __attribute__((used)) sxunmap(void *mem, size_t size) { |
112 |
|
|
int retval = munmap(mem, size); |
113 |
|
|
assert((retval == 0) && "Invalid umnmap"); |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
|
117 |
|
|
/** |
118 |
|
|
* Pointer is aligned at a multiple of the size. The size has to be a multiple |
119 |
|
|
* of 2MB. |
120 |
|
|
*/ |
121 |
|
|
static inline void * __attribute__((used)) sxmmap_align(size_t size) { |
122 |
|
|
assert((size % (2 * 1024 * 1024)) == 0); |
123 |
|
|
char *mem = reinterpret_cast<char *>(sxmmap(2 * size)); |
124 |
|
|
uintptr_t head = size - (uintptr_t(mem) % size); |
125 |
|
|
sxunmap(mem, head); |
126 |
|
|
mem += head; |
127 |
|
|
uintptr_t tail = size - head; |
128 |
|
|
if (tail > 0) |
129 |
|
|
sxunmap(mem + size, tail); |
130 |
|
|
return mem; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
|
134 |
|
|
#ifdef CVMFS_NAMESPACE_GUARD |
135 |
|
|
} // namespace CVMFS_NAMESPACE_GUARD |
136 |
|
|
#endif |
137 |
|
|
|
138 |
|
|
#endif // CVMFS_SMALLOC_H_ |