os_kernel_lab/related_info/lab2/buddy_system.c
2015-03-22 14:49:24 +08:00

199 lines
4.4 KiB
C

#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
struct buddy2 {
unsigned size;
unsigned longest[1];
};
struct buddy2* buddy2_new( int size );
void buddy2_destroy( struct buddy2* self );
int buddy2_alloc(struct buddy2* self, int size);
void buddy2_free(struct buddy2* self, int offset);
int buddy2_size(struct buddy2* self, int offset);
void buddy2_dump(struct buddy2* self);
#define LEFT_LEAF(index) ((index) * 2 + 1)
#define RIGHT_LEAF(index) ((index) * 2 + 2)
#define PARENT(index) ( ((index) + 1) / 2 - 1)
#define IS_POWER_OF_2(x) (!((x)&((x)-1)))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ALLOC malloc
#define FREE free
static unsigned fixsize(unsigned size) {
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
return size+1;
}
struct buddy2* buddy2_new( int size ) {
struct buddy2* self;
unsigned node_size;
int i;
if (size < 1 || !IS_POWER_OF_2(size))
return NULL;
self = (struct buddy2*)ALLOC( 2 * size * sizeof(unsigned));
self->size = size;
node_size = size * 2;
for (i = 0; i < 2 * size - 1; ++i) {
if (IS_POWER_OF_2(i+1))
node_size /= 2;
self->longest[i] = node_size;
}
return self;
}
void buddy2_destroy( struct buddy2* self) {
FREE(self);
}
int buddy2_alloc(struct buddy2* self, int size) {
unsigned index = 0;
unsigned node_size;
unsigned offset = 0;
if (self==NULL)
return -1;
if (size <= 0)
size = 1;
else if (!IS_POWER_OF_2(size))
size = fixsize(size);
if (self->longest[index] < size)
return -1;
for(node_size = self->size; node_size != size; node_size /= 2 ) {
if (self->longest[LEFT_LEAF(index)] >= size)
index = LEFT_LEAF(index);
else
index = RIGHT_LEAF(index);
}
self->longest[index] = 0;
offset = (index + 1) * node_size - self->size;
while (index) {
index = PARENT(index);
self->longest[index] =
MAX(self->longest[LEFT_LEAF(index)], self->longest[RIGHT_LEAF(index)]);
}
return offset;
}
void buddy2_free(struct buddy2* self, int offset) {
unsigned node_size, index = 0;
unsigned left_longest, right_longest;
assert(self && offset >= 0 && offset < self->size);
node_size = 1;
index = offset + self->size - 1;
for (; self->longest[index] ; index = PARENT(index)) {
node_size *= 2;
if (index == 0)
return;
}
self->longest[index] = node_size;
while (index) {
index = PARENT(index);
node_size *= 2;
left_longest = self->longest[LEFT_LEAF(index)];
right_longest = self->longest[RIGHT_LEAF(index)];
if (left_longest + right_longest == node_size)
self->longest[index] = node_size;
else
self->longest[index] = MAX(left_longest, right_longest);
}
}
int buddy2_size(struct buddy2* self, int offset) {
unsigned node_size, index = 0;
assert(self && offset >= 0 && offset < self->size);
node_size = 1;
for (index = offset + self->size - 1; self->longest[index] ; index = PARENT(index))
node_size *= 2;
return node_size;
}
void buddy2_dump(struct buddy2* self) {
char canvas[65];
int i,j;
unsigned node_size, offset;
if (self == NULL) {
printf("buddy2_dump: (struct buddy2*)self == NULL");
return;
}
if (self->size > 64) {
printf("buddy2_dump: (struct buddy2*)self is too big to dump");
return;
}
memset(canvas,'_', sizeof(canvas));
node_size = self->size * 2;
for (i = 0; i < 2 * self->size - 1; ++i) {
if ( IS_POWER_OF_2(i+1) )
node_size /= 2;
if ( self->longest[i] == 0 ) {
if (i >= self->size - 1) {
canvas[i - self->size + 1] = '*';
}
else if (self->longest[LEFT_LEAF(i)] && self->longest[RIGHT_LEAF(i)]) {
offset = (i+1) * node_size - self->size;
for (j = offset; j < offset + node_size; ++j)
canvas[j] = '*';
}
}
}
canvas[self->size] = '\0';
puts(canvas);
}
int main() {
char cmd[80];
int arg;
struct buddy2* buddy = buddy2_new(32);
buddy2_dump(buddy);
for (;;) {
scanf("%s %d", cmd, &arg);
if (strcmp(cmd, "alloc") == 0) {
printf("allocated@%d\n", buddy2_alloc(buddy, arg));
buddy2_dump(buddy);
} else if (strcmp(cmd, "free") == 0) {
buddy2_free(buddy, arg);
buddy2_dump(buddy);
} else if (strcmp(cmd, "size") == 0) {
printf("size: %d\n", buddy2_size(buddy, arg));
buddy2_dump(buddy);
} else
buddy2_dump(buddy);
}
}