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); }
/*{ ** 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; }