Example #1
0
PTR
MEreqmem(
	u_i2	tag,
	SIZE_TYPE size,
	bool	zero,
	STATUS	*status)
{
    PTR	block=NULL;
    register ME_NODE *node;		/* the node to return */
    register ME_NODE *start;		/* for searching free list */
    register ME_NODE *this;		/* block to get node from */
    register ME_NODE *frag;		/* fragment block */
    
    ME_NODE 	*tmp;			/* not register for MEadd */
    SIZE_TYPE	nsize;			/* nsize node to obtain */
    SIZE_TYPE	fsize;			/* size of 'this' fragment block */
    SIZE_TYPE	newstuff;		/* size to add to process, or  0 */
    SIZE_TYPE	prev_actual;		/* rescan free list? */
    SIZE_TYPE	alloc_pages;
    CL_ERR_DESC	err_code;

    STATUS	MEstatus = OK;
    
    i_meuser += size;
    
    if (!size)
	MEstatus = ME_NO_ALLOC;
    
    if( !MEsetup )
        MEinitLists();
    
    /*
    **	Try to do the allocation.
    */
    if( MEstatus == OK )
    {
	nsize = SIZE_ROUND( size );
	/*
	** Get memory with malloc().
	*/
	if( MEadvice == ME_USER_ALLOC )
	{
	    if( (node = (ME_NODE *)malloc( nsize )) == NULL )
	    	MEstatus = ME_GONE;
	}
	/*
	** Get block from private free list.
	*/
	else
	{
# ifdef OS_THREADS_USED
	    CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */

	    /*
	    **  Look on free list for 1st block big enough
	    **  to hold request.  This linear search can be slow.
	    */
	    start = (ME_NODE *)&MEfreelist;
	    this = MEfreelist.MEfirst;
	    while ( this != NULL && this != start && this->MEsize < nsize )
		this = this->MEnext;
	    
	    if( this == NULL )
	        MEstatus = ME_CORRUPTED;
	    
	    /*
	    ** At this point, we are in one of three states:
	    ** 1)  Corrupted memory; MEstatus != OK
	    ** 2)  this is good node, this != start
	    ** 3)  No good node; this == start;
	    */
	    if ( MEstatus == OK )
	    {
		/*
		** If nothing on free list is big enough
		** get one or more standard blocks from system,
		** take what is needed and add remainder
		** to free list.
		*/
		if (this != start)
		{
		    /* take right off the free list */
		    newstuff = 0;
		}
		else	/* this == start */
		{
		    /*
		     * Expand the free list by calling getpages
		     * newstuff holds the number of pages needed
		     */
		    newstuff = (nsize + ME_MPAGESIZE-1)/ME_MPAGESIZE;
		    /* if first time allocation, get enough for MO overhead */
		    if ( (prev_actual = i_meactual) == (SIZE_TYPE) 0 )
			newstuff += 4;
# ifdef OS_THREADS_USED
	            CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    MEstatus = MEget_pages(ME_SPARSE_MASK, newstuff, NULL, 
			(PTR *)&tmp, &alloc_pages, &err_code);
# ifdef OS_THREADS_USED
	            CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    if (MEstatus == OK)
		    {
			/* now we need to find where to put this new memory
			   on the sorted free list - we search in reverse */
			tmp->MEsize = newstuff * ME_MPAGESIZE;
			this = MEfreelist.MElast;
			while (start != this && this != NULL &&
			       this > tmp)
			    this = this->MEprev;
			if (this != start && NEXT_NODE(this) == tmp)
			{
			    this->MEsize += tmp->MEsize;
			}
			else
			{
			    (void)QUinsert( (QUEUE *) tmp, (QUEUE *)this );
			    this = tmp;
			}
			if (this->MEnext != start &&
			    NEXT_NODE(this) == this->MEnext)
			{
			    this->MEsize += this->MEnext->MEsize;
			    (void)QUremove( (QUEUE *) this->MEnext);
			}
			/*
			** While the free list mutex was released, another
			** thread may have freed up a big enough piece of
			** memory for our needs, or may have extended the
			** free list.
			** If that's the case, research the free list;
			** we'll find either a right-sized node or 
			** the new memory we just added to the free list.
			*/
			if ( prev_actual != i_meactual )
			{
			    this = MEfreelist.MEfirst;
			    while ( this != NULL && this != start && this->MEsize < nsize )
				this = this->MEnext;
		
			    if( this == NULL )
				MEstatus = ME_CORRUPTED;
			}
		    }
		    else
			if (MEstatus == ME_OUT_OF_MEM)
			    MEstatus = ME_GONE;
		}

		/*
		** At this point, we can be in two states.
		** 1)  Corrupted memory, MEstatus != OK
		** 2)  'this' is an OK node from the free list.
		*/
		
		if ( MEstatus == OK )
		{
		    node = this;
		    
		    /*
		    ** if this is correct size or would
		    **   leave useless block in chain
		    **	just move block to allocated list
		    ** else
		    **	grab what is needed from 'this'
		    **	  block and then update 'this'
		    */
		    
		    fsize = node->MEsize - nsize;
		    if ( fsize <= sizeof(ME_NODE) )
		    {
			(void)QUremove( (QUEUE *) node );
			
			/* fudge size in node to eat leftover amount. */
			fsize = 0;
			nsize = node->MEsize;
		    }
		    else	/* make fragment block */
		    {
			/*
			** Make a leftover block after the
			** allocated space in node, in 'this'
			*/
			frag = (ME_NODE *)((char *) node + nsize );
			frag->MEsize = fsize;
			frag->MEtag = 0;
			
			/* remove node, add fragment to free list */
			(void)QUremove( (QUEUE *) node );
			MEstatus = MEfadd( frag, FALSE );
			
		    }  /* fragment left over */
		    /* Increment meactual while mutex held */
		    i_meactual += nsize;
		}  /* Got a node */
	    }  /* free list search OK */
# ifdef OS_THREADS_USED
	    CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
	}  /* ME_USER_ALLOC */
	
	/*
	** At this point we are in one of two states:
	** 1.  Corrupted, MEstatus != OK.
	** 2.  Have a 'node' to use, from freelist or malloc.
	**     The freelist is consistant, but the allocated list is
	**     not setup for the node. "nsize" is the actual size of "node".
	*/
	
	if( MEstatus == OK )
	{
	    /* splice into allocated object queue */
	    if (0 == tag)
	    {
# ifdef OS_THREADS_USED
	    	CS_synch_lock( &MElist_mutex );
# endif /* OS_THREADS_USED */
	    	(void)QUinsert( (QUEUE *) node, (QUEUE *) MElist.MElast );
# ifdef OS_THREADS_USED
		CS_synch_unlock( &MElist_mutex );
# endif /* OS_THREADS_USED */
	    }
	    else
	    {
		IIME_atAddTag(tag, node);
	    }
	    /* Set values in block to be returned */
	    node->MEtag = tag;
	    node->MEsize = nsize;
	    node->MEaskedfor = size;
	    
	    /* Fill in the returned pointer */
	    block = (PTR)((char *)node + sizeof(ME_NODE));
	    
	    if (zero)
		MEfill( (nsize - sizeof(ME_NODE)), 0, block);
	}  /* got node OK */
    }
    if (status != NULL)
	*status = MEstatus;
    if (MEstatus != OK)
	return((PTR)NULL);
    else
	return(block);
}
Example #2
0
/*{
** Name:	IIME_ftFreeTag	- Free all allocated memory for a tag.
**
** Description:
**	This routine is called by MEtfree to free all the allocated 
**	memory for a tag.
**
**	It works by finding the METAGNODE for the tag in the hash table
**	and then traversing the QUEUE of allocated blocks freeing
**	each block.
**
** Inputs:
**	tag		The tag whose memory is to be freed.
**
** Outputs:
**	Returns:
**		OK if all the allocated memory for the tag was freed.
**		ME_NO_TFREE if the tag does not have a record in the hash table.
**		other failure status if the nodes can't be freed.
**
** Side Effects:
**	Will return the METAGNODE for the tag to freelist.
**
** History:
**	5-dec-1989 (Joe)
**	    First Written
**      30-May-96 (stial01)
**          New advice ME_TUXEDO_ALLOC should behave like ME_INGRES_ALLOC
**	12-feb-1997 (canor01)
**	    Initialize local MEstatus.
**      27-Jan-1999 (fanra01)
**          Add thread alloc case for tag free.  Otherwise our memory is
**          returned to the system heap causing wonderfully esoteric execution.
*/
STATUS
IIME_ftFreeTag(
	i4	tag )
{
    register METAGNODE	**first;
    STATUS MEstatus = OK;

# ifdef OS_THREADS_USED
    CS_synch_lock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
    for (first = &(htab[tag%256]);
	 *first != NULL;
	 first = &((*first)->met_hash))
    {
	if ((*first)->met_tag == tag)
	{
	    register ME_NODE	*this;
	    register ME_NODE	*next;
	    register METAGNODE	*freenode;

	    for (this = (*first)->met_list.MEfirst;
		 this != NULL && this != (ME_NODE *) &((*first)->met_list);)
	    {
		next = this->MEnext;
		if ( MEstatus == OK )
		{
		    i_meactual -= this->MEsize;
		    i_meuser -= this->MEaskedfor;
		    (void)QUremove( (QUEUE *) this );
		    if( (MEadvice == ME_INGRES_ALLOC )
			|| (MEadvice == ME_INGRES_THREAD_ALLOC)
			|| (MEadvice == ME_TUXEDO_ALLOC) )
		    {
# ifdef OS_THREADS_USED
			CS_synch_lock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
			MEstatus = MEfadd(this, TRUE);
# ifdef OS_THREADS_USED
			CS_synch_unlock( &MEfreelist_mutex );
# endif /* OS_THREADS_USED */
		    }
		    else
			free( (char *)this );
		}
		if (MEstatus == OK)
		    this = next;
		else
		    break;
	    }
	    freenode =  *first;
	    *first = freenode->met_hash;
	    freenode->met_hash = freelist;
	    freelist = freenode;
# ifdef OS_THREADS_USED
	    CS_synch_unlock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
	    return MEstatus;
	}
    }
# ifdef OS_THREADS_USED
    CS_synch_unlock( &MEtaglist_mutex );
# endif /* OS_THREADS_USED */
    return ME_NO_TFREE;
}