-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathkalloc.hh
More file actions
165 lines (139 loc) · 3.48 KB
/
Copy pathkalloc.hh
File metadata and controls
165 lines (139 loc) · 3.48 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#pragma once
#include "percpu.hh"
#include "atomic_util.hh"
#include <atomic>
#include <typeinfo>
#include <memory>
template<class T>
struct vptr64 {
typedef u128 __inttype;
typedef T __ptrtype;
__inttype _a;
T ptr() const { return (T) iptr(); }
u64 iptr() const { return _a & 0xffffffffffffffffULL; }
u64 v() const { return _a >> 64; }
vptr64(T p, u64 v) : _a((((u128)v)<<64) | (u64) p) {}
vptr64(u128 a) : _a(a) {}
};
template<class T>
struct vptr48 {
typedef u64 __inttype;
typedef T __ptrtype;
__inttype _a;
T ptr() const {
u64 i = iptr();
if (i & (1ULL << 47))
i += 0xffffULL << 48;
return (T) i;
}
u64 iptr() const { return _a & 0xffffffffffffULL; }
u16 v() const { return _a >> 48; }
vptr48(T p, u16 v) : _a((((u64)v)<<48) | (((u64)p) & 0xffffffffffffULL)) {}
vptr48(u64 a) : _a(a) {}
};
template<class VPTR>
class versioned {
private:
std::atomic<typename VPTR::__inttype> _a;
public:
VPTR load() { return VPTR(_a.load()); }
bool compare_exchange(const VPTR &expected, typename VPTR::__ptrtype desired) {
VPTR n(desired, expected.v() + 1);
return cmpxch(&_a, expected._a, n._a);
}
};
enum {
slab_perf,
slab_type_max
};
// std allocator
template<class T>
class allocator_base
{
public:
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
pointer
address(reference x) const noexcept
{
return std::addressof(x);
}
const_pointer
address(const_reference x) const noexcept
{
return std::addressof(x);
}
template<class U, class... Args>
void
construct(U* p, Args&&... args)
{
::new((void *)p) U(std::forward<Args>(args)...);
}
template <class U>
void
destroy(U* p)
{
p->~U();
}
};
// Standard allocator that uses the kernel page allocator. This
// satisfies both the standard Allocator requirement as well as the
// ZAllocator requirement.
template<class T>
class kalloc_allocator : public allocator_base<T>
{
public:
template <class U> struct rebind { typedef kalloc_allocator<U> other; };
kalloc_allocator() = default;
kalloc_allocator(const kalloc_allocator&) = default;
template<class U> kalloc_allocator(const kalloc_allocator<U>&) noexcept { }
T*
allocate(std::size_t n, const void *hint = 0)
{
if (n * sizeof(T) != PGSIZE)
panic("%s cannot allocate %zu bytes", __PRETTY_FUNCTION__, n * sizeof(T));
return (T*)kalloc(typeid(T).name());
}
void
deallocate(T* p, std::size_t n)
{
if (n * sizeof(T) != PGSIZE)
panic("%s cannot deallocate %zu bytes", __PRETTY_FUNCTION__,
n * sizeof(T));
kfree(p);
}
std::size_t
max_size() const noexcept
{
return PGSIZE;
}
// ZAllocator methods
T*
default_allocate()
{
if (sizeof(T) != PGSIZE)
panic("%s cannot allocate %zu bytes", __PRETTY_FUNCTION__, sizeof(T));
if (std::has_trivial_default_constructor<T>::value) {
// A trivial default constructor will zero-initialize
// everything, so we can short-circuit this by allocating a zero
// page.
return (T*)zalloc(typeid(T).name());
}
// Fall back to usual allocation and default construction
T *p = allocate(1);
try {
// Unqualified lookup doesn't find declarations in dependent
// bases. Hence "this->".
this->construct(p);
} catch (...) {
deallocate(p, 1);
throw;
}
return p;
}
};