-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathallocator.cpp
executable file
·185 lines (160 loc) · 5.45 KB
/
allocator.cpp
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include<iostream>
#include<cstdlib>
#include<cstring>
#include "allocator_interface.h"
#include "memlib.h"
#include "alloc_types.h"
#ifdef DEBUG
#include "visualizer.h"
// #define DEBUG_CHECK_AGGRESSIVE
#endif
namespace my
{
/*
* This checks that after the allocator has been initialized,
* it returns a valid pointer to arena_hdr
* Returns 0 iff none of the invariants are violated;
* returns a negative error code otherwise.
*/
int allocator::check()
{
// Delegate the heap consistency check to the arena_hdr
return ((arena_hdr*)(mem_heap_lo()))->check();
}
/*
* init - Initialize the malloc package. Called once before any other
* calls are made. This sets up the initial arena and creates a chunk.
*/
int allocator::init()
{
// Allocate memory for an arena header and its first chunk
// Conveniently, this is just under our slackness limit.
size_t initial_allocation = ARENA_HDR_SIZE + INITIAL_CHUNK_SIZE;
byte* new_mem = (byte*)mem_sbrk(initial_allocation);
if (new_mem == NULL) {
return -1; // Panic! Not out fault!
}
// Write in the arena header; chunk header written by arena initializer
arena_hdr* this_arena = (arena_hdr*)mem_heap_lo();
*this_arena = arena_hdr();
// Now that it's on the heap, we can finish initialization
this_arena->finalize();
this_arena->insert_chunk((node_t*) ((byte*)(mem_heap_lo()) + ARENA_HDR_SIZE));
// If we had failed, exceptions would have appeared elsewhere.
return 0;
}
/*
* malloc - Allocate a block by incrementing the brk pointer.
* Always allocate a block whose size is a multiple of the alignment.
*/
void * allocator::malloc(size_t size)
{
// Send this size to the lone arena for allocation
#ifdef DEBUG_VIS_MALLOC
// Use arena visualization
visualize_arena(((arena_hdr*)(mem_heap_lo())));
#endif
void* new_mem = ((arena_hdr*)(mem_heap_lo()))->malloc(size);
// For safety's sake, make sure we're given back something reasonable
// This replicated some of the functionality of the heap checker, but in
// this case, we'll still be able to backtrace.
assert(mem_heap_lo() <= new_mem);
assert(mem_heap_hi() >= new_mem);
assert((size_t)new_mem == ALIGN((size_t)new_mem));
#ifdef DEBUG_CHECK_AGGRESSIVE
int heap_status = check();
assert(heap_status == 0);
#endif
return new_mem;
}
/*
* free - Freeing a block does nothing.
*/
void allocator::free(void *ptr)
{
if (ptr == NULL)
return;
// Find arena control structure at the bottom of the heap and delegate.
#ifdef DEBUG_VIS_FREE
printf("** Begin Free Visualization **\n");
visualize_arena(((arena_hdr*)(mem_heap_lo())));
#endif
((arena_hdr*)(mem_heap_lo()))->free(ptr);
#ifdef DEBUG_VIS_FREE
visualize_arena(((arena_hdr*)(mem_heap_lo())));
printf("** End Free Visualization **\n");
#endif
}
/*
* realloc - Implemented simply in terms of malloc and free
*/
void * allocator::realloc(void *ptr, size_t size)
{
#ifdef DEBUG_VIS_REALLOC
printf("** Just about to realloc **\n");
visualize_arena(((arena_hdr*)(mem_heap_lo())));
#endif
/* Look for special case - reallocate a pointer to zero size -> free */
if (size == 0) {
free(ptr);
// Equivalent to a free, but free doesn't return anything.
// Return null to be safe.
return NULL;
}
/* Look for special case - reallocate a null pointer -> malloc */
if (ptr == NULL) {
return malloc(size); // return malloc(size)
}
/* Do a proper reallocation */
size_t old_size = ((arena_hdr*)(mem_heap_lo()))->size_of_alloc(ptr);
PRINT_TRACE("Asked for a realloc on %zu bytes.\n", old_size);
/* We can ask subordinate routines to try to do clever reallocation. */
/* If they fail, they will return NULL as a signal that we need to do a big,
slow malloc-copy-free to solve the problem. */
void* reallocated_ptr = ((arena_hdr*)(mem_heap_lo()))->realloc(ptr, size, old_size);
if (reallocated_ptr != NULL) {
// This indicates something clever succeeded.
PRINT_TRACE("A clever in-place realloc was done.\n");
return reallocated_ptr;
}
/* All right, do a malloc-copy-free */
/* Allocate a new chunk of memory, and fail if that allocation fails. */
void* newptr = malloc(size);
if (newptr == NULL) {
return NULL;
}
/* Get the size of the old block of memory. Take a peek at malloc(),
where we stashed this in the SIZE_T_SIZE bytes directly before the
address we returned. Now we can back up by that many bytes and read
the size. */
/* If the new block is smaller than the old one, we have to stop copying
early so that we don't write off the end of the new block of memory. */
if (size < old_size) {
old_size = size;
}
PRINT_TRACE("Reallocating with a copy of size %zu.\n", size);
/* This is a standard library call that performs a simple memory copy. */
std::memcpy(newptr, ptr, old_size);
PRINT_TRACE("...memcpy done.\n");
/* Release the old block. */
PRINT_TRACE("...and now, freeing the old pointer.\n");
free(ptr);
/* Return a pointer to the new block. */
return newptr;
}
/* call mem_reset_brk. */
void allocator::reset_brk()
{
mem_reset_brk() ;
}
/* call mem_heap_lo */
void * allocator::heap_lo()
{
return mem_heap_lo() ;
}
/* call mem_heap_hi */
void * allocator::heap_hi()
{
return mem_heap_hi() ;
}
};