main() { LIST L, p, p2; char ans, element; MAKENULL(&L); do { clrscr(); printf("\n MENU\n"); printf("[1] Insert\n"); printf("[2] Delete\n"); printf("[3] Display\n"); printf("[4] Search\n"); printf("[5] Quit\n\n"); printf("Enter chosen number: "); ans = toupper(getche()); switch (ans) { case '1': /* case 1 has an approximated running time of 3n + 12 */ printf("\n\nEnter an element to insert: "); element = getche(); p = INS_POS(element, L); INSERT(element, p); break; case '2' : /* case 2 has an approximated running time of 8n + 10 */ printf("\n\nEnter element to delete: "); element = getche(); p = LOCATE(element,L); DELETE(element, p); break; case '3' : /* case 3 has an approximated running time of 3n + 4 */ printf("\n\n"); PRINTLIST(L); break; case '4' : /* case 4 has an approximated running time of 4n + 14 */ printf("\n\nEnter element to search: "); element = getch(); p = LOCATE(element,L); SEARCH(element, p); break; case '5' : break; } } while (ans != '5'); DELETEALL(p); /* DELETEALL has an approximated runnning time of 4n + 1 */ }
void* fakemem_malloc(size_t size) { // if we are not initialized, we need to allocate the initial data structures if (FAKEMEM_ALLOC_STATE == NULL && fakemem_init() == NULL) { errno = ENOMEM; return NULL; } if (size == 0) { errno = EINVAL; return NULL; } PRINTD("\nmalloc called. CAS = %p, size = %lu\n", FAKEMEM_ALLOC_STATE, size); // set the size to be of the granularity size = ((size-1)/FAKEMEM_ALLOC_BLOCK+1)*FAKEMEM_ALLOC_BLOCK; PRINTD("rounded size is %lu\n", size); fakemem_block* walker = FAKEMEM_ALLOC_STATE->free_blocks; fakemem_block* parent = walker; while (walker != NULL) { if (walker->size >= size) break; if (parent != walker) parent = walker; walker = walker->next; } if (walker == NULL) { errno = ENOMEM; return NULL; } PRINTD("found walker %p, offset %lu, size %lu\n", walker, walker->offset, walker->size); // this is what we put in taken fakemem_block* new_block = NULL; // first, update the free list // new_block will contain the block which needs to go to the taken list if (walker->size == size) { // we just move the block to the taken list new_block = walker; if (parent != walker) parent->next = walker->next; else FAKEMEM_ALLOC_STATE->free_blocks = walker->next; PRINTD("size matches chunk. parent = %p, new_block = %p\n", parent, new_block); } else { // we need to create and fill in the new block new_block = (fakemem_block*)malloc(sizeof(fakemem_block)); if (new_block == NULL) { errno = ENOMEM; return NULL; } new_block->offset = walker->offset; new_block->size = size; walker->offset += size; walker->size -= size; PRINTD("new block created. walker = %p, new_block = %p\n", walker, new_block); } PRINTD("parent %p, next %p\n", parent, parent->next); // then, proceed to adding a new block to the taken list walker = FAKEMEM_ALLOC_STATE->taken; parent = walker; while (walker != NULL) { PRINTD("new_block->offset = %lu, walker->offset = %lu\n", new_block->offset, walker->offset); if (new_block->offset > walker->offset) break; if (parent != walker) parent = walker; walker = walker->next; } new_block->next = walker; PRINTD("taken list: new_block->next = %p\n", new_block->next); PRINTD("taken list: parent = %p\n", parent); if (parent == NULL || parent == FAKEMEM_ALLOC_STATE->taken) FAKEMEM_ALLOC_STATE->taken = new_block; else parent->next = new_block; PRINTD("taken list: parent = %p, parent->next = %p, taken = %p\n", parent, parent?parent->next:parent, FAKEMEM_ALLOC_STATE->taken); PRINTLIST("free", FAKEMEM_ALLOC_STATE->free_blocks); PRINTLIST("taken", FAKEMEM_ALLOC_STATE->taken); PRINTD("malloc ends\n\n"); // finally, return the address we "allocated" return ((void*)((uintptr_t)FAKEMEM_ALLOC_STATE->base_vaddr + new_block->offset)); }
void fakemem_free(void* ptr) { PRINTD("\nfree called. ptr = %p, CAS = %p, taken = %p\n", ptr, FAKEMEM_ALLOC_STATE, FAKEMEM_ALLOC_STATE->taken); if (FAKEMEM_ALLOC_STATE == NULL || FAKEMEM_ALLOC_STATE->taken == NULL) return; fakemem_block* walker = FAKEMEM_ALLOC_STATE->taken; fakemem_block* parent = walker; size_t off = (size_t)((uintptr_t)ptr - (uintptr_t)FAKEMEM_ALLOC_STATE->base_vaddr); PRINTD("Offset = %ld\n", off); while (walker != NULL) { PRINTMB("walker", walker); /*PRINTD("walker = %p, walker->next = %p, walker->offset = %lu\n", walker, walker->next, walker->offset);*/ if (walker->offset == off) break; if (parent != walker) parent = walker; walker = walker->next; } PRINTD("found walker %p\n", walker); // this should be an error in a safe language... if (walker == NULL) return; PRINTD("walker is %p, off is %lu\n", walker, walker->offset); // remove the node with the right offset if (walker == parent && walker->next == NULL) { // this is the case with only one... FAKEMEM_ALLOC_STATE->taken = NULL; } else { parent->next = walker->next; } walker->next = NULL; // add to the free list fakemem_block* new_block = walker; walker = FAKEMEM_ALLOC_STATE->free_blocks; parent = walker; PRINTLIST("taken", FAKEMEM_ALLOC_STATE->taken); // iterate over all free blocks, find the first one which is after out block // in: new_block, containing data to enlist // out: parent holds the place where to put the data while (walker != NULL) { PRINTMB("free-walk", walker); if (walker->offset > new_block->offset) break; if (parent != walker) parent = walker; walker = walker->next; } if (walker == NULL) return; PRINTD("walker = %p, parent = %p; parent->size = %lu, offset = %lu\n", walker, parent, parent->size, parent->offset); PRINTMB("new_block", new_block); PRINTLIST("free_blocks", FAKEMEM_ALLOC_STATE->free_blocks); if (parent->offset + parent->size == new_block->offset) { PRINTD("Will merge two nodes, parent in front\n"); // we will assimilate the block; parent->size += new_block->size; free(new_block); } else if (new_block->offset + new_block->size == parent->offset) { PRINTD("Will merge two nodes, parent in back\n"); parent->size += new_block->size; parent->offset -= new_block->size; free(new_block); } else { new_block->next = walker; if (parent == FAKEMEM_ALLOC_STATE->free_blocks) { FAKEMEM_ALLOC_STATE->free_blocks = new_block; } else { parent->next = new_block; } } // now, do the compacting... walker = parent = FAKEMEM_ALLOC_STATE->free_blocks; PRINTD("will try to compact...\n"); while (walker != NULL) { PRINTMB("walker", walker); /*PRINTD("walker = %p, walker->next = %p, walker->offset = %lu, walker->size = %lu\n", walker, walker->next, walker->offset, walker->size);*/ if (walker && walker->next) { if (walker->offset + walker->size == walker->next->offset) { // compact... PRINTD("will compact %p\n", walker->next); walker->size += walker->next->size; fakemem_block* temp = walker->next; walker->next = walker->next->next; PRINTD("removing %p\n", temp); free(temp); } } if (parent != walker) parent = walker; walker = walker->next; } #ifdef DEBUG fakemem_block* taken = FAKEMEM_ALLOC_STATE->taken; PRINTD("taken = %p, taken->next = %p\n", taken, taken?taken->next:taken); PRINTLIST("free", FAKEMEM_ALLOC_STATE->free_blocks); PRINTLIST("taken", FAKEMEM_ALLOC_STATE->taken); PRINTD("free ends\n\n"); #endif }