ftp.nice.ch/pub/next/developer/languages/lisp/AKCL.1.599.s.tar.gz#/akcl-1-599/c/alloc.c

This is alloc.c in view mode; [Download] [Up]

/*
(c) Copyright Taiichi Yuasa and Masami Hagiya, 1984.  All rights reserved.
Copying of this file is authorized to users who have executed the true and
proper "License Agreement for Kyoto Common LISP" with SIGLISP.
*/

/*
	alloc.c
	IMPLEMENTATION-DEPENDENT
*/

#include "include.h"


object Vignore_maximum_pages;


#include "page.h"

#ifdef DEBUG_SBRK
int debug;
char *
sbrk1(n)
     int n;
{char *ans;
 if (debug){
   printf("\n{sbrk(%d)",n);
   fflush(stdout);}
 ans= (char *)sbrk(n);
 if (debug){
   printf("->[0x%x]", ans);
   fflush(stdout);
   printf("core_end=0x%x,sbrk(0)=0x%x}",core_end,sbrk(0));
   fflush(stdout);}
 return ans;
}
#define sbrk sbrk1
#endif /* DEBUG_SBRK */

int real_maxpage = MAXPAGE;
int new_holepage;

#define	available_pages	\
	(real_maxpage-page(heap_end)-new_holepage-2*nrbpage-real_maxpage/32)


#ifdef UNIX
extern char *sbrk();
#endif

#ifdef BSD
#include <sys/time.h>
#include <sys/resource.h>
struct rlimit data_rlimit;
extern char etext;
#endif


/* If  (n >= 0 ) return pointer to n pages starting at heap end,
   These must come from the hole, so if that is exhausted you have
   to gc and move the hole.
   if  (n < 0) return pointer to n pages starting at heap end,
   but don't worry about the hole.   Basically just make sure
   the space is available from the Operating system.
 */
char *
alloc_page(n)
int n;
{
	char *e;
	int m;
	e = heap_end;
	if (n >= 0) {
		if (n >= holepage) {
			holepage = new_holepage + n;

			{int in_sgc=sgc_enabled;
			 if (in_sgc) sgc_quit();
			GBC(t_relocatable);
			if (in_sgc)
			  {sgc_start();
			   /* starting sgc can use up some pages
			      and may move heap end, so start over
			    */
			   return alloc_page(n);}
		       }
		}
		holepage -= n;
		heap_end += PAGESIZE*n;
		return(e);
	}
     else
       /* n < 0 , then this says ensure there are -n pages
	  starting at heap_end, and return pointer to heap_end */
      {
	n = -n;
	m = (core_end - heap_end)/PAGESIZE;
	if (n <= m)
		return(e);

	IF_ALLOCATE_ERR error("Can't allocate.  Good-bye!");
#ifdef SGC
	if (sgc_enabled)
	  make_writable(page(core_end),page(core_end)+n-m);

#endif	
	core_end += PAGESIZE*(n - m);
	return(e);}
}

void
add_page_to_freelist(p,tm)
     char *p;
     struct typemanager *tm;
{short t,size;
 int i=tm->tm_nppage,fw;
 int nn;
 object x,f;
 t=tm->tm_type;
#ifdef SGC
 nn=page(p);
 if (sgc_enabled)
   { if (!WRITABLE_PAGE_P(nn)) make_writable(nn,nn+1);}
#endif
 type_map[page(p)]= t;
 size=tm->tm_size;
 f=tm->tm_free;
 x= (object)p;
 x->d.t=t;
 x->d.m=FREE;
#ifdef SGC
 if (sgc_enabled && tm->tm_sgc)
   {x->d.s=SGC_RECENT;
    sgc_type_map[page(x)] = (SGC_PAGE_FLAG | SGC_TEMP_WRITABLE);}
 else x->d.s = SGC_NORMAL;
 
 /* array headers must be always writable, since a write to the
    body does not touch the header.   It may be desirable if there
    are many arrays in a system to make the headers not writable,
    but just SGC_TOUCH the header each time you write to it.   this
    is what is done with t_structure */
  if (t== (tm_of(t_array)->tm_type))
   sgc_type_map[page(x)] |= SGC_PERM_WRITABLE;
   
#endif 
 fw= *(int *)x;
 while (--i >= 0)
   { *(int *)x=fw;
     F_LINK(x)=f;
     f=x;
     x= (object) ((char *)x + size);
   }
 tm->tm_free=f;
 tm->tm_nfree += tm->tm_nppage;
 tm->tm_npage++;
}



