-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuddy.c
114 lines (107 loc) · 4.27 KB
/
buddy.c
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
/* a buddy system
*/
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include "buddy.h"
/* the maximum block size is 2**(MAX-1) */
#define MAX 30
/* all the freelists are initially empty */
static void * freelists[MAX] = { NULL };
void * buddyalloc( int i ) {
/* buddy system allocate one block of size 2 to the i */
void * p;
if (i >= MAX) return NULL;
if (freelists[i] != NULL) { /* easy case */
p = freelists[i];
freelists[i] = *(void **)p;
} else { /* freelists[i] == NULL, hard case */
p = buddyalloc( i + 1 );
if (p != NULL) { /* split oversized block */
void * b = (void *)(((intptr_t) p) ^ (1 << i));
*(void **)b = NULL;
freelists[i] = b;
}
}
return p;
}
void buddyfree( void * p, int i ) {
/* buddy system free the block p of size 2 to the i */
void * b; /* candidate for buddy of p */
void ** pb = &freelists[i]; /* pointer b */
/* search for buddy in free list */
for (;;) { /* loop exit by break*/
b = *pb;
if (b == NULL) { /* search reached end of list */
/* put p at end of list */
*(void **)p = NULL;
*pb = p;
/* quit loop */
break;
}
if (((intptr_t)p) == (((intptr_t)b) ^ (1 << i))) {
/* unlink b from its free list */
*pb = *(void **)b;
/* compute address of merged blocks */
p = (void *)(((intptr_t)p) & ((intptr_t)b));
/* free result of merger */
buddyfree( p, i + 1 );
break;
}
/* walk down list */
pb = (void **)b;
}
}
void enlargeheap( int i ) {
/* enlarge the heap to guarantee a free block of size 2**i */
intptr_t twotothei;
void * p; /* start of new block of memory (or remainder of it ) */
void * q; /* end of new block of memory */
void * nextp; /* proposed next value of p */
/* guarantee an aligned block of size 2**i by getting twice that */
i = i + 1;
twotothei = 1 << i;
/* guarantee minimum size */
while (twotothei < sizeof( void * )) {
i = i + 1;
twotothei = twotothei << 1;
}
/* get a block of memory from p to just before q */
p = sbrk( twotothei );
q = sbrk( 0 );
/* it's possible that allocation will fail */
if ((p == q) || (((intptr_t)p) == -1) || p == NULL ) return;
/* at this point, the original value of i is irrelevant */
/* First chop block into successively larger free blocks */
i = 0;
twotothei = 1;
for (;;) { /* exit by break */
/* find the largest block compatible with the address */
while ((((intptr_t)p) & (twotothei)) == 0) {
i = i + 1;
twotothei = twotothei << 1;
}
/* now, p is xxxx10000 and twotothei is 000010000 */
nextp = (void *)(((intptr_t)p) + twotothei);
if (nextp >= q) break;
/* chop off a chip and free it if big enough */
if (twotothei >= sizeof( void * )) buddyfree( p, i );
p = nextp;
}
/* Second chop what's left into successively smaller free blocks */
do {
/* the proposed nextp might be too large */
while (nextp > q) {
i = i - 1;
twotothei = twotothei >> 1;
nextp = (void *)(((intptr_t)p) + twotothei);
}
/* chop off a chip and free it if big enough */
if (twotothei >= sizeof( void * )) buddyfree( p, i );
/* walk on to the next step */
p = nextp;
i = i - 1;
twotothei = twotothei >> 1;
nextp = (void *)(((intptr_t)p) + twotothei);
} while (p < q);
}