Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
0
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);
}
Exemple #4
0
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;
}
Exemple #5
0
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;
	}
    }
}