object
alloc_object(t)
enum type t;
{
	STATIC object obj;
	STATIC struct typemanager *tm;
	STATIC int i;
	STATIC char *p;
	STATIC object x, f;

ONCE_MORE:
	tm = tm_of(t);

	if (interrupt_flag) {
		interrupt_flag = FALSE;
#ifdef UNIX
		alarm(0);
#endif
		terminal_interrupt(TRUE);
		goto ONCE_MORE;
	}
	obj = tm->tm_free;
	if (obj == OBJNULL) {
		if (tm->tm_npage >= tm->tm_maxpage)
			goto CALL_GBC;
		if (available_pages < 1) {
			Vignore_maximum_pages->s.s_dbind = Cnil;
			goto CALL_GBC;
		}
		p = alloc_page(1);
		add_page_to_freelist(p,tm);
		obj = tm->tm_free;
		if (tm->tm_npage >= tm->tm_maxpage)
			goto CALL_GBC;
	}
	tm->tm_free = ((struct freelist *)obj)->f_link;
	--(tm->tm_nfree);
	(tm->tm_nused)++;
	obj->d.t = (short)t;
	obj->d.m = FALSE;
	return(obj);
#define TOTAL_THIS_TYPE(tm) \
	(tm->tm_nppage * (sgc_enabled ? sgc_count_type(tm->tm_type) : tm->tm_npage))
CALL_GBC:
	GBC(tm->tm_type);
	if (tm->tm_nfree == 0 ||
	    (float)tm->tm_nfree * 10.0 < (float) TOTAL_THIS_TYPE(tm))
		goto EXHAUSTED;
	goto ONCE_MORE;

EXHAUSTED:
	if (symbol_value(Vignore_maximum_pages) != Cnil) {
		if (tm->tm_maxpage/2 <= 0)
			tm->tm_maxpage += 1;
		else
			tm->tm_maxpage += tm->tm_maxpage/2;
		goto ONCE_MORE;
	}
	GBC_enable = FALSE;
	vs_push(make_simple_string(tm_table[(int)t].tm_name+1));
	vs_push(make_fixnum(tm->tm_npage));
	GBC_enable = TRUE;
	CEerror("The storage for ~A is exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE to expand the space.",
		"Continues execution.",
		2, vs_top[-2], vs_top[-1]);
	vs_pop;
	vs_pop;
	goto ONCE_MORE;
}

grow_linear(old,fract,grow_min,grow_max)
     int old,grow_min,grow_max,fract;
{int delt;
 if(fract==0) fract=50;
 if(grow_min==0) grow_min=1;
 if(grow_max==0) grow_max=1000;
 delt=(old*fract)/100;
 delt= (delt < grow_min ? grow_min:
	delt > grow_max ? grow_max:
	delt);
 return old + delt;}

