void print_sequential_allocated(void* node, void** next_hdr) { int flag = FALSE; void* page_ptr = BASEADDR(node); while (BASEADDR(node) == page_ptr) { void* checker = CONTROL_BLOCK_FIRST_NODE(root_page->ptr); while (checker != NULL) { if (checker == node) { flag = TRUE; break; } checker = NEXT(checker); } if (flag == TRUE) { break; } int page_id; if ((void*) BASEADDR(node) == root_page->ptr) { page_id = root_page->id; } else { page_id = (*((kma_page_t**) BASEADDR(node)))->id; } printf("%2d ALLOCATED | hdr = %11p; size %4x; next_hdr = %11p\n", page_id, node, SIZE(node), node + ALLOC_HEADER_SIZE + SIZE(node)); *next_hdr = node + ALLOC_HEADER_SIZE + SIZE(node); node += ALLOC_HEADER_SIZE + SIZE(node); } }
// need to insert into list on same page as buffer void insertIntoFreeList(void* buffer, int bufferSize) { int freeBufferIndex = getFreeBufferIndex(bufferSize); void** freeBufferList = getFreeBufferPointer(freeBufferIndex); bufferData_t* currentBuffer = (bufferData_t*)*freeBufferList; bufferData_t* pastBuffer = NULL; // handle case where list is empty if (currentBuffer == NULL) { *freeBufferList = buffer; currentBuffer = (bufferData_t*)*freeBufferList; assert(currentBuffer != NULL); currentBuffer->nextFreeBuffer = NULL; currentBuffer->bufferSize = bufferSize; return; } // now handle case where there are elements in free list size_t inputBufferPage = getPageNumber(BASEADDR(buffer)); size_t currentPageNum = getPageNumber(BASEADDR(currentBuffer)); assert(currentBuffer != NULL); while (currentBuffer->nextFreeBuffer != NULL && currentPageNum < inputBufferPage) { pastBuffer = currentBuffer; currentBuffer = currentBuffer->nextFreeBuffer; assert(currentBuffer != NULL); currentPageNum = getPageNumber(BASEADDR(currentBuffer)); } if (currentBuffer->nextFreeBuffer == NULL) { // reached end of list, insert at end currentBuffer->nextFreeBuffer = buffer; currentBuffer = (bufferData_t*)buffer; currentBuffer->nextFreeBuffer = NULL; currentBuffer->bufferSize = bufferSize; } else { // in middle of list but past where we want to input buffer if (pastBuffer == NULL) { // we want to insert buffer at start of free list *freeBufferList = buffer; ((bufferData_t*)buffer)->nextFreeBuffer = (void*)currentBuffer; ((bufferData_t*)buffer)->bufferSize = bufferSize; } else { // we want to insert list between pastBuffer and currentBuffer assert(pastBuffer != NULL); pastBuffer->nextFreeBuffer = buffer; ((bufferData_t*)buffer)->nextFreeBuffer = (void*)currentBuffer; ((bufferData_t*)buffer)->bufferSize = bufferSize; } } }
void dump() { if (root_page == NULL) { printf(" EMPTY |\n"); return; } void* prev = NULL; void* node = CONTROL_BLOCK_FIRST_NODE(root_page->ptr); void* next_hdr = NULL; kma_page_t* page = NULL; kma_page_t* prev_page = NULL; while (node != NULL) { prev_page = page; int page_id; if ((void*) BASEADDR(node) == root_page->ptr) { page = root_page; page_id = root_page->id; } else { page = *((kma_page_t**) BASEADDR(node)); page_id = (*((kma_page_t**) BASEADDR(node)))->id; } if (prev == NULL) { if (node > root_page->ptr + CONTROL_BLOCK_SIZE) { print_sequential_allocated(root_page->ptr + CONTROL_BLOCK_SIZE, &next_hdr); } } else if (prev_page != page) { print_sequential_allocated(page->ptr + CONTROL_BLOCK_SIZE, &next_hdr); } else { kma_size_t diff = node - (prev + ALLOC_HEADER_SIZE + SIZE(prev)); if (diff > 0) { print_sequential_allocated(prev + ALLOC_HEADER_SIZE + SIZE(prev), &next_hdr); } } // if (prev_page == page && next_hdr != NULL) { // assert(next_hdr == node); // } printf("%2d FREED | hdr = %11p; size %4x; next_hdr = %11p; PREV = %11p; NEXT = %11p\n", page_id, node, SIZE(node), node + ALLOC_HEADER_SIZE + SIZE(node), PREV(node), NEXT(node)); next_hdr = node + ALLOC_HEADER_SIZE + SIZE(node); prev = node; node = NEXT(node); } }
// call after unset bitmap for this buffer void coalesceFreeMemory(void** pointer, int* bufferSize) { // calculate buddy location void* startOfPage = BASEADDR(*pointer); // check if buddy is free void* buddyPtr = getBuddyPointer(startOfPage, *pointer, *bufferSize); if (!checkIfBitmapSet(buddyPtr,*bufferSize)) { // can coalesce! // need to remove it from freeList // handle inserting back in in kma_free removeFromFreeList(buddyPtr,*bufferSize); *bufferSize = *bufferSize*2; if (buddyPtr < *pointer) { *pointer = buddyPtr; } if (*bufferSize != PAGESIZE) { coalesceFreeMemory(pointer, bufferSize); } } // base case is either buddy isn't free of full page free }
void kma_free(void* ptr, kma_size_t size) { size = roundUp(size); kma_page_t *page = *((kma_page_t **) BASEADDR(ptr)); if (diff(size) == 8) { //if 8196, free the page free_page(page); PAGE_COUNT--; } else { page->size += size; if (page->size == PAGESIZE - sizeof(kma_page_t*)) { derefPage(page->ptr, size); //if page is made of free buffers, derefence the buffer in freelist free_page(page); PAGE_COUNT--; } else { //not all free, give the buffer back to freelist insertAtHead(ptr, size); } } //free everything if(PAGE_COUNT == 1) { free_page(FREEPAGE); INIT = FALSE; PAGE_COUNT = 0; FREE_LIST_HEAD = NULL; } }
/* Computes the location of a blocks buddy. This function relies on if the block is an even or odd multiple of its size away from the beginning, which indicates if the buddy will be on the left or the right. */ allocheaderT* get_buddy(allocheaderT* alloc) { int diff = (long int) alloc - (long int) BASEADDR(alloc); if ((diff / (alloc->size)) & 1) // odd return (allocheaderT*) ((long int) alloc - (long int) alloc->size); else return (allocheaderT*) ((long int) alloc + (long int) alloc->size); }
void* getBuffer(size_t size, void** entry) { void* cur = *entry; void* next = *(void **)cur; *(void **)cur = entry; *entry = next; kma_page_t * page = *((kma_page_t **) BASEADDR(cur)); page->size -= size; return cur + sizeof(void *); }
void derefPage(void* page, size_t size) { void** pre = FREE_LIST_HEAD + diff(size); void* cur = *pre; while (cur != NULL) { if (BASEADDR(cur) == page) { *pre = *(void **)cur; //remove from freelist } else { pre = cur; //move on } cur = *(void **)cur; } }
/** * Free memory **/ void kma_free(void* ptr, kma_size_t size) { addEntry(ptr, size); pageHeader* baseAdd = BASEADDR(ptr); baseAdd->blockCount--; pageHeader* firstPage = (pageHeader*)(mainPage->ptr); int totalPages = firstPage->pageCount; int count = 1; pageHeader* lastPage; for (; count; totalPages--) { lastPage = ((pageHeader*)((long int)firstPage + totalPages * PAGESIZE)); count = 0; if (lastPage->blockCount == 0) { count = 1; block* tmp; for (tmp = firstPage->head; tmp != NULL; tmp = tmp->next) { if (BASEADDR(tmp) == lastPage) { deleteEntry(tmp); } } count = 1; if (lastPage == firstPage) { count = 0; mainPage = NULL; } free_page(lastPage->self); if (mainPage) { firstPage->pageCount--; } } } }
void alterBitMap(void* ptr, int sizeInBytes, bool setBits) { BYTE byteValue; if (setBits) { byteValue = 255; } else { byteValue = 0; } // get base addr of page void* startOfPage = BASEADDR(ptr); size_t pageNumber = getPageNumber(startOfPage); assert(pageNumber >= 0); int numBitsInBitmap = sizeInBytes/MIN_BUFFER_SIZE; size_t bitmapIndex = getByteIndex(startOfPage, ptr); size_t bitmapOffset = getByteOffset(startOfPage, ptr); BYTE* bitmapLoc = &startOfManagedMemory->pages[pageNumber].bitmap[bitmapIndex]; int i; if (bitmapOffset == 0) { // if offset is 0 then possible that we can set bytes at a time for (i=0; i < numBitsInBitmap/8; i++) { *bitmapLoc = byteValue; bitmapLoc = bitmapLoc + 1; } } // if there is a offset within a byte, then we know numBitsInBitmap < 8 because buffer has offset multiples of size assert(bitmapOffset < 8); for (i=bitmapOffset; i < numBitsInBitmap % 8; i++) { if (setBits) { *bitmapLoc |= 1 << (7-i); printf("bitmap altered %hhu\n", *bitmapLoc); } else { *bitmapLoc &= ~(1 << (7-i)); } } }
void kma_free(void* ptr, kma_size_t size) { void* internalPtr = (void*)(((BYTE*) ptr) - sizeof(bufferData_t)); int bufferSize = getAmountOfMemoryToRequest(size); size_t pageNum = getPageNumber(BASEADDR(internalPtr)); // unset bitmap unsetBitmap(internalPtr, bufferSize); // coalesce free buddies coalesceFreeMemory(&internalPtr, &bufferSize); if (bufferSize == PAGESIZE) { // can free page free_page(startOfManagedMemory->pages[pageNum].pageData); // right way would be to shift all pages after this over int pageIndex = pageNum + 1; while (startOfManagedMemory->pages[pageIndex].pageData != NULL) { memcpy((void*)&startOfManagedMemory->pages[pageIndex-1], (void*)&startOfManagedMemory->pages[pageIndex], sizeof(pageControlStruct_t*)); pageIndex = pageIndex + 1; } // so that the last page in list isn't duplicated startOfManagedMemory->pages[pageIndex-1].pageData = NULL; int j; for (j=0; j < BITMAP_SIZE; j++) { startOfManagedMemory->pages[pageIndex-1].bitmap[j] = 0; } } if (onlyControlStructureLeft()) { // everything gone except control structure // free page free_page(startOfManagedMemory->pages[0].pageData); startOfManagedMemory = NULL; return; } if (bufferSize != PAGESIZE) { // insert into free list insertIntoFreeList(internalPtr, bufferSize); } }
void dump() { kma_size_t class_size = PAGESIZE; int i = 0; while (class_size > ALLOC_HEADER_SIZE) { printf("CLASS SIZE %#x\n", class_size); void* node = FIRST_FREE_NODE(i); while (node != NULL) { printf("%10s %p | BASEADDR(hdr) = %p; SIZE(hdr) = %#6x; NEXT(hdr) = %p;\n", IS_ALLOCATED(node) ? "ALLOCATED" : "FREE", node, BASEADDR(node), SIZE(node), NEXT(node)); node = NEXT(node); } i++; class_size >>= 1; } }
bool checkIfBitmapSet(void* ptr, int sizeInBytes) { void* startOfPage = BASEADDR(ptr); size_t pageNumber = getPageNumber(startOfPage); assert(pageNumber >= 0); int numBitsInBitmap = sizeInBytes/MIN_BUFFER_SIZE; size_t bitmapIndex = getByteIndex(startOfPage, ptr); size_t bitmapOffset = getByteOffset(startOfPage, ptr); BYTE* bitmapLoc = &startOfManagedMemory->pages[pageNumber].bitmap[bitmapIndex]; int i; if (bitmapOffset == 0) { // if offset is 0 then possible that we can set bytes at a time for (i=0; i < numBitsInBitmap/8; i++) { if (*bitmapLoc != 0) { return TRUE; } bitmapLoc = bitmapLoc + 1; } } // if there is a offset within a byte, then we know numBitsInBitmap < 8 because buffer has offset multiples of size assert(bitmapOffset < 8); for (i=bitmapOffset; i < numBitsInBitmap % 8; i++) { if ((*bitmapLoc & 1 << (7-i)) != 0) { return TRUE; } } // bitmap all 0s, can coalesce! return FALSE; }
/** * allocate memory **/ void* kma_malloc(kma_size_t size) { // if the requested size is greater than a page, ignore it if ((size + sizeof(void*)) > PAGESIZE) { return NULL; } // if there are no allocated page, then initate the page if (!mainPage) { mainPage = get_page(); initPage(mainPage); } // find suitable space void* firstFit1 = firstFit(size); pageHeader* base = BASEADDR(firstFit1); // increase block count base->blockCount++; // return block address return firstFit1; }
void coalesce(void* hdr) { int again = FALSE; kma_size_t size = SIZE(hdr); void* prev = PREV(hdr); void* next = NEXT(hdr); /* If the previous free block is adjacent and in the same page, coalesce */ if (prev != NULL && BASEADDR(prev) == BASEADDR(hdr) && prev + ALLOC_HEADER_SIZE + SIZE(prev) == hdr) { size += SIZE(prev) + ALLOC_HEADER_SIZE; NEXT(prev) = next; if (next != NULL) { PREV(next) = prev; } SIZE(prev) = size; hdr = prev; again = TRUE; } /* If the next free block is adjacent and in the same page, coalesce */ if (next != NULL && BASEADDR(hdr) == BASEADDR(next) && hdr + ALLOC_HEADER_SIZE + SIZE(hdr) == next) { size += SIZE(next) + ALLOC_HEADER_SIZE; NEXT(hdr) = NEXT(next); if (NEXT(next) != NULL) { PREV(NEXT(next)) = hdr; } SIZE(hdr) = size; again = TRUE; } /* If coalescing has ocurred, try to do it again */ if (again == TRUE) { coalesce(hdr); } else { /* If not, attempt to free page */ kma_size_t page_size; if (BASEADDR(hdr) == root_page->ptr) { page_size = root_page->size; } else { page_size = (*((kma_page_t**) BASEADDR(hdr)))->size; } /* If the block takes up the whole page, it is ready to be freed */ if (SIZE(hdr) == page_size - CONTROL_BLOCK_SIZE - ALLOC_HEADER_SIZE) { /* Remove the block from the linked list */ if (PREV(hdr) != NULL) { NEXT(PREV(hdr)) = NEXT(hdr); } else { CONTROL_BLOCK_FIRST_NODE(root_page->ptr) = NEXT(hdr); } if (NEXT(hdr) != NULL) { PREV(NEXT(hdr)) = PREV(hdr); } /* If the page is the root page, make the page of the next free block the new root page, otherwise simply free the page */ if (BASEADDR(hdr) == root_page->ptr) { kma_page_t* root_page_temp = root_page; if (NEXT(hdr) != NULL) { root_page = *((kma_page_t**) BASEADDR(NEXT(hdr))); CONTROL_BLOCK_FIRST_NODE(root_page->ptr) = NEXT(hdr); } else { root_page = NULL; } free_page(root_page_temp); } else { free_page(*((kma_page_t**) BASEADDR(hdr))); } } } }
void kma_free(void* ptr, kma_size_t size) { pageheaderT* page = (pageheaderT*) (BASEADDR(ptr)+sizeof(allocheaderT)); freelistL* buffer = get_required_buffer(size, page); allocheaderT* alloc = buffer->first_block; // can't do any of this entire page is allocated to one chunk. if (round_up(size) != PAGESIZE) { // creating new free buffer allocheaderT* new_alloc = (allocheaderT*) (ptr); new_alloc->start = ALLOC_START(new_alloc); new_alloc->size = round_up(size); new_alloc->next = NULL; // insert buffer as first item if empty if (alloc == NULL) buffer->first_block = new_alloc; // insert buffer as first item when not empty else if ((long int) alloc > (long int) new_alloc) { new_alloc->next = alloc; buffer->first_block = new_alloc; } // find the appropriate location and insert the bufer else { while (alloc->next != NULL) { if ((long int) alloc->next > (long int) new_alloc) { new_alloc->next = alloc->next; alloc->next = new_alloc; break; } else alloc = alloc->next; } coalesce(page); } } // if no more elements have been allocated to this page, free it. page->used -= 1; if (page->used == 0) { // case 1: freed first page, but there are still some pages existing. if (page->page == first_page && page->next != NULL) { kma_page_t* temp = page->next->page; free_page(first_page); first_page = temp; } // case 2: all pages are being freed. else if (page->page == first_page) { free_page(first_page); first_page = NULL; } // case 3: freeing any other page else { pageheaderT* temp = PAGE_HEADER(first_page); pageheaderT* prev = NULL; while (temp != page) { prev = temp; temp = temp->next; } prev->next = page->next; free_page(page->page); } } }