void* realloc(void *p, uint64_t size) { void *ptr; struct boundary_tag *tag; int real_size; if ( size == 0 ) { free( p ); return NULL; } if ( p == NULL ) return malloc( size ); liballoc_lock(); // lockit tag = (struct boundary_tag*)((unsigned int)p - sizeof( struct boundary_tag )); real_size = tag->size; liballoc_unlock(); if ( real_size > size ) real_size = size; ptr = malloc( size ); liballoc_memcpy( ptr, p, real_size ); free( p ); return ptr; }
void* realloc(void *p, size_t size) { void *ptr; struct liballoc_minor *min; int real_size; if ( size == 0 ) { free( p ); return NULL; } if ( p == NULL ) return malloc( size ); if ( liballoc_lock != NULL ) liballoc_lock(); // lockit min = (struct liballoc_minor*)((unsigned int)p - sizeof( struct liballoc_minor )); real_size = min->size; if ( liballoc_unlock != NULL ) liballoc_unlock(); if ( real_size > size ) real_size = size; ptr = malloc( size ); liballoc_memcpy( ptr, p, real_size ); free( p ); return ptr; }
void free(void *ptr) { struct liballoc_minor *min; struct liballoc_major *maj; if ( ptr == NULL ) return; if ( liballoc_lock != NULL ) liballoc_lock(); // lockit min = (struct liballoc_minor*)((unsigned int)ptr - sizeof( struct liballoc_minor )); if ( min->magic != LIBALLOC_MAGIC ) { // being lied to... if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock return; } maj = min->block; maj->usage -= (min->size + sizeof( struct liballoc_minor )); min->magic = 0; // No mojo. if ( min->next != NULL ) min->next->prev = min->prev; if ( min->prev != NULL ) min->prev->next = min->next; if ( min->prev == NULL ) maj->first = min->next; // Might empty the block. This was the first // minor. // We need to clean up after the majors now.... if ( maj->first == NULL ) // Block completely unused. { if ( l_memRoot == maj ) l_memRoot = maj->next; if ( maj->prev != NULL ) maj->prev->next = maj->next; if ( maj->next != NULL ) maj->next->prev = maj->prev; liballoc_free( maj, maj->pages * l_pageSize ); } if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock }
void* PREFIX(realloc)(void *p, size_t size) { void *ptr; struct liballoc_minor *min; unsigned int real_size; // Honour the case of size == 0 => free old and return NULL if ( size == 0 ) { PREFIX(free)( p ); return NULL; } // In the case of a NULL pointer, return a simple malloc. if ( p == NULL ) return PREFIX(malloc)( size ); // Unalign the pointer if required. ptr = p; UNALIGN(ptr); liballoc_lock(); // lockit min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof( struct liballoc_minor )); // Ensure it is a valid structure. if ( min->magic != LIBALLOC_MAGIC ) { l_errorCount += 1; // Check for overrun errors. For all bytes of LIBALLOC_MAGIC if ( ((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)) ) { l_possibleOverruns += 1; #if defined DEBUG || defined INFO serial_printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", min->magic, LIBALLOC_MAGIC ); FLUSH(); #endif } if ( min->magic == LIBALLOC_DEAD ) { #if defined DEBUG || defined INFO serial_printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", ptr, __builtin_return_address(0) ); FLUSH(); #endif } else { #if defined DEBUG || defined INFO serial_printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", ptr, __builtin_return_address(0) ); FLUSH(); #endif } // being lied to... liballoc_unlock(); // release the lock return NULL; } // Definitely a memory block. real_size = min->req_size; if ( real_size >= size ) { min->req_size = size; liballoc_unlock(); return p; } liballoc_unlock(); // If we got here then we're reallocating to a block bigger than us. ptr = PREFIX(malloc)( size ); // We need to allocate new memory liballoc_memcpy( ptr, p, real_size ); PREFIX(free)( p ); return ptr; }
void PREFIX(free)(void *ptr) { struct liballoc_minor *min; struct liballoc_major *maj; if ( ptr == NULL ) { l_warningCount += 1; #if defined DEBUG || defined INFO serial_printf( "liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n", __builtin_return_address(0) ); FLUSH(); #endif return; } UNALIGN( ptr ); liballoc_lock(); // lockit min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof( struct liballoc_minor )); if ( min->magic != LIBALLOC_MAGIC ) { l_errorCount += 1; // Check for overrun errors. For all bytes of LIBALLOC_MAGIC if ( ((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)) ) { l_possibleOverruns += 1; #if defined DEBUG || defined INFO serial_printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", min->magic, LIBALLOC_MAGIC ); FLUSH(); #endif } if ( min->magic == LIBALLOC_DEAD ) { #if defined DEBUG || defined INFO serial_printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", ptr, __builtin_return_address(0) ); FLUSH(); #endif } else { #if defined DEBUG || defined INFO serial_printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", ptr, __builtin_return_address(0) ); FLUSH(); #endif } // being lied to... liballoc_unlock(); // release the lock return; } #ifdef DEBUG serial_printf( "liballoc: %x PREFIX(free)( %x ): ", __builtin_return_address( 0 ), ptr ); FLUSH(); #endif maj = min->block; l_inuse -= min->size; maj->usage -= (min->size + sizeof( struct liballoc_minor )); min->magic = LIBALLOC_DEAD; // No mojo. if ( min->next != NULL ) min->next->prev = min->prev; if ( min->prev != NULL ) min->prev->next = min->next; if ( min->prev == NULL ) maj->first = min->next; // Might empty the block. This was the first // minor. // We need to clean up after the majors now.... if ( maj->first == NULL ) // Block completely unused. { if ( l_memRoot == maj ) l_memRoot = maj->next; if ( l_bestBet == maj ) l_bestBet = NULL; if ( maj->prev != NULL ) maj->prev->next = maj->next; if ( maj->next != NULL ) maj->next->prev = maj->prev; l_allocated -= maj->size; liballoc_free( maj, maj->pages ); } else { if ( l_bestBet != NULL ) { int bestSize = l_bestBet->size - l_bestBet->usage; int majSize = maj->size - maj->usage; if ( majSize > bestSize ) l_bestBet = maj; } } #ifdef DEBUG serial_printf( "OK\n"); FLUSH(); #endif liballoc_unlock(); // release the lock }
void *PREFIX(malloc)(size_t req_size) { int startedBet = 0; unsigned long long bestSize = 0; void *p = NULL; uintptr_t diff; struct liballoc_major *maj; struct liballoc_minor *min; struct liballoc_minor *new_min; unsigned long size = req_size; // For alignment, we adjust size so there's enough space to align. if ( ALIGNMENT > 1 ) { size += ALIGNMENT + ALIGN_INFO; } // So, ideally, we really want an alignment of 0 or 1 in order // to save space. liballoc_lock(); if ( size == 0 ) { l_warningCount += 1; #if defined DEBUG || defined INFO serial_printf( "liballoc: WARNING: alloc( 0 ) called from %x\n", __builtin_return_address(0) ); FLUSH(); #endif liballoc_unlock(); return PREFIX(malloc)(1); } if ( l_memRoot == NULL ) { #if defined DEBUG || defined INFO #ifdef DEBUG serial_printf( "liballoc: initialization of liballoc " VERSION "\n" ); #endif //atexit( liballoc_dump ); FLUSH(); #endif // This is the first time we are being used. l_memRoot = allocate_new_page( size ); if ( l_memRoot == NULL ) { liballoc_unlock(); #ifdef DEBUG serial_printf( "liballoc: initial l_memRoot initialization failed\n", p); FLUSH(); #endif return NULL; } #ifdef DEBUG serial_printf( "liballoc: set up first memory major %x\n", l_memRoot ); FLUSH(); #endif } #ifdef DEBUG serial_printf( "liballoc: %x PREFIX(malloc)( %i ): ", __builtin_return_address(0), size ); FLUSH(); #endif // Now we need to bounce through every major and find enough space.... maj = l_memRoot; startedBet = 0; // Start at the best bet.... if ( l_bestBet != NULL ) { bestSize = l_bestBet->size - l_bestBet->usage; if ( bestSize > (size + sizeof(struct liballoc_minor))) { maj = l_bestBet; startedBet = 1; } } while ( maj != NULL ) { diff = maj->size - maj->usage; // free memory in the block if ( bestSize < diff ) { // Hmm.. this one has more memory then our bestBet. Remember! l_bestBet = maj; bestSize = diff; } #ifdef USE_CASE1 // CASE 1: There is not enough space in this major block. if ( diff < (size + sizeof( struct liballoc_minor )) ) { #ifdef DEBUG serial_printf( "CASE 1: Insufficient space in block %x\n", maj); FLUSH(); #endif // Another major block next to this one? if ( maj->next != NULL ) { maj = maj->next; // Hop to that one. continue; } if ( startedBet == 1 ) // If we started at the best bet, { // let's start all over again. maj = l_memRoot; startedBet = 0; continue; } // Create a new major block next to this one and... maj->next = allocate_new_page( size ); // next one will be okay. if ( maj->next == NULL ) break; // no more memory. maj->next->prev = maj; maj = maj->next; // .. fall through to CASE 2 .. } #endif #ifdef USE_CASE2 // CASE 2: It's a brand new block. if ( maj->first == NULL ) { maj->first = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major) ); maj->first->magic = LIBALLOC_MAGIC; maj->first->prev = NULL; maj->first->next = NULL; maj->first->block = maj; maj->first->size = size; maj->first->req_size = req_size; maj->usage += size + sizeof( struct liballoc_minor ); l_inuse += size; p = (void*)((uintptr_t)(maj->first) + sizeof( struct liballoc_minor )); ALIGN( p ); #ifdef DEBUG serial_printf( "CASE 2: returning %x\n", p); FLUSH(); #endif liballoc_unlock(); // release the lock return p; } #endif #ifdef USE_CASE3 // CASE 3: Block in use and enough space at the start of the block. diff = (uintptr_t)(maj->first); diff -= (uintptr_t)maj; diff -= sizeof(struct liballoc_major); if ( diff >= (size + sizeof(struct liballoc_minor)) ) { // Yes, space in front. Squeeze in. maj->first->prev = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major) ); maj->first->prev->next = maj->first; maj->first = maj->first->prev; maj->first->magic = LIBALLOC_MAGIC; maj->first->prev = NULL; maj->first->block = maj; maj->first->size = size; maj->first->req_size = req_size; maj->usage += size + sizeof( struct liballoc_minor ); l_inuse += size; p = (void*)((uintptr_t)(maj->first) + sizeof( struct liballoc_minor )); ALIGN( p ); #ifdef DEBUG serial_printf( "CASE 3: returning %x\n", p); FLUSH(); #endif liballoc_unlock(); // release the lock return p; } #endif #ifdef USE_CASE4 // CASE 4: There is enough space in this block. But is it contiguous? min = maj->first; // Looping within the block now... while ( min != NULL ) { // CASE 4.1: End of minors in a block. Space from last and end? if ( min->next == NULL ) { // the rest of this block is free... is it big enough? diff = (uintptr_t)(maj) + maj->size; diff -= (uintptr_t)min; diff -= sizeof( struct liballoc_minor ); diff -= min->size; // minus already existing usage.. if ( diff >= (size + sizeof( struct liballoc_minor )) ) { // yay.... min->next = (struct liballoc_minor*)((uintptr_t)min + sizeof( struct liballoc_minor ) + min->size); min->next->prev = min; min = min->next; min->next = NULL; min->magic = LIBALLOC_MAGIC; min->block = maj; min->size = size; min->req_size = req_size; maj->usage += size + sizeof( struct liballoc_minor ); l_inuse += size; p = (void*)((uintptr_t)min + sizeof( struct liballoc_minor )); ALIGN( p ); #ifdef DEBUG serial_printf( "CASE 4.1: returning %x\n", p); FLUSH(); #endif liballoc_unlock(); // release the lock return p; } } // CASE 4.2: Is there space between two minors? if ( min->next != NULL ) { // is the difference between here and next big enough? diff = (uintptr_t)(min->next); diff -= (uintptr_t)min; diff -= sizeof( struct liballoc_minor ); diff -= min->size; // minus our existing usage. if ( diff >= (size + sizeof( struct liballoc_minor )) ) { // yay...... new_min = (struct liballoc_minor*)((uintptr_t)min + sizeof( struct liballoc_minor ) + min->size); new_min->magic = LIBALLOC_MAGIC; new_min->next = min->next; new_min->prev = min; new_min->size = size; new_min->req_size = req_size; new_min->block = maj; min->next->prev = new_min; min->next = new_min; maj->usage += size + sizeof( struct liballoc_minor ); l_inuse += size; p = (void*)((uintptr_t)new_min + sizeof( struct liballoc_minor )); ALIGN( p ); #ifdef DEBUG serial_printf( "CASE 4.2: returning %x\n", p); FLUSH(); #endif liballoc_unlock(); // release the lock return p; } } // min->next != NULL min = min->next; } // while min != NULL ... #endif #ifdef USE_CASE5 // CASE 5: Block full! Ensure next block and loop. if ( maj->next == NULL ) { #ifdef DEBUG serial_printf( "CASE 5: block full\n"); FLUSH(); #endif if ( startedBet == 1 ) { maj = l_memRoot; startedBet = 0; continue; } // we've run out. we need more... maj->next = allocate_new_page( size ); // next one guaranteed to be okay if ( maj->next == NULL ) break; // uh oh, no more memory..... maj->next->prev = maj; } #endif maj = maj->next; } // while (maj != NULL) liballoc_unlock(); // release the lock #ifdef DEBUG serial_printf( "All cases exhausted. No memory available.\n"); FLUSH(); #endif #if defined DEBUG || defined INFO serial_printf( "liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size); liballoc_dump(); FLUSH(); #endif return NULL; }
void free(void *ptr) { int index; struct boundary_tag *tag; if ( ptr == NULL ) return; liballoc_lock(); tag = (struct boundary_tag*)((unsigned int)ptr - sizeof( struct boundary_tag )); if ( tag->magic != LIBALLOC_MAGIC ) { liballoc_unlock(); // release the lock return; } // MELT LEFT... while ( (tag->split_left != NULL) && (tag->split_left->index >= 0) ) { tag = melt_left( tag ); remove_tag( tag ); } // MELT RIGHT... while ( (tag->split_right != NULL) && (tag->split_right->index >= 0) ) { tag = absorb_right( tag ); } // Where is it going back to? index = getexp( tag->real_size - sizeof(struct boundary_tag) ); if ( index < MINEXP ) index = MINEXP; // A whole, empty block? if ( (tag->split_left == NULL) && (tag->split_right == NULL) ) { if ( l_completePages[ index ] == MAXCOMPLETE ) { // Too many standing by to keep. Free this one. unsigned int pages = tag->real_size / l_pageSize; if ( (tag->real_size % l_pageSize) != 0 ) pages += 1; if ( pages < l_pageCount ) pages = l_pageCount; liballoc_free( tag, pages ); liballoc_unlock(); return; } l_completePages[ index ] += 1; // Increase the count of complete pages. } // .......... insert_tag( tag, index ); liballoc_unlock(); }
void *malloc(uint64_t size) { int index; void *ptr; struct boundary_tag *tag = NULL; liballoc_lock(); if ( l_initialized == 0 ) { for ( index = 0; index < MAXEXP; index++ ) { l_freePages[index] = NULL; l_completePages[index] = 0; } l_initialized = 1; } index = getexp( size ) + MODE; if ( index < MINEXP ) index = MINEXP; // Find one big enough. tag = l_freePages[ index ]; // Start at the front of the list. while ( tag != NULL ) { // If there's enough space in this tag. if ( (tag->real_size - sizeof(struct boundary_tag)) >= (size + sizeof(struct boundary_tag) ) ) { break; } tag = tag->next; } // No page found. Make one. if ( tag == NULL ) { if ( (tag = allocate_new_tag( size )) == NULL ) { liballoc_unlock(); return NULL; } index = getexp( tag->real_size - sizeof(struct boundary_tag) ); } else { remove_tag( tag ); if ( (tag->split_left == NULL) && (tag->split_right == NULL) ) l_completePages[ index ] -= 1; } // We have a free page. Remove it from the free pages list. tag->size = size; // Removed... see if we can re-use the excess space. unsigned int remainder = tag->real_size - size - sizeof( struct boundary_tag ) * 2; // Support a new tag + remainder if ( ((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<<MINEXP))*/ ) { int childIndex = getexp( remainder ); if ( childIndex >= 0 ) { struct boundary_tag *new_tag = split_tag( tag ); new_tag = new_tag; // Get around the compiler warning about unused variables. } } ptr = (void*)((unsigned int)tag + sizeof( struct boundary_tag ) ); liballoc_unlock(); return ptr; }
void *malloc(size_t size) { void *p = NULL; unsigned int diff; struct liballoc_major *maj; struct liballoc_minor *min; struct liballoc_minor *new_min; if ( liballoc_lock != NULL ) liballoc_lock(); if ( l_memRoot == NULL ) { // This is the first time we are being used. l_memRoot = allocate_new_page( size ); if ( l_memRoot == NULL ) { if ( liballoc_unlock != NULL ) liballoc_unlock(); return NULL; } } // Now we need to bounce through every major and find enough space.... maj = l_memRoot; while ( maj != NULL ) { diff = maj->pages * (l_pageSize) - maj->usage; // free memory in the block // CASE 1: There is not enough space in this major block. if ( diff < (size + sizeof( struct liballoc_minor )) ) { // Another major block next to this one? if ( maj->next != NULL ) { maj = maj->next; // Hop to that one. continue; } // Create a new major block next to this one and... maj->next = allocate_new_page( size ); // next one will be okay. if ( maj->next == NULL ) break; // no more memory. maj->next->prev = maj; maj = maj->next; // .. fall through to CASE 2 .. } // CASE 2: It's a brand new block. if ( maj->first == NULL ) { maj->first = (struct liballoc_minor*)( (unsigned int)maj + sizeof(struct liballoc_major) ); maj->first->magic = LIBALLOC_MAGIC; maj->first->prev = NULL; maj->first->next = NULL; maj->first->block = maj; maj->first->size = size; maj->usage += size + sizeof( struct liballoc_minor ); p = (void*)((unsigned int)(maj->first) + sizeof( struct liballoc_minor )); if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock return p; } // CASE 3: Block in use and enough space at the start of the block. diff = (unsigned int)(maj->first) - (unsigned int)maj - sizeof(struct liballoc_major); if ( diff >= (size + sizeof(struct liballoc_minor)) ) { // Yes, space in front. Squeeze in. maj->first->prev = (struct liballoc_minor*)( (unsigned int)maj + sizeof(struct liballoc_major) ); maj->first->prev->next = maj->first; maj->first = maj->first->prev; maj->first->magic = LIBALLOC_MAGIC; maj->first->prev = NULL; maj->first->block = maj; maj->first->size = size; maj->usage += size + sizeof( struct liballoc_minor ); p = (void*)((unsigned int)(maj->first) + sizeof( struct liballoc_minor )); if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock return p; } // CASE 4: There is enough space in this block. But is it contiguous? min = maj->first; // Looping within the block now... while ( min != NULL ) { // CASE 4.1: End of minors in a block. Space from last and end? if ( min->next == NULL ) { // the rest of this block is free... is it big enough? diff = (unsigned int)(maj) + (l_pageSize) * maj->pages; diff -= ((unsigned int) min + sizeof( struct liballoc_minor ) + min->size); // minus already existing usage.. if ( diff >= size + sizeof( struct liballoc_minor ) ) { // yay.... min->next = (struct liballoc_minor*)((unsigned int)min + sizeof( struct liballoc_minor ) + min->size); min->next->prev = min; min = min->next; min->next = NULL; min->magic = LIBALLOC_MAGIC; min->block = maj; min->size = size; maj->usage += size + sizeof( struct liballoc_minor ); p = (void*)((unsigned int)min + sizeof( struct liballoc_minor )); if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock return p; } } // CASE 4.2: Is there space between two minors? if ( min->next != NULL ) { // is the difference between here and next big enough? diff = (unsigned int)(min->next) - (unsigned int)min - sizeof( struct liballoc_minor ) - min->size; // minus our existing usage. if ( diff >= size + sizeof( struct liballoc_minor ) ) { // yay...... new_min = (struct liballoc_minor*)((unsigned int)min + sizeof( struct liballoc_minor ) + min->size); new_min->magic = LIBALLOC_MAGIC; new_min->next = min->next; new_min->prev = min; new_min->size = size; new_min->block = maj; min->next->prev = new_min; min->next = new_min; maj->usage += size + sizeof( struct liballoc_minor ); p = (void*)((unsigned int)new_min + sizeof( struct liballoc_minor )); if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock return p; } } // min->next != NULL min = min->next; } // while min != NULL ... // CASE 5: Block full! Ensure next block and loop. if ( maj->next == NULL ) { // we've run out. we need more... maj->next = allocate_new_page( size ); // next one guaranteed to be okay if ( maj->next == NULL ) break; // uh oh, no more memory..... maj->next->prev = maj; } maj = maj->next; } // while (maj != NULL) if ( liballoc_unlock != NULL ) liballoc_unlock(); // release the lock return NULL; }
void free(void *ptr) { int index; struct boundary_tag *tag; if ( ptr == NULL ) return; liballoc_lock(); tag = (struct boundary_tag*)((unsigned int)ptr - sizeof( struct boundary_tag )); if ( tag->magic != LIBALLOC_MAGIC ) { liballoc_unlock(); // release the lock return; } #ifdef DEBUG l_inuse -= tag->size; printf("free: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 ); #endif // MELT LEFT... while ( (tag->split_left != NULL) && (tag->split_left->index >= 0) ) { #ifdef DEBUG printf("Melting tag left into available memory. Left was %i, becomes %i (%i)\n", tag->split_left->real_size, tag->split_left->real_size + tag->real_size, tag->split_left->real_size ); #endif tag = melt_left( tag ); remove_tag( tag ); } // MELT RIGHT... while ( (tag->split_right != NULL) && (tag->split_right->index >= 0) ) { #ifdef DEBUG printf("Melting tag right into available memory. This was was %i, becomes %i (%i)\n", tag->real_size, tag->split_right->real_size + tag->real_size, tag->split_right->real_size ); #endif tag = absorb_right( tag ); } // Where is it going back to? index = getexp( tag->real_size - sizeof(struct boundary_tag) ); if ( index < MINEXP ) index = MINEXP; // A whole, empty block? if ( (tag->split_left == NULL) && (tag->split_right == NULL) ) { if ( l_completePages[ index ] == MAXCOMPLETE ) { // Too many standing by to keep. Free this one. unsigned int pages = tag->real_size / l_pageSize; if ( (tag->real_size % l_pageSize) != 0 ) pages += 1; if ( pages < l_pageCount ) pages = l_pageCount; liballoc_free( tag, pages ); #ifdef DEBUG l_allocated -= pages * l_pageSize; printf("Resource freeing %x of %i pages\n", tag, pages ); dump_array(); #endif liballoc_unlock(); return; } l_completePages[ index ] += 1; // Increase the count of complete pages. } // .......... insert_tag( tag, index ); #ifdef DEBUG printf("Returning tag with %i bytes (requested %i bytes), which has exponent: %i\n", tag->real_size, tag->size, index ); dump_array(); #endif liballoc_unlock(); }
void *malloc(size_t size) { int index; void *ptr; struct boundary_tag *tag = NULL; liballoc_lock(); if ( l_initialized == 0 ) { #ifdef DEBUG printf("%s\n","liballoc initializing."); #endif for ( index = 0; index < MAXEXP; index++ ) { l_freePages[index] = NULL; l_completePages[index] = 0; } l_initialized = 1; } index = getexp( size ) + MODE; if ( index < MINEXP ) index = MINEXP; // Find one big enough. tag = l_freePages[ index ]; // Start at the front of the list. while ( tag != NULL ) { // If there's enough space in this tag. if ( (tag->real_size - sizeof(struct boundary_tag)) >= (size + sizeof(struct boundary_tag) ) ) { #ifdef DEBUG printf("Tag search found %i >= %i\n",(tag->real_size - sizeof(struct boundary_tag)), (size + sizeof(struct boundary_tag) ) ); #endif break; } tag = tag->next; } // No page found. Make one. if ( tag == NULL ) { if ( (tag = allocate_new_tag( size )) == NULL ) { liballoc_unlock(); return NULL; } index = getexp( tag->real_size - sizeof(struct boundary_tag) ); } else { remove_tag( tag ); if ( (tag->split_left == NULL) && (tag->split_right == NULL) ) l_completePages[ index ] -= 1; } // We have a free page. Remove it from the free pages list. tag->size = size; // Removed... see if we can re-use the excess space. #ifdef DEBUG printf("Found tag with %i bytes available (requested %i bytes, leaving %i), which has exponent: %i (%i bytes)\n", tag->real_size - sizeof(struct boundary_tag), size, tag->real_size - size - sizeof(struct boundary_tag), index, 1<<index ); #endif unsigned int remainder = tag->real_size - size - sizeof( struct boundary_tag ) * 2; // Support a new tag + remainder if ( ((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<<MINEXP))*/ ) { int childIndex = getexp( remainder ); if ( childIndex >= 0 ) { #ifdef DEBUG printf("Seems to be splittable: %i >= 2^%i .. %i\n", remainder, childIndex, (1<<childIndex) ); #endif struct boundary_tag *new_tag = split_tag( tag ); new_tag = new_tag; // Get around the compiler warning about unused variables. #ifdef DEBUG printf("Old tag has become %i bytes, new tag is now %i bytes (%i exp)\n", tag->real_size, new_tag->real_size, new_tag->index ); #endif } } ptr = (void*)((unsigned int)tag + sizeof( struct boundary_tag ) ); #ifdef DEBUG l_inuse += size; printf("malloc: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 ); dump_array(); #endif liballoc_unlock(); return ptr; }