object
make_cons(a, d)
object a, d;
{
	STATIC object obj;
	STATIC int i;
	STATIC char *p;
	STATIC object x, f;
	struct typemanager *tm=(&tm_table[(int)t_cons]);
/* #define	tm	(&tm_table[(int)t_cons])*/

ONCE_MORE:
	if (interrupt_flag) {
		interrupt_flag = FALSE;
#ifdef UNIX
		alarm(0);
#endif
		terminal_interrupt(TRUE);
		goto ONCE_MORE;
	}
	obj = tm->tm_free;
	if (obj == OBJNULL) {
		if (tm->tm_npage >= tm->tm_maxpage)
			goto CALL_GBC;
		if (available_pages < 1) {
			Vignore_maximum_pages->s.s_dbind = Cnil;
			goto CALL_GBC;
		}
		p = alloc_page(1);
		add_page_to_freelist(p,tm);
		obj = tm->tm_free ;
		if (tm->tm_npage >= tm->tm_maxpage)
			goto CALL_GBC;
	}
	tm->tm_free = ((struct freelist *)obj)->f_link;
	--(tm->tm_nfree);
	(tm->tm_nused)++;
	obj->c.t = (short)t_cons;
	obj->c.m = FALSE;
	obj->c.c_car = a;
	obj->c.c_cdr = d;
	return(obj);

CALL_GBC:
	GBC(t_cons);
	if (tm->tm_nfree == 0 ||
	    (float)tm->tm_nfree * 10.0 < (float) TOTAL_THIS_TYPE(tm))
		goto EXHAUSTED;
	goto ONCE_MORE;

EXHAUSTED:
	if (symbol_value(Vignore_maximum_pages) != Cnil) {
	  tm->tm_maxpage =
	    grow_linear(tm->tm_maxpage,tm->tm_growth_percent,
			tm->tm_min_grow,tm->tm_max_grow);
		goto ONCE_MORE;
	}
	GBC_enable = FALSE;
	vs_push(make_fixnum(tm->tm_npage));
	GBC_enable = TRUE;
	CEerror("The storage for CONS is exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE to expand the space.",
		"Continues execution.",
		1, vs_top[-1]);
	vs_pop;
	goto ONCE_MORE;
#undef	tm
}


object on_stack_cons(x,y)
     object x,y;
{object p = (object) alloca_val;
 p->c.t= (short)t_cons;
 p->c.m=FALSE;
 p->c.c_car=x;
 p->c.c_cdr=y;
 return p;
}


 

#define	round_up(n)	(((n) + 03) & ~03)

char *
alloc_contblock(n)
int n;
{
	STATIC char *p;
	STATIC struct contblock **cbpp;
	STATIC int i;
	STATIC int m;
	STATIC bool g;
	bool gg;

/*
	printf("allocating %d-byte contiguous block...\n", n);
*/

	g = FALSE;
	n = round_up(n);

ONCE_MORE:
	if (interrupt_flag) {
		interrupt_flag = FALSE;
		gg = g;
		terminal_interrupt(TRUE);
		g = gg;
		goto ONCE_MORE;
	}
	for(cbpp= &cb_pointer; (*cbpp)!=NULL; cbpp= &(*cbpp)->cb_link)
		if ((*cbpp)->cb_size >= n) {
			p = (char *)(*cbpp);
			i = (*cbpp)->cb_size - n;
			*cbpp = (*cbpp)->cb_link;
			--ncb;
			insert_contblock(p+n, i);
			return(p);
		}
	m = (n + PAGESIZE - 1)/PAGESIZE;
	if (ncbpage + m > maxcbpage || available_pages < m) {
		if (available_pages < m)
			Vignore_maximum_pages->s.s_dbind = Cnil;
		if (!g) {
			GBC(t_contiguous);
			g = TRUE;
			goto ONCE_MORE;
		}
		if (symbol_value(Vignore_maximum_pages) != Cnil)
		  {struct typemanager *tm = &tm_table[(int)t_contiguous];
		   maxcbpage=grow_linear(maxcbpage,tm->tm_growth_percent,
			      tm->tm_min_grow, tm->tm_max_grow);
			g = FALSE;
			goto ONCE_MORE;
		}
		vs_push(make_fixnum(ncbpage));
		CEerror("Contiguous blocks exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE-CONTIGUOUS-PAGES to expand the space.",
			"Continues execution.", 1, vs_head);
		vs_pop;
		g = FALSE;
		goto ONCE_MORE;
	}

	p = alloc_page(m);

	for (i = 0;  i < m;  i++)
		type_map[page(p) + i] = (char)t_contiguous;
	ncbpage += m;
	insert_contblock(p+n, PAGESIZE*m - n);
	return(p);
}

insert_contblock(p, s)
char *p;
int s;
{
	struct contblock **cbpp, *cbp;

	if (s < CBMINSIZE)
		return;
	ncb++;
	cbp = (struct contblock *)p;
	cbp->cb_size = s;
	for (cbpp = &cb_pointer;  *cbpp;  cbpp = &((*cbpp)->cb_link))
		if ((*cbpp)->cb_size >= s) {
			cbp->cb_link = *cbpp;
			*cbpp = cbp;
			return;
		}
	cbp->cb_link = NULL;
	*cbpp = cbp;
}

char *
alloc_relblock(n)
int n;
{
	STATIC char *p;
	STATIC bool g;
	bool gg;
	int i;

/*
	printf("allocating %d-byte relocatable block...\n", n);
*/

	g = FALSE;
	n = round_up(n);

ONCE_MORE:
	if (interrupt_flag) {
		interrupt_flag = FALSE;
		gg = g;
		terminal_interrupt(TRUE);
		g = gg;
		goto ONCE_MORE;
	}
	if (rb_limit - rb_pointer < n) {
		if (!g) {
			GBC(t_relocatable);
			g = TRUE;
			{ float f1 = (float)(rb_limit - rb_pointer),
				f2 = (float)(rb_limit - rb_start);

				if (f1 * 10.0 < f2) 
				;
			else
				goto ONCE_MORE;
			}
		}
		if (symbol_value(Vignore_maximum_pages) != Cnil)
		  {struct typemanager *tm = &tm_table[(int)t_relocatable];
		   nrbpage=grow_linear(i=nrbpage,tm->tm_growth_percent,
			      tm->tm_min_grow, tm->tm_max_grow);
		   if (available_pages < 0)
		     nrbpage = i;
		   else {
			  rb_end +=  (PAGESIZE* (nrbpage -i));
			  rb_limit = rb_end - 2*RB_GETA;
			  if (page(rb_end) - page(heap_end) !=
			      holepage + nrbpage)
			    FEerror("bad rb_end");
			  alloc_page(-( nrbpage + holepage));
			  g = FALSE;
			  goto ONCE_MORE;
			}
		}
		if (rb_limit > rb_end - 2*RB_GETA)
			error("relocatable blocks exhausted");
		rb_limit += RB_GETA;
		vs_push(make_fixnum(nrbpage));
		CEerror("Relocatable blocks exhausted.~%\
Currently, ~D pages are allocated.~%\
Use ALLOCATE-RELOCATABLE-PAGES to expand the space.",
			"Continues execution.", 1, vs_head);
		vs_pop;
		g = FALSE;
		goto ONCE_MORE;
	}
	p = rb_pointer;
	rb_pointer += n;
	return(p);
}

init_tm(t, name, elsize, nelts,sgc)
enum type t;
char name[];
int elsize, nelts;
{
	int i, j;
	int maxpage;
	/* round up to next number of pages */
	maxpage = (((nelts * elsize) + PAGESIZE -1)/PAGESIZE);
	tm_table[(int)t].tm_name = name;
	for (j = -1, i = 0;  i < (int)t_end;  i++)
		if (tm_table[i].tm_size != 0 &&
		    tm_table[i].tm_size >= elsize &&
		    (j < 0 || tm_table[j].tm_size > tm_table[i].tm_size))
			j = i;
	if (j >= 0) {
		tm_table[(int)t].tm_type = (enum type)j;
		tm_table[j].tm_maxpage += maxpage;
#ifdef SGC		
		tm_table[j].tm_sgc += sgc;
#endif
		return;
	}
	tm_table[(int)t].tm_type = t;
	tm_table[(int)t].tm_size = round_up(elsize);
	tm_table[(int)t].tm_nppage = PAGESIZE/round_up(elsize);
	tm_table[(int)t].tm_free = OBJNULL;
	tm_table[(int)t].tm_nfree = 0;
	tm_table[(int)t].tm_nused = 0;
	tm_table[(int)t].tm_npage = 0;
	tm_table[(int)t].tm_maxpage = maxpage;
	tm_table[(int)t].tm_gbccount = 0;
#ifdef SGC	
	tm_table[(int)t].tm_sgc = sgc;
	tm_table[(int)t].tm_sgc_max = 3000;
	tm_table[(int)t].tm_sgc_minfree = (int)
	  (0.4 * tm_table[(int)t].tm_nppage);
#endif

}

set_maxpage()
{
  /* This is run in init.  Various initializations including getting
     maxpage are here */ 
#ifdef SGC
  page_multiple=getpagesize()/PAGESIZE;
  if (page_multiple==0) error("PAGESIZE must be factor of getpagesize()");
  if (sgc_enabled)
    {memory_protect(1);}
  if (~(-MAXPAGE) != MAXPAGE-1) error("MAXPAGE must be power of 2");
  if (core_end)
     bzero(&sgc_type_map[ page(core_end)],MAXPAGE- page(core_end));
#else
  page_multiple=1;
#endif
  
SET_REAL_MAXPAGE;

      }





init_alloc()
{
	int i, j;
	struct typemanager *tm;
	char *p, *q;
	enum type t;
	int c;
	
#ifdef UNIX
#ifndef DGUX
#ifndef NeXT
	{
		extern object malloc_list;
		malloc_list = Cnil;
		enter_mark_origin(&malloc_list);
	}
#endif
#endif
#endif	
	holepage = INIT_HOLEPAGE;
	new_holepage = HOLEPAGE;
	nrbpage = INIT_NRBPAGE;

	set_maxpage();


	INIT_ALLOC;
	

	alloc_page(-(holepage + nrbpage));
	rb_start = rb_pointer = heap_end + PAGESIZE*holepage;
	rb_end = rb_start + PAGESIZE*nrbpage;
	rb_limit = rb_end - 2*RB_GETA;
#ifdef SGC	
	tm_table[(int)t_relocatable].tm_sgc = 50;
#endif
	
	for (i = 0;  i < MAXPAGE;  i++)
		type_map[i] = (char)t_other;

	init_tm(t_fixnum, "NFIXNUM",
		sizeof(struct fixnum_struct), 8192,20);
	init_tm(t_cons, ".CONS", sizeof(struct cons), 65536 ,50 );
	init_tm(t_structure, "SSTRUCTURE", sizeof(struct structure), 5461,0 );
	init_tm(t_cfun, "fCFUN", sizeof(struct cfun), 4096,0  );
	init_tm(t_sfun, "gSFUN", sizeof(struct sfun),409,0 );
	init_tm(t_string, "\"STRING", sizeof(struct string), 5461,1  );
	init_tm(t_array, "aARRAY", sizeof(struct array), 4681,1 );
	init_tm(t_symbol, "|SYMBOL", sizeof(struct symbol), 3640,1 );
	init_tm(t_bignum, "BBIGNUM", sizeof(struct bignum), 2730,0 );
	init_tm(t_ratio, "RRATIONAL", sizeof(struct ratio), 170,0 );
	init_tm(t_shortfloat, "FSHORT-FLOAT",
		sizeof(struct shortfloat_struct), 256 ,0);
	init_tm(t_longfloat, "LLONG-FLOAT",
		sizeof(struct longfloat_struct), 170 ,0);
	init_tm(t_complex, "CCOMPLEX", sizeof(struct complex), 170 ,0);
	init_tm(t_character,"#CHARACTER",sizeof(struct character), 256 ,0);
	init_tm(t_package, ":PACKAGE", sizeof(struct package), 2*PAGESIZE / sizeof(struct package),0);
	init_tm(t_hashtable, "hHASH-TABLE", sizeof(struct hashtable), 78,0 );
	init_tm(t_vector, "vVECTOR", sizeof(struct vector), 146 ,0);
	init_tm(t_bitvector, "bBIT-VECTOR", sizeof(struct bitvector), 73 ,0);
	init_tm(t_stream, "sSTREAM", sizeof(struct stream), 78 ,0);
	init_tm(t_random, "$RANDOM-STATE", sizeof(struct random), 256 ,0);
	init_tm(t_readtable, "rREADTABLE", sizeof(struct readtable), 256 ,0);
	init_tm(t_pathname, "pPATHNAME", sizeof(struct pathname), 73 ,0);
	init_tm(t_cclosure, "cCCLOSURE", sizeof(struct cclosure), 85 ,0);
	init_tm(t_vfun, "VVFUN", sizeof(struct vfun), 102 ,0);
	init_tm(t_gfun, "gGFUN", sizeof(struct sfun), 0 ,0);
	init_tm(t_cfdata, "cCFDATA", sizeof(struct cfdata), 102 ,0);
	init_tm(t_spice, "!SPICE", sizeof(struct spice), 4096 ,0);
	init_tm(t_fat_string, "FFAT-STRING", sizeof(struct fat_string), 102
		,0);
	init_tm(t_relocatable, "%RELOCATABLE-BLOCKS", 1000,0,20);
	init_tm(t_contiguous, "_CONTIGUOUS-BLOCKS", 1001,0,20);


	ncb = 0;
	ncbpage = 0;
	maxcbpage = 512;
	
}


cant_get_a_type()
{
	FEerror("Can't get a type.", 0);
}

siLallocate()
{
	struct typemanager *tm;
	int c, i;
	char *p, *pp;
	object f, x;
	int t;

	if (vs_top - vs_base < 2)
		too_few_arguments();
	if (vs_top - vs_base > 3)
	  too_many_arguments();
	t= t_from_type(vs_base[0]);
	if (type_of(vs_base[1]) != t_fixnum ||
	    (i = fix(vs_base[1])) < 0)
		FEerror("~A is not a non-negative fixnum.", 1, vs_base[1]);
	tm = tm_of(t);
	if (tm->tm_npage > i) {i=tm->tm_npage;}
	tm->tm_maxpage = i;
	if (vs_top - vs_base == 3 && vs_base[2] != Cnil &&
	    tm->tm_maxpage > tm->tm_npage)
	  goto ALLOCATE;
	vs_top = vs_base;
	vs_push(Ct);
	return;

ALLOCATE:
	if (available_pages < tm->tm_maxpage - tm->tm_npage ||
	    (pp = alloc_page(tm->tm_maxpage - tm->tm_npage)) == NULL) {
	vs_push(make_simple_string(tm->tm_name+1));
	FEerror("Can't allocate ~D pages for ~A.", 2, vs_base[1], vs_top[-1]);
	}
	for (;  tm->tm_npage < tm->tm_maxpage;  pp += PAGESIZE)
	  add_page_to_freelist(pp,tm);
	vs_top = vs_base;
	vs_push(Ct);
}

t_from_type(type)
     object type;
{object typ= coerce_to_string(type);
 object c = aref1(typ,0);
 int i;
 for (i= (int)t_start ; i < (int)t_contiguous ; i++)
   {struct typemanager *tm = &tm_table[i];
   if(tm->tm_name &&
      0==strncmp((tm->tm_name)+1,typ->st.st_self,typ->st.st_fillp)
      )
     return i;}
 FEerror("Unrecognized type");
}
/* When sgc is enabled the TYPE should have at least MIN pages of sgc type,
   and at most MAX of them.   Each page should be FREE_PERCENT free
   when the sgc is turned on.  FREE_PERCENT is an integer between 0 and 100. 
   */
   
object
siSallocate_sgc(type,min,max,free_percent)
     object type;
     int min,max,free_percent;
{int m,t=t_from_type(type);
 struct typemanager *tm;
 object res;
 tm=tm_of(t);
  res= list(3,make_fixnum(tm->tm_sgc),
	   make_fixnum(tm->tm_sgc_max),
	   make_fixnum((100*tm->tm_sgc_minfree)/tm->tm_nppage));
 
 if(min<0 || max< min || min > 3000 || free_percent < 0 || free_percent > 100)
    goto END;
 tm->tm_sgc_max=max;
 tm->tm_sgc=min;
 tm->tm_sgc_minfree= (tm->tm_nppage *free_percent) /100;
 END:
 return res;
}

/* Growth of TYPE will be by at least MIN pages and at most MAX pages.
   It will try to grow PERCENT of the current pages.
   */
object
siSallocate_growth(type,min,max,percent)
int min,max,percent;
object type;
{int  t=t_from_type(type);
 struct typemanager *tm=tm_of(t);
 object res;
 res= list(3,make_fixnum(tm->tm_min_grow),
	   make_fixnum(tm->tm_max_grow),
	   make_fixnum(tm->tm_growth_percent));
 
 if(min<0 || max< min || min > 3000 || percent < 0 || percent > 500)
    goto END;
 tm->tm_max_grow=max;
 tm->tm_min_grow=min;
 tm->tm_growth_percent= percent;
 END:
 return res;
}
 
  

siLallocated_pages()
{
	struct typemanager *tm;
	int c;

	check_arg(1);
	{int t=t_from_type(vs_base[0]);
	 vs_base[0]=make_fixnum(tm_of(t)->tm_npage);}
      }


siLmaxpage()
{
	struct typemanager *tm;
	int c;

	check_arg(1);
	{int t=t_from_type(vs_base[0]);
	 vs_base[0]=make_fixnum(tm_of(t)->tm_npage);}
      }


siLalloc_contpage()
{
	int i, m;
	char *p;

	if (vs_top - vs_base < 1)
		too_few_arguments();
	if (vs_top - vs_base > 2)
		too_many_arguments();
	if (type_of(vs_base[0]) != t_fixnum ||
	    (i = fix(vs_base[0])) < 0)
		FEerror("~A is not a non-negative fixnum.", 1, vs_base[0]);
	if (ncbpage > i)
	  { printf("Allocate contiguous %d: %d already there pages",i,ncbpage);
	    i=ncbpage;}
	maxcbpage = i;
	if (vs_top - vs_base < 2 || vs_base[1] == Cnil) {
		vs_top = vs_base;
		vs_push(Ct);
		return;
	}
	m = maxcbpage - ncbpage;
	if (available_pages < m || (p = alloc_page(m)) == NULL)
		FEerror("Can't allocate ~D pages for contiguous blocks.",
			1, vs_base[0]);
	for (i = 0;  i < m;  i++)
		type_map[page(p + PAGESIZE*i)] = (char)t_contiguous;
	ncbpage += m;
	insert_contblock(p, PAGESIZE*m);
	vs_top = vs_base;
	vs_push(Ct);
}

siLncbpage()
{
	check_arg(0);
	vs_push(make_fixnum(ncbpage));
}

siLmaxcbpage()
{
	check_arg(0);
	vs_push(make_fixnum(maxcbpage));
}

siLalloc_relpage()
{
	int i;
	char *p;

	if (vs_top - vs_base < 1)
		too_few_arguments();
	if (vs_top - vs_base > 2)
		too_many_arguments();
	if (type_of(vs_base[0]) != t_fixnum ||
	    (i = fix(vs_base[0])) < 0)
		FEerror("~A is not a non-negative fixnum.", 1, vs_base[0]);
	if (nrbpage > i && rb_pointer >= rb_start + PAGESIZE*i - 2*RB_GETA
	 || 2*i > real_maxpage-page(heap_end)-new_holepage-real_maxpage/32)
		FEerror("Can't set the limit for relocatable blocks to ~D.",
			1, vs_base[0]);
	rb_end += (i-nrbpage)*PAGESIZE;
	nrbpage = i;
	rb_limit = rb_end - 2*RB_GETA;
	alloc_page(-(holepage + nrbpage));
	vs_top = vs_base;
	vs_push(Ct);
}

siLnrbpage()
{
	check_arg(0);
	vs_push(make_fixnum(nrbpage));
}

siLget_hole_size()
{
	check_arg(0);
	vs_push(make_fixnum(new_holepage));
}

siLset_hole_size()
{
	int i;

	check_arg(1);
	i = fixint(vs_base[0]);
	if (i < 1 ||
	    i > real_maxpage - page(heap_end) - 2*nrbpage - real_maxpage/32)
		FEerror("Illegal value for the hole size.", 0);
	new_holepage = i;
}

init_alloc_function()
{
	make_si_function("ALLOCATE", siLallocate);
	make_si_function("ALLOCATED-PAGES", siLallocated_pages);
	make_si_function("MAXIMUM-ALLOCATABLE-PAGES", siLmaxpage);
	make_si_function("ALLOCATE-CONTIGUOUS-PAGES", siLalloc_contpage);
	make_si_function("ALLOCATED-CONTIGUOUS-PAGES", siLncbpage);
	make_si_function("MAXIMUM-CONTIGUOUS-PAGES", siLmaxcbpage);
	make_si_function("ALLOCATE-RELOCATABLE-PAGES", siLalloc_relpage);
	make_si_function("ALLOCATED-RELOCATABLE-PAGES", siLnrbpage);
	make_si_function("GET-HOLE-SIZE", siLget_hole_size);
	make_si_function("SET-HOLE-SIZE", siLset_hole_size);
	make_si_sfun("ALLOCATE-SGC",siSallocate_sgc,
		     4 | ARGTYPE(0,f_object) | ARGTYPE(1,f_fixnum) |
		     ARGTYPE(2,f_fixnum) | ARGTYPE(3,f_fixnum)
		     | RESTYPE(f_object));


	make_si_sfun("ALLOCATE-GROWTH",siSallocate_growth,
		     4 | ARGTYPE(0,f_object) | ARGTYPE(1,f_fixnum) |
		     ARGTYPE(2,f_fixnum) | ARGTYPE(3,f_fixnum)
		     | RESTYPE(f_object));
	Vignore_maximum_pages
	= make_special("*IGNORE-MAXIMUM-PAGES*", Ct);

}

#ifndef NeXT

#ifdef UNIX
#ifndef DGUX

/*
	UNIX malloc simulator.

	Used by
		getwd, popen, etc.
*/

object malloc_list;

/*  If this is defined, substitute the fast gnu malloc for the slower
    version below.   If you have many calls to malloc this is worth
    your while.   I have only tested it slightly under 4.3Bsd.   There
    the difference in a test run with 120K mallocs and frees,
    was 29 seconds to 1.9 seconds */
    
#ifdef GNU_MALLOC
#include "malloc.c"
#else

char *
malloc(size)
int size;
{
	object x;
#ifdef NOFREE_ERR
	if (GBC_enable==0 && initflag ==0)
	  {
#ifdef SGC
	perm_writable(sbrk(0),size);
#endif 
	   return sbrk(size);
	}
#endif
	x = alloc_simple_string(size);
	vs_push(x);
	x->st.st_self = alloc_contblock(size);
#ifdef SGC
	perm_writable(x->st.st_self,size);
#endif
	malloc_list = make_cons(x, malloc_list);
	vs_pop;
	return(x->st.st_self);
}


void
free(ptr)
#ifndef NO_VOID_STAR
void *
#else
char *
#endif  
  ptr;
{
	object *p;

	for (p = &malloc_list; *p && !endp(*p);  p = &((*p)->c.c_cdr))
		if ((*p)->c.c_car->st.st_self == ptr) {
			insert_contblock((*p)->c.c_car->st.st_self,
					 (*p)->c.c_car->st.st_dim);
			(*p)->c.c_car->st.st_self = NULL;
			*p = (*p)->c.c_cdr;
			return ;
		}
#ifdef NOFREE_ERR
	return ;
#else	
	FEerror("free(3) error.",0);
	return;
#endif	
}

char *
realloc(ptr, size)
char *ptr;
int size;
{
	object x;
	int i, j;

	for (x = malloc_list;  !endp(x);  x = x->c.c_cdr)
		if (x->c.c_car->st.st_self == ptr) {
			x = x->c.c_car;
			if (x->st.st_dim >= size) {
				x->st.st_fillp = size;
				return(ptr);
			} else {
				j = x->st.st_dim;
				x->st.st_self = alloc_contblock(size);
				x->st.st_fillp = x->st.st_dim = size;
				for (i = 0;  i < size;  i++)
					x->st.st_self[i] = ptr[i];
				insert_contblock(ptr, j);
				return(x->st.st_self);
			}
		}
	FEerror("realloc(3) error.", 0);
}

#endif /* gnumalloc */
char *
calloc(nelem, elsize)
int nelem, elsize;
{
	char *ptr;
	int i;

	ptr = malloc(i = nelem*elsize);
	while (--i >= 0)
		ptr[i] = 0;
	return(ptr);
}

cfree(ptr)
char *ptr;
{
	free(ptr);

}
#endif
#endif


#ifndef GNUMALLOC
char *
memalign(align,size)
     int align,size;
{ object x = alloc_simple_string(size);
  x->st.st_self = ALLOC_ALIGNED(alloc_contblock,size,align);
  malloc_list = make_cons(x, malloc_list);
  return x->st.st_self;
}
#ifdef WANT_VALLOC
char *
valloc(size)
int size;     
{ return memalign(getpagesize(),size);}
#endif

#endif

#endif /* NeXT */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.