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 186 187 188 189 190 191 192 193 194 195 196 197 198
| #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h>
#define CHECK(x, code, message, ...) if(!(x)) {fprintf(stderr, "%s:%d, error: %s\t----\t", __FILE__, __LINE__, strerror(errno)); fprintf(stderr, (const char*)message, ##__VA_ARGS__); exit(code); } #define ERR(code, format, ...) fprintf(stderr, (const char*)format, ##__VA_ARGS__); exit(code)
#define UNUSED 0 #define USED 1
#define EXIT_SBRK_FAIL 1 #define UNKNOWN_FAIL 2 #define UNKNOWN_MEM_ERROR 3 #define FREE_TWICE 4
#define MAXALLOC 100000
void *freeMem = NULL;
unsigned long getBlockSize(void *mem) { return *((unsigned long *)mem - 1); }
void setBlockSize(void *mem, size_t size) { *((unsigned long *)mem - 1) = size; }
void *getNextFreeBlock(void *__free) { return (unsigned long*) *((unsigned long *)__free + 1); }
void setNextFreeBlock(void *__free, void *__ptr) { *((unsigned long *)__free + 1) = (unsigned long)__ptr; }
void *getPrevFreeBlock(void *__free) { return (unsigned long*) *(unsigned long *)__free; }
void setPrevFreeBlock(void *__free, void *__ptr) { *(unsigned long *)__free = (unsigned long)__ptr; }
char getUsed(void *__ptr) { return *((char *)__ptr - 1 - sizeof(void *)); }
void setUsed(void *__ptr, char used) { *((char *)__ptr - 1 - sizeof(void *)) = used; }
void memInit(char used, void *__ptr, void *prev, void *next, size_t size) { setUsed(__ptr, used); setBlockSize(__ptr, size); setPrevFreeBlock(__ptr, prev); setNextFreeBlock(__ptr, next); }
void *firstFit(size_t size) { void *move = freeMem; void *next = getNextFreeBlock(freeMem); while(next != NULL) { if(getBlockSize(next) >= size) { break; } move = next; next = getNextFreeBlock(next); } return move; }
void *__malloc(size_t size) { if(freeMem == NULL) { freeMem = sbrk(sizeof(void *) * 3 + 1); CHECK(freeMem != (void*)-1, EXIT_SBRK_FAIL, "sbrk fail\n"); freeMem += sizeof(void *) + 1; memInit(UNUSED, freeMem, NULL, NULL, sizeof(void *) * 2); } void *__free = firstFit(size); void *newMem = NULL; CHECK(__free != NULL, UNKNOWN_FAIL, "unknown error\n"); if(getNextFreeBlock(__free) == NULL) { size = size > 2 * sizeof(void *) ? size : 2 * sizeof(void *); newMem = sbrk(1 + sizeof(void *) + size); CHECK(newMem != (void*)-1, EXIT_SBRK_FAIL, "sbrk fail\n"); newMem += 1 + sizeof(void *); memInit(USED, newMem, NULL, NULL, size); } else { newMem = getNextFreeBlock(__free); setUsed(newMem, USED); setNextFreeBlock(__free, getNextFreeBlock(newMem)); } return newMem; }
void __free(void * __ptr) { CHECK(freeMem != NULL, UNKNOWN_MEM_ERROR,"memory: %p is not allocated by __mallo\n", __ptr); CHECK(getUsed(__ptr) == USED, FREE_TWICE, "trying to free memory %p twice\n", __ptr); setUsed(__ptr, UNUSED); void *move = freeMem; void *next = getNextFreeBlock(freeMem); void *front = (char *)__ptr - 1 - sizeof(void *), *back = (char *)__ptr + getBlockSize(__ptr); while(next != NULL) { if((char *)next - 1 - sizeof(void *) >= (char *)back) { break; } move = next; next = getNextFreeBlock(next); } if(front == (char *)move + getBlockSize(move)) { setBlockSize(move, (char *)back - (char *)move); __ptr = move; } else { setNextFreeBlock(__ptr, getNextFreeBlock(move)); setNextFreeBlock(move, __ptr); setPrevFreeBlock(__ptr, move); } if(next == NULL) return; if(back == (char *)next - 1 - sizeof(void *)) { setBlockSize(__ptr, (char *)next + getBlockSize(next) - (char *)__ptr); } else { setPrevFreeBlock(next, __ptr); } return; }
void __printMemblock(void* ptr) { printf("------------Memory Block %p---------------\n", ptr); printf("front = %p, back = %p\n", (char *)ptr - 1 - sizeof(void *), (char *)ptr + getBlockSize(ptr)); int used = *((char *)ptr - 1 - sizeof(unsigned long)); printf("used\t\t=\t%d\n", used); printf("blocksize\t=\t%lu\n", *((unsigned long *)ptr - 1)); if(!used) { printf("last free block\t=\t%p\n", (unsigned long*) *(unsigned long *)ptr); printf("next free block\t=\t%p\n", (unsigned long*) *((unsigned long *)ptr + 1)); } printf("Current brk = %p\n", sbrk(0)); }
void __showFreeBlocks() { printf("show free blocks\n"); void *move = freeMem; while(move) { __printMemblock(move); move = getNextFreeBlock(move); } }
int main(int argc, char *argv[]) { if(argc < 3) { ERR(1, "Usage: %s numalloc blocksize [freestep] [freemin] [freemax]\n", argv[0]); } int numalloc = atoi(argv[1]); size_t blocksize = atoi(argv[2]); int freestep = argc > 3 ? atoi(argv[3]) : 1; int freemin = argc > 4 ? atoi(argv[4]) : 1; int freemax = argc > 5 ? atoi(argv[5]) : numalloc;
void *ptr[MAXALLOC];
if(numalloc > MAXALLOC) { ERR(2, "constraint: numalloc <= %d\n", MAXALLOC); }
printf("sizeof(void *) = %lu\n", sizeof(void *)); printf("Start to allocate mem, Current program break: %p\n", sbrk(0));
for(int i = 0; i < numalloc; i++) { ptr[i] = __malloc(blocksize); if(ptr[i] == NULL) { ERR(3, "fail to __malloc loc: %d\n", i); } printf("Current program break: %p\n", sbrk(0)); __printMemblock(ptr[i]); }
for(int i = 0; i < numalloc; i++) { __printMemblock(ptr[i]); } __showFreeBlocks(); printf("Allocation finished, Current program break: %p\n", sbrk(0));
for(int i = freemin-1; i < freemax; i += freestep) { __free(ptr[i]); printf("Current program break: %p\n", sbrk(0)); __printMemblock(ptr[i]); } printf("Mem __free finished, Current program break: %p\n", sbrk(0));
for(int i = freemin-1; i < freemax; i += freestep) { __printMemblock(ptr[i]); } __showFreeBlocks(); return 0; }
|