void *malloc(size_t size) { register PACKET *current; register size_t newsize; register size_t oldsize; if (size <= 0) return NULL; if (check_alloc_size(size) == 0) return 0; if (need_mem_init) minit(); _lock(); /*-----------------------------------------------------------------------*/ /* SIZE IS CALCULATED BY FIRST ALIGNING (SIZE + BLOCK OVERHEAD) TO THE */ /* REQUIRED MINIMUM ALIGNMENT AND THEN SUBTRACTING THE BLOCK OVERHEAD. */ /*-----------------------------------------------------------------------*/ newsize = _M_RNDUP((size + _M_BLOCK_OVERHEAD), _M_MIN_ALN) - _M_BLOCK_OVERHEAD; current = sys_free; /*-----------------------------------------------------------------------*/ /* SCAN THROUGH FREE LIST FOR PACKET LARGE ENOUGH TO CONTAIN PACKET */ /*-----------------------------------------------------------------------*/ while (current && current->packet_size < newsize) current = current->size_ptr; if (!current) { _unlock(); return NULL; } oldsize = current->packet_size; /* REMEMBER OLD SIZE */ mremove(current); /* REMOVE PACKET FROM FREE LIST */ /*-----------------------------------------------------------------------*/ /* IF PACKET IS LARGER THAN NEEDED, FREE EXTRA SPACE AT END */ /* BY INSERTING REMAINING SPACE INTO FREE LIST. */ /*-----------------------------------------------------------------------*/ if (oldsize - newsize >= (_M_MIN_BLOCK + _M_BLOCK_OVERHEAD)) { register PACKET *next = (PACKET *) ((char *) current + _M_BLOCK_OVERHEAD + newsize); next->packet_size = oldsize - newsize - _M_BLOCK_OVERHEAD; minsert(next); current->packet_size = newsize; } current->packet_size |= _M_BLOCK_USED; _unlock(); return (char *)current + _M_BLOCK_OVERHEAD; }
void *realloc(void *userptr, size_t size) { PACKET *next, *prev, *sysblock; memsz_t newsize; /*-----------------------------------------------------------------------*/ /* Handle special cases */ /*-----------------------------------------------------------------------*/ if (check_alloc_size(size) == 0) return 0; newsize = (memsz_t)size; if (newsize == 0) { free(userptr); return 0; } if (userptr == 0) return malloc(newsize); /*-----------------------------------------------------------------------*/ /* We may need to adjust the size of the allocation request to ensure */ /* that the address of the field "next_free" remains strictly aligned */ /* in all packets on the free list. */ /*-----------------------------------------------------------------------*/ if ((newsize ^ OVERHEAD) & 1) ++newsize; /*-----------------------------------------------------------------------*/ /* Find the start of the system block containing the old allocation. */ /*-----------------------------------------------------------------------*/ sysblock = (PACKET *)((char *)userptr - OVERHEAD); /*-----------------------------------------------------------------------*/ /* Find the system block physically after SYSBLOCK on the heap. */ /*-----------------------------------------------------------------------*/ next = (PACKET *)((char *)userptr + sysblock->packet_size); /*-----------------------------------------------------------------------*/ /* If we are growing the packet, check if we must revert to calling */ /* malloc and copying the data. We must do so if: */ /* 1) sysblock is the last block in the heap, or */ /* 2) the next block is not free, or */ /* 3) the next block is free but not big enough. */ /*-----------------------------------------------------------------------*/ _lock(); if ((newsize > sysblock->packet_size) && (((char *)next >= (char *)sys_base + memsize) || (next->packet_size > 0) || ((next->packet_size < 0) && (newsize > sysblock->packet_size - next->packet_size + OVERHEAD)))) { void *ptr; _unlock(); ptr = malloc(newsize); if (ptr) { memcpy(ptr, userptr, sysblock->packet_size); free(userptr); } return ptr; } /*-----------------------------------------------------------------------*/ /* Once we reach here, we know we can realloc in place. */ /*-----------------------------------------------------------------------*/ /* Search the free list for the *free* packets physically closest to */ /* the packet to be freed. PREV is the closest free packet with a */ /* smaller address, and NEXT is the closest free packet with a larger */ /* address. */ /*-----------------------------------------------------------------------*/ next = sys_free; prev = 0; while (next < sysblock) { prev = next; next = next->next_free; } if ((char *)next == (char *)userptr + sysblock->packet_size) { /*-------------------------------------------------------------------*/ /* The system block immediately following SYSBLOCK is free. */ /* Coalesce with it, then try to free the unused portion. */ /*-------------------------------------------------------------------*/ #ifdef DEBUG next->guard = 0; #endif if (sysblock->packet_size + -next->packet_size - newsize <= MINSIZE) { /*---------------------------------------------------------------*/ /* The next block is completely absorbed. */ /*---------------------------------------------------------------*/ if (prev) prev->next_free = next->next_free; else sys_free = next->next_free; sysblock->packet_size += -next->packet_size + OVERHEAD; /* SGN<0 */ } else { /*---------------------------------------------------------------*/ /* The next block has enough space left over to break off a new */ /* block and add it to the free list. */ /*---------------------------------------------------------------*/ PACKET *nextnext = next->next_free; int nextsize = -next->packet_size + sysblock->packet_size - newsize; PACKET *newnext = (PACKET*)((char *)userptr + newsize); newnext->packet_size = -nextsize; /* NEGATIVE==FREE */ newnext->next_free = nextnext; #ifdef DEBUG newnext->guard = GUARDWORD; #endif sysblock->packet_size = newsize; /* POSITIVE==IN USE */ if (prev) prev->next_free = newnext; else sys_free = newnext; } } else { /*-------------------------------------------------------------------*/ /* Shrink in place if there is enough extra to make a free block */ /*-------------------------------------------------------------------*/ if (sysblock->packet_size - newsize >= OVERHEAD + MINSIZE) { int nextsize = sysblock->packet_size - newsize - OVERHEAD; PACKET *newnext = (PACKET*)((char *)userptr + newsize); newnext->packet_size = -nextsize; /* NEGATIVE==FREE */ newnext->next_free = next; #ifdef DEBUG newnext->guard = GUARDWORD; #endif sysblock->packet_size = newsize; /* POSITIVE==IN USE */ if (prev) prev->next_free = newnext; else sys_free = newnext; } } _unlock(); return userptr; }
void *malloc(size_t size) { memsz_t allocsize; PACKET *current, *next, *prev; if (check_alloc_size(size) == 0) return 0; allocsize = (memsz_t)size; if (allocsize == 0) return 0; /*-----------------------------------------------------------------------*/ /* We may need to adjust the size of the allocation request to ensure */ /* that the address of the field "next_free" remains strictly aligned */ /* in all packets on the free list. */ /*-----------------------------------------------------------------------*/ if ((allocsize ^ OVERHEAD) & 1) ++allocsize; _lock(); if (first_call) minit(); current = sys_free; prev = 0; /*-----------------------------------------------------------------------*/ /* Find the first block large enough to hold the requested allocation */ /*-----------------------------------------------------------------------*/ while (current != LIMIT && -current->packet_size < allocsize) { prev = current; current = current->next_free; } if (current == LIMIT) { /*-------------------------------------------------------------------*/ /* No block large enough was found, so return NULL. */ /*-------------------------------------------------------------------*/ _unlock(); return 0; } if (-current->packet_size > (allocsize + OVERHEAD + MINSIZE)) { /*-------------------------------------------------------------------*/ /* The packet is larger than needed; split the block and mark the */ /* smaller-addressed block as used. The smaller-addressed block */ /* was chosen as a way to ensure that freed blocks get recycled */ /* before allocations are made from the large original free block. */ /* However, this may tend to increase the length of the free list */ /* search for a large enough block. */ /*-------------------------------------------------------------------*/ /* Knuth's algorithm 2.5a instead allocates the larger-addressed */ /* block to the user. This tends to leave the largest free blocks */ /* at the beginning of the free list. Knuth's 2.5a' uses a "rover" */ /* pointer to prevent small free blocks from being concentrated in */ /* any part of the list. */ /*-------------------------------------------------------------------*/ next = (PACKET *)((char *)current + allocsize + OVERHEAD); next->packet_size=current->packet_size+allocsize+OVERHEAD;/*NEG==FREE*/ #ifdef DEBUG next->guard = GUARDWORD; #endif current->packet_size = allocsize; /* POSITIVE==IN USE */ if (prev) prev->next_free = next; else sys_free = next; next->next_free = current->next_free; } else { /*-------------------------------------------------------------------*/ /* Allocate the whole block and remove it from the free list. */ /*-------------------------------------------------------------------*/ if (prev) prev->next_free = current->next_free; else sys_free = current->next_free; current->packet_size = -current->packet_size; /* POSITIVE==IN USE */ } _unlock(); return &(current->next_free); }
void *memalign(size_t alignment, size_t size) { PACKET *aln_packet; PACKET *current; size_t newsize; size_t aln_mask = alignment - 1; int leftover = -1; char *aln_start; char *un_aln_start; if (size <= 0) return NULL; if (check_alloc_size(size) == 0) return NULL; /*--------------------------------------------------------------------*/ /* IF ALIGNMENT IS NOT A POWER OF TWO OR IS LESS THAN THE DEFAULT */ /* ALIGNMENT OF MALLOC, THEN SIMPLY RETURN WHAT MALLOC RETURNS. */ /*--------------------------------------------------------------------*/ if (alignment <= _M_MIN_ALN || (alignment & (alignment-1))) return malloc(size); if (need_mem_init) minit(); _lock(); newsize = _M_RNDUP((size + _M_BLOCK_OVERHEAD), _M_MIN_ALN) - _M_BLOCK_OVERHEAD; current = sys_free; /*-----------------------------------------------------------------------*/ /* SCAN THROUGH FREE LIST FOR PACKET LARGE ENOUGH TO CONTAIN ALIGNED */ /* PACKET */ /*-----------------------------------------------------------------------*/ for ( ; current ; current = current->size_ptr) { un_aln_start = (char *) current + _M_BLOCK_OVERHEAD; /*--------------------------------------------------------------------*/ /* IT IS POSSIBLE THAT WE COULD OVERFLOW THE size_t TYPE BELOW, BUT */ /* ADDING A CHECK HERE WOULD LIKELY BE A SIGNIFICANT PERFORMANCE HIT. */ /*--------------------------------------------------------------------*/ aln_start = (char *)(((size_t) un_aln_start + aln_mask) & ~aln_mask); leftover = un_aln_start + current->packet_size - aln_start -newsize; /*--------------------------------------------------------------------*/ /* MAKE SURE THAT THE PRE BLOCK SPACE IS LARGE ENOUGH TO BE A BLOCK */ /* OF ITS OWN. */ /*--------------------------------------------------------------------*/ for ( ; (char *)current+sizeof(PACKET) > aln_start-_M_BLOCK_OVERHEAD ; aln_start += alignment, leftover -= alignment); if (leftover >= 0) break; } if (!current) { _unlock(); return NULL; } /*-----------------------------------------------------------------------*/ /* SETUP NEW PACKET FOR ALIGNED MEMORY. */ /*-----------------------------------------------------------------------*/ mremove(current); aln_packet = (PACKET *) (aln_start - _M_BLOCK_OVERHEAD); aln_packet->packet_size = newsize | _M_BLOCK_USED; /*-----------------------------------------------------------------------*/ /* HANDLE THE FREE SPACE BEFORE THE ALIGNED BLOCK. IF THE ORIGINAL */ /* BLOCK WAS ALIGNED, THERE WON'T BE FREE SPACE BEFORE THE ALIGNED BLOCK.*/ /*-----------------------------------------------------------------------*/ if (aln_start != un_aln_start) { current->packet_size = (char *)aln_packet - un_aln_start; minsert(current); } /*-----------------------------------------------------------------------*/ /* HANDLE THE FREE SPACE AFTER THE ALIGNED BLOCK. IF IT IS LARGE ENOUGH */ /* TO BE A BLOCK OF ITS OWN, THEN MAKE IT ONE, OTHERWISE ADD THE */ /* LEFTOVER SIZE TO THE ALIGNED BLOCK. */ /*-----------------------------------------------------------------------*/ if (leftover >= _M_BLOCK_OVERHEAD + _M_MIN_BLOCK) { register PACKET *next = (PACKET *) (aln_start + newsize); next->packet_size = leftover - _M_BLOCK_OVERHEAD; minsert(next); } else aln_packet->packet_size += leftover; _unlock(); return aln_start; }
void *realloc(void *packet, size_t size) { register char *pptr = (char *) packet - _M_BLOCK_OVERHEAD; register size_t newsize; register size_t oldsize; if (packet == 0) return malloc(size); if (size == 0) { free(packet); return NULL; } if (check_alloc_size(size) == 0) return 0; if (need_mem_init) minit(); _lock(); /*-----------------------------------------------------------------------*/ /* NEW SIZE IS CALCULATED BY FIRST ALIGNING (SIZE+BLOCK OVERHEAD) TO THE */ /* REQUIRED MINIMUM ALIGNMENT AND THEN SUBTRACTING THE BLOCK OVERHEAD. */ /*-----------------------------------------------------------------------*/ newsize = _M_RNDUP((size + _M_BLOCK_OVERHEAD), _M_MIN_ALN) - _M_BLOCK_OVERHEAD; oldsize = ((PACKET *)pptr)->packet_size; if (!(oldsize & _M_BLOCK_USED)) { _unlock(); return NULL; } if (newsize == --oldsize) { _unlock(); return packet; } /*-----------------------------------------------------------------------*/ /* IF NEW SIZE IS LESS THAN CURRENT SIZE, TRUNCATE PACKET AND RETURN END */ /* TO FREE LIST */ /*-----------------------------------------------------------------------*/ if (newsize < oldsize) { if (oldsize - newsize < (_M_MIN_BLOCK + _M_BLOCK_OVERHEAD)) { _unlock(); return packet; } ((PACKET *)pptr)->packet_size = newsize | _M_BLOCK_USED; oldsize -= newsize + _M_BLOCK_OVERHEAD; pptr += newsize + _M_BLOCK_OVERHEAD; ((PACKET *)pptr)->packet_size = oldsize | _M_BLOCK_USED; free(pptr + _M_BLOCK_OVERHEAD); _unlock(); return packet; } /*-----------------------------------------------------------------------*/ /* IF NEW SIZE IS BIGGER THAN CURRENT PACKET, */ /* 1) CHECK NEXT PACKET IN LIST, SEE IF PACKET CAN BE EXPANDED */ /* 2) IF NOT, MOVE PACKET TO NEW LOCATION. */ /*-----------------------------------------------------------------------*/ else { PACKET *next = (PACKET *)(pptr + oldsize + _M_BLOCK_OVERHEAD); int temp; if (((char *)next < &heap_mem[_memory_size - _M_BLOCK_OVERHEAD]) && (!(next->packet_size & _M_BLOCK_USED)) && ((temp = oldsize + next->packet_size +_M_BLOCK_OVERHEAD - newsize) >= 0)) { mremove(next); if (temp < _M_MIN_BLOCK + _M_BLOCK_OVERHEAD) { ((PACKET *)pptr)->packet_size = newsize + temp | _M_BLOCK_USED; _unlock(); return packet; } ((PACKET *)pptr)->packet_size = newsize | _M_BLOCK_USED; pptr += newsize + _M_BLOCK_OVERHEAD; ((PACKET *)pptr)->packet_size = temp - _M_BLOCK_OVERHEAD; minsert((PACKET *)pptr); _unlock(); return packet; } else { /*---------------------------------------------------------------*/ /* ALLOCATE NEW PACKET AND MOVE DATA INTO IT. */ /*---------------------------------------------------------------*/ register char *new_packet = (char *)malloc(size); if (new_packet == 0) { _unlock(); return NULL; } memcpy(new_packet, packet, oldsize); free(packet); _unlock(); return new_packet; } } }