forked from KolibriOS/kolibrios
Clib string & memory functions
git-svn-id: svn://kolibrios.org@553 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
205
programs/develop/open watcom/trunk/clib/heap/nexpand.c
Normal file
205
programs/develop/open watcom/trunk/clib/heap/nexpand.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Open Watcom Project
|
||||
*
|
||||
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
|
||||
*
|
||||
* ========================================================================
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original
|
||||
* Code as defined in and that are subject to the Sybase Open Watcom
|
||||
* Public License version 1.0 (the 'License'). You may not use this file
|
||||
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
|
||||
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
|
||||
* provided with the Original Code and Modifications, and is also
|
||||
* available at www.sybase.com/developer/opensource.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
|
||||
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
|
||||
* NON-INFRINGEMENT. Please see the License for the specific language
|
||||
* governing rights and limitations under the License.
|
||||
*
|
||||
* ========================================================================
|
||||
*
|
||||
* Description: Near heap expansion routines.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
//#include "dll.h" // needs to be first
|
||||
#include "variety.h"
|
||||
#include <stddef.h>
|
||||
#include <malloc.h>
|
||||
#include "heap.h"
|
||||
#include "heapacc.h"
|
||||
#if defined(__DOS_EXT__)
|
||||
#include "extender.h"
|
||||
#endif
|
||||
|
||||
#if defined(__SMALL_DATA__)
|
||||
|
||||
_WCRTLINK void *_expand( void *stg, size_t amount )
|
||||
{
|
||||
return( _nexpand( stg, amount ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__AXP__) || defined(__PPC__)
|
||||
#define _SEGMENT int
|
||||
#else
|
||||
#define _SEGMENT __segment
|
||||
#endif
|
||||
|
||||
int __HeapManager_expand( _SEGMENT seg,
|
||||
unsigned offset,
|
||||
size_t req_size,
|
||||
size_t *growth_size )
|
||||
{
|
||||
#if defined(M_I86)
|
||||
typedef struct freelistp __based(seg) *fptr;
|
||||
typedef char __based(void) *cptr;
|
||||
|
||||
struct miniheapblkp __based(seg) *hblk;
|
||||
#else
|
||||
typedef struct freelistp _WCNEAR *fptr;
|
||||
typedef char _WCNEAR *cptr;
|
||||
|
||||
mheapptr hblk;
|
||||
#endif
|
||||
fptr p1;
|
||||
fptr p2;
|
||||
fptr pnext;
|
||||
fptr pprev;
|
||||
size_t new_size;
|
||||
size_t old_size;
|
||||
size_t free_size;
|
||||
|
||||
/* round (new_size + tag) to multiple of pointer size */
|
||||
new_size = (req_size + TAG_SIZE + ROUND_SIZE) & ~ROUND_SIZE;
|
||||
if( new_size < req_size ) new_size = ~0; //go for max
|
||||
if( new_size < FRL_SIZE ) {
|
||||
new_size = FRL_SIZE;
|
||||
}
|
||||
p1 = (fptr) ((cptr)offset - TAG_SIZE);
|
||||
old_size = p1->len & ~1;
|
||||
if( new_size > old_size ) {
|
||||
/* enlarging the current allocation */
|
||||
p2 = (fptr) ((cptr)p1 + old_size);
|
||||
*growth_size = new_size - old_size;
|
||||
for(;;) {
|
||||
free_size = p2->len;
|
||||
if( p2->len == END_TAG ) {
|
||||
return( __HM_TRYGROW );
|
||||
} else if( free_size & 1 ) { /* next piece is allocated */
|
||||
break;
|
||||
} else {
|
||||
pnext = p2->next;
|
||||
pprev = p2->prev;
|
||||
|
||||
if( seg == _DGroup() ) { // near heap
|
||||
for( hblk = __nheapbeg; hblk->next; hblk = hblk->next ) {
|
||||
if( (fptr)hblk <= (fptr)offset &&
|
||||
(fptr)((PTR)hblk+hblk->len) > (fptr)offset ) break;
|
||||
}
|
||||
}
|
||||
#if defined(M_I86)
|
||||
else { // Based heap
|
||||
hblk = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( hblk->rover == p2 ) { /* 09-feb-91 */
|
||||
hblk->rover = p2->prev;
|
||||
}
|
||||
if( free_size < *growth_size ||
|
||||
free_size - *growth_size < FRL_SIZE ) {
|
||||
/* unlink small free block */
|
||||
pprev->next = pnext;
|
||||
pnext->prev = pprev;
|
||||
p1->len += free_size;
|
||||
hblk->numfree--;
|
||||
if( free_size >= *growth_size ) {
|
||||
return( __HM_SUCCESS );
|
||||
}
|
||||
*growth_size -= free_size;
|
||||
p2 = (fptr) ((cptr)p2 + free_size);
|
||||
} else {
|
||||
p2 = (fptr) ((cptr)p2 + *growth_size);
|
||||
p2->len = free_size - *growth_size;
|
||||
p2->prev = pprev;
|
||||
p2->next = pnext;
|
||||
pprev->next = p2;
|
||||
pnext->prev = p2;
|
||||
p1->len += *growth_size;
|
||||
return( __HM_SUCCESS );
|
||||
}
|
||||
}
|
||||
}
|
||||
/* no suitable free blocks behind, have to move block */
|
||||
return( __HM_FAIL );
|
||||
} else {
|
||||
/* shrinking the current allocation */
|
||||
if( old_size - new_size >= FRL_SIZE ) {
|
||||
/* block big enough to split */
|
||||
p1->len = new_size | 1;
|
||||
p1 = (fptr) ((cptr)p1 + new_size);
|
||||
p1->len = (old_size - new_size) | 1;
|
||||
if( seg == _DGroup() ) { // near heap
|
||||
for( hblk = __nheapbeg; hblk->next; hblk = hblk->next ) {
|
||||
if( (fptr)hblk <= (fptr)offset &&
|
||||
(fptr)((PTR)hblk+hblk->len) > (fptr)offset ) break;
|
||||
}
|
||||
}
|
||||
#if defined(M_I86)
|
||||
else // Based heap
|
||||
hblk = 0;
|
||||
#endif
|
||||
/* _bfree will decrement 'numalloc' 08-jul-91 */
|
||||
hblk->numalloc++;
|
||||
#if defined(M_I86)
|
||||
_bfree( seg, (cptr)p1 + TAG_SIZE );
|
||||
/* free the top portion */
|
||||
#else
|
||||
_nfree( (cptr)p1 + TAG_SIZE );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return( __HM_SUCCESS );
|
||||
}
|
||||
|
||||
|
||||
_WCRTLINK void _WCNEAR *_nexpand( void _WCNEAR *stg, size_t req_size )
|
||||
{
|
||||
struct {
|
||||
unsigned expanded : 1;
|
||||
} flags;
|
||||
int retval;
|
||||
size_t growth_size;
|
||||
|
||||
flags.expanded = 0;
|
||||
_AccessNHeap();
|
||||
for( ;; ) {
|
||||
retval = __HeapManager_expand( _DGroup(),
|
||||
(unsigned) stg,
|
||||
req_size,
|
||||
&growth_size );
|
||||
if( retval == __HM_SUCCESS ) {
|
||||
_ReleaseNHeap();
|
||||
return( stg );
|
||||
}
|
||||
if( retval == __HM_FAIL || !__IsCtsNHeap() ) break;
|
||||
if( retval == __HM_TRYGROW ) {
|
||||
if( flags.expanded ) break;
|
||||
if( __ExpandDGROUP( growth_size ) == 0 ) {
|
||||
break;
|
||||
}
|
||||
flags.expanded = 1;
|
||||
}
|
||||
}
|
||||
_ReleaseNHeap();
|
||||
return( NULL );
|
||||
}
|
Reference in New Issue
Block a user