void   set_up_heap   (			// Create and initialize the heap.
    // ===========
    //
    Task*              task,
    Bool               is_boot,
    Heapcleaner_Args*  params
) {
    int		ratio;
    int		max_size = 0;		// Initialized only to suppress a gcc -Wall warning.

    Heap*	heap;
    Agegroup*	ag;

    Multipage_Ram_Region*  multipage_ram_region;

    Val* agegroup0_buffer;

    // Default any parameters unspecified by user:
    //
    if (params->agegroup0_buffer_bytesize == 0)  params->agegroup0_buffer_bytesize  = DEFAULT_AGEGROUP0_BUFFER_BYTESIZE;		// From   src/c/h/runtime-configuration.h
    if (params->active_agegroups           < 0)  params->active_agegroups           = DEFAULT_ACTIVE_AGEGROUPS;				// From   src/c/h/runtime-configuration.h

    if (params->oldest_agegroup_keeping_idle_fromspace_buffers < 0) {
        params->oldest_agegroup_keeping_idle_fromspace_buffers =  DEFAULT_OLDEST_AGEGROUP_KEEPING_IDLE_FROMSPACE_BUFFERS;		// From   src/c/h/runtime-configuration.h
    }

    // First we initialize the underlying memory system:
    //
    set_up_multipage_ram_region_os_interface ();				// set_up_multipage_ram_region_os_interface	def in   src/c/ram/get-multipage-ram-region-from-mach.c
										// set_up_multipage_ram_region_os_interface	def in   src/c/ram/get-multipage-ram-region-from-mmap.c
										// set_up_multipage_ram_region_os_interface	def in   src/c/ram/get-multipage-ram-region-from-win32.c

    // Allocate a ram region to hold
    // the book_to_sibid__global and agegroup0 buffer:
    //
    {   long	book2sibid_bytesize;

	#ifdef TWO_LEVEL_MAP
	    #error two level map not supported
	#else
		book2sibid_bytesize = BOOK2SIBID_TABLE_SIZE_IN_SLOTS * sizeof( Sibid );
	#endif

	multipage_ram_region
	    =
            obtain_multipage_ram_region_from_os(
		//
		MAX_PTHREADS * params->agegroup0_buffer_bytesize
                +
                book2sibid_bytesize
           );

	if (multipage_ram_region == NULL) 	   die ("Unable to allocate ram region for book_to_sibid__global");

	book_to_sibid__global = (Sibid*) BASE_ADDRESS_OF_MULTIPAGE_RAM_REGION( multipage_ram_region );

	agegroup0_buffer = (Val*) (((Punt)book_to_sibid__global) + book2sibid_bytesize);
    }

    // Initialize the book_to_sibid__global:
    //
    #ifdef TWO_LEVEL_MAP
        #error two level map not supported
    #else
	for (int i = 0;  i < BOOK2SIBID_TABLE_SIZE_IN_SLOTS;  i++) {
	    //
	    book_to_sibid__global[ i ] = UNMAPPED_BOOK_SIBID;
	}
    #endif

    // Initialize heap descriptor:
    //
    heap = MALLOC_CHUNK(Heap);
    //
    memset ((char*)heap, 0, sizeof(Heap));
    //
    for (int age = 0;  age < MAX_AGEGROUPS;  age++) {
	//
	ratio = DfltRatios[age];

	if (age == 0) {   max_size = MAX_SZ1( params->agegroup0_buffer_bytesize * MAX_PTHREADS );
	} else {          max_size = (5 * max_size)/2;
	    //
	    if (max_size > 64 * ONE_MEG_BINARY)  {				// WTF? This silliness probably needs to Just Die.  XXX BUGGO FIXME. -- 2011-11-01 CrT
                max_size = 64 * ONE_MEG_BINARY;
	    }
	}

	ag		      =
	heap->agegroup[age]   =  MALLOC_CHUNK( Agegroup );

	ag->heap	= heap;
	ag->age	        = age+1;
	ag->cleanings	= 0;
	ag->ratio	= ratio;
	//
	ag->last_cleaning_count_of_younger_agegroup
	    =
	    0;
	//
	ag->tospace_ram_region			= NULL;
	ag->fromspace_ram_region		= NULL;
	ag->saved_fromspace_ram_region		= NULL;
	ag->coarse_inter_agegroup_pointers_map	= NULL;

	for (int ilk = 0;  ilk < MAX_PLAIN_ILKS;  ilk++) {			// MAX_PLAIN_ILKS		def in    src/c/h/sibid.h
	    //
	    ag->sib[ ilk ] = MALLOC_CHUNK( Sib );
	    //
	    ag->sib[ ilk ]->tospace_bytesize              = 0;
	    ag->sib[ ilk ]->requested_sib_buffer_bytesize = 0;
	    ag->sib[ ilk ]->soft_max_bytesize             = max_size;
	    //
	    ag->sib[ ilk ]->id =   MAKE_SIBID( age+1, ilk+1, 0);
	}
	for (int ilk = 0;  ilk < MAX_HUGE_ILKS;  ilk++) {			// MAX_HUGE_ILKS		def in    src/c/h/sibid.h
	    //
	    ag->hugechunks[ ilk ] = NULL;					// ilk = 0 == CODE__HUGE_ILK	def in    src/c/h/sibid.h
	}
    }

    for (int age = 0;   age < params->active_agegroups;   age++) {
	//
	int k = (age == params->active_agegroups -1)
                     ?  age
                     :  age+1;

	for (int ilk = 0;  ilk < MAX_PLAIN_ILKS;  ilk++) {
	    //
	    heap->agegroup[ age ]->sib[ ilk ]->sib_for_promoted_chunks
                =
                heap->agegroup[ k ]->sib[ ilk ];
	}
    }

    heap->oldest_agegroup_keeping_idle_fromspace_buffers
	=
	params->oldest_agegroup_keeping_idle_fromspace_buffers;

    heap->active_agegroups                    = params->active_agegroups;
    //
    heap->agegroup0_cleanings_done            = 0;
    heap->hugechunk_ramregion_count	      = 0;
    heap->hugechunk_ramregions		      = NULL;
    //
    heap->hugechunk_freelist		      = MALLOC_CHUNK( Hugechunk );
    heap->hugechunk_freelist->chunk	      = (Punt)0;
    //
    heap->hugechunk_freelist->bytesize   = 0;
    heap->hugechunk_freelist->hugechunk_state = FREE_HUGECHUNK;
    heap->hugechunk_freelist->prev	      = heap->hugechunk_freelist;
    //
    heap->hugechunk_freelist->next	      = heap->hugechunk_freelist;
    heap->weak_pointers_forwarded_during_cleaning		    = NULL;

    // Initialize new space:
    //
    heap->multipage_ram_region       =  multipage_ram_region;
    //
    heap->agegroup0_buffer           =  agegroup0_buffer;
    //
    heap->agegroup0_buffer_bytesize  =  params->agegroup0_buffer_bytesize
				      * MAX_PTHREADS;				// "* MAX_PTHREADS" because it gets partitioned into MAX_PTHREADS buffers by
										// partition_agegroup0_buffer_between_pthreads() in   src/c/heapcleaner/pthread-heapcleaner-stuff.c
    //
    set_book2sibid_entries_for_range (
	//
	book_to_sibid__global,
	(Val*) book_to_sibid__global,
	BYTESIZE_OF_MULTIPAGE_RAM_REGION( heap->multipage_ram_region ),
	NEWSPACE_SIBID
    );

    #ifdef VERBOSE
	debug_say ("NewSpace = [%#x, %#x:%#x), %d bytes\n",
	    heap->agegroup0_buffer, HEAP_ALLOCATION_LIMIT( heap ),
	    (Val_Sized_Unt)(heap->agegroup0_buffer)+params->agegroup0_buffer_bytesize, params->agegroup0_buffer_bytesize);
    #endif

    clear_cleaner_statistics( heap );										// clear_cleaner_statistics		def in   src/c/heapcleaner/heapcleaner-initialization.c


    //
    if (heapcleaner_statistics_fd__global > 0) {
	//	
      Cleaner_Statistics_Header   header;									// Cleaner_Statistics_Header		is from   src/c/h/heapcleaner-statistics-2.h
	//
	ZERO_BIGCOUNTER( &heap->total_bytes_allocated );
	//
	header.mask = STATMASK_ALLOC
		    | STATMASK_NGENS
		    | STATMASK_START
		    | STATMASK_STOP;

	header.is_new_runtime = 1;
	//
	header.agegroup0_buffer_bytesize = params->agegroup0_buffer_bytesize;
	header.active_agegroups        = params->active_agegroups;
	//
	{   struct timeval tv;
	    //
	    gettimeofday ( &tv, NULL);
	    //
	    header.start_time.seconds  =  tv.tv_sec;	
	    header.start_time.uSeconds =  tv.tv_usec;	
	};
	//
	write( heapcleaner_statistics_fd__global, (char*)&header, sizeof( Cleaner_Statistics_Header ) );
    }


    if (is_boot) {
	//
	// Create agegroup 1's to-space:
	//
        for (int ilk = 0;  ilk < MAX_PLAIN_ILKS;  ilk++) {
	    //
	    heap->agegroup[ 0 ]->sib[ ilk ]->tospace_bytesize
                =
                BOOKROUNDED_BYTESIZE( 2 * heap->agegroup0_buffer_bytesize );
	}

	if (allocate_and_partition_an_agegroup( heap->agegroup[0] ) == FAILURE)	    die ("unable to allocate initial agegroup 1 buffer\n");

	for (int ilk = 0;  ilk < MAX_PLAIN_ILKS;  ilk++) {
	    //
	    heap->agegroup[ 0 ]->sib[ ilk ]->end_of_fromspace_oldstuff
		=
		heap->agegroup[ 0 ]->sib[ ilk ]->tospace;
	}
    }

    // Initialize the cleaner-related
    // parts of the Mythryl state:
    //
    task->heap	                  =  heap;
    task->heap_allocation_pointer =  (Val*) task->heap->agegroup0_buffer;

    #if NEED_SOFTWARE_GENERATED_PERIODIC_EVENTS
	//
	reset_heap_allocation_limit_for_software_generated_periodic_events( task );
    #else
	task->heap_allocation_limit = HEAP_ALLOCATION_LIMIT( heap );
    #endif
}										// fun set_up_heap
Exemple #2
0
static void   read_heap   (
    //        =========
    //
    Inbuf*       bp,
    Heap_Header* header,
    Task*        task,
    Val*         externs
){
    Heap*		heap =  task->heap;

    Sib_Header*	sib_headers;
    Sib_Header*	p;
    Sib_Header*	q;

    int			sib_headers_bytesize;
    int			i, j, k;

    long		prevSzB[MAX_PLAIN_SIBS], size;
    Sibid*		oldBOOK2SIBID;
    Punt		addrOffset[MAX_AGEGROUPS][MAX_PLAIN_SIBS];

    Hugechunk_Quire_Relocation_Info*	boRelocInfo;

    Addresstable*	boRegionTable;

    // Allocate a book_to_sibid__global for the imported
    // heap image's address space:
    //
    #ifdef TWO_LEVEL_MAP
        #error two level map not supported
    #else
	oldBOOK2SIBID = MALLOC_VEC (Sibid, BOOK2SIBID_TABLE_SIZE_IN_SLOTS);
    #endif

    // Read in the hugechunk region descriptors
    // for the old address space:
    //
    {
	int		  size;
	Hugechunk_Quire_Header* boRgnHdr;

	boRegionTable = make_address_hashtable(LOG2_BOOK_BYTESIZE+1, header->hugechunk_quire_count);

	size = header->hugechunk_quire_count * sizeof(Hugechunk_Quire_Header);

	boRgnHdr = (Hugechunk_Quire_Header*) MALLOC (size);

	heapio__read_block( bp, boRgnHdr, size );

	boRelocInfo = MALLOC_VEC(Hugechunk_Quire_Relocation_Info, header->hugechunk_quire_count);

	for (i = 0;  i < header->hugechunk_quire_count;  i++) {

	    set_book2sibid_entries_for_range(oldBOOK2SIBID,
		(Val*)(boRgnHdr[i].base_address),
		BOOKROUNDED_BYTESIZE(boRgnHdr[i].bytesize),
		HUGECHUNK_DATA_SIBID(1)
            );

	    oldBOOK2SIBID[GET_BOOK_CONTAINING_POINTEE(boRgnHdr[i].base_address)] = HUGECHUNK_RECORD_SIBID(MAX_AGEGROUPS);

	    boRelocInfo[i].first_ram_quantum = boRgnHdr[i].first_ram_quantum;

	    boRelocInfo[i].page_count
                =
                (boRgnHdr[i].bytesize - (boRgnHdr[i].first_ram_quantum - boRgnHdr[i].base_address))
                >>
                LOG2_HUGECHUNK_RAM_QUANTUM_IN_BYTES;

	    boRelocInfo[i].hugechunk_page_to_hugechunk = MALLOC_VEC(Hugechunk_Relocation_Info*, boRelocInfo[i].page_count);

	    for (j = 0;  j < boRelocInfo[i].page_count;  j++) {
	        //
		boRelocInfo[i].hugechunk_page_to_hugechunk[j] = NULL;
            } 
	    addresstable_insert (boRegionTable, boRgnHdr[i].base_address, &(boRelocInfo[i]));
	}
	FREE (boRgnHdr);
    }

    // Read the sib headers:
    //
    sib_headers_bytesize = header->active_agegroups * TOTAL_SIBS * sizeof( Sib_Header );
    //
    sib_headers = (Sib_Header*) MALLOC( sib_headers_bytesize );
    //
    heapio__read_block( bp, sib_headers, sib_headers_bytesize );

    for (i = 0;  i < MAX_PLAIN_SIBS;  i++) {
        //
	prevSzB[i] = task->heap_allocation_buffer_bytesize;
    }

    // Allocate the sib buffers and read in the heap image:
    //
    for (p = sib_headers, i = 0;  i < header->active_agegroups;  i++) {
        //
	Agegroup*  age =  heap->agegroup[ i ];

	// Compute the space required for this agegroup,
	// and mark the oldBOOK2SIBID to reflect the old address space:
	//
	for (q = p, j = 0;  j < MAX_PLAIN_SIBS;  j++) {

	    set_book2sibid_entries_for_range (
		//
		oldBOOK2SIBID,

		(Val*) q->info.o.base_address,

		BOOKROUNDED_BYTESIZE( q->info.o.bytesize ),

		age->sib[ j ]->id
	    );

	    size = q->info.o.bytesize + prevSzB[j];

	    if (j == RO_CONSCELL_SIB
            &&  size > 0
            ){
		size += 2*WORD_BYTESIZE;
	    }

	    age->sib[ j ]->tospace.bytesize
		=
		BOOKROUNDED_BYTESIZE( size );

	    prevSzB[ j ] =  q->info.o.bytesize;

	    q++;
	}

	if (set_up_tospace_sib_buffers_for_agegroup(age) == FALSE) {
	    die ("unable to allocated space for agegroup %d\n", i+1);
        } 
	if (sib_is_active( age->sib[ RW_POINTERS_SIB ] )) {							// sib_is_active	def in    src/c/h/heap.h
	    //
	    make_new_coarse_inter_agegroup_pointers_map_for_agegroup (age);
        }

	// Read in the sib buffers for this agegroup
	// and initialize the address offset table:
	//
	for (int j = 0;  j < MAX_PLAIN_SIBS;  j++) {
	    //
	    Sib* ap = age->sib[ j ];

	    if (p->info.o.bytesize > 0) {

		addrOffset[i][j] = (Punt)(ap->tospace.start) - (Punt)(p->info.o.base_address);

		heapio__seek( bp, (long) p->offset );

		heapio__read_block( bp, (ap->tospace.start), p->info.o.bytesize );

		ap->tospace.used_end  = (Val *)((Punt)(ap->tospace.start) + p->info.o.bytesize);

		ap->fromspace.seniorchunks_end =  ap->tospace.start;

	    } else if (sib_is_active(ap)) {

		ap->fromspace.seniorchunks_end =  ap->tospace.start;
	    }

	    if (verbosity__global > 0)   say(".");

	    p++;
	}

        // Read in the hugechunk sib buffers (currently just codechunks):
        //
	for (int ilk = 0;  ilk < MAX_HUGE_SIBS;  ilk++) {			// MAX_HUGE_SIBS		def in    src/c/h/sibid.h
	    //	
	    Punt	 totSizeB;

	    Hugechunk* free_chunk;
	    Hugechunk* bdp = NULL;		// Without this initialization, gcc -Wall gives a 'possible uninitialized use' warning.

	    Hugechunk_Quire*	 free_quire;
	    Hugechunk_Header*	 boHdrs;

	    int			 boHdrSizeB;
	    int			 index;

	    Hugechunk_Quire_Relocation_Info*  region;

	    if (p->info.bo.hugechunk_quanta_count > 0) {
		//
		totSizeB = p->info.bo.hugechunk_quanta_count << LOG2_HUGECHUNK_RAM_QUANTUM_IN_BYTES;

		free_chunk = allocate_hugechunk_quire( heap, totSizeB );

		free_quire = free_chunk->hugechunk_quire;

		free_quire->age_of_youngest_live_chunk_in_quire
		    =
                    i;

		set_book2sibid_entries_for_range (
		    //
		    book_to_sibid__global,
                    (Val*) free_quire,
		    BYTESIZE_OF_QUIRE( free_quire->quire ),
		    HUGECHUNK_DATA_SIBID( i )
		);

		book_to_sibid__global[ GET_BOOK_CONTAINING_POINTEE( free_quire ) ]
		    =
		    HUGECHUNK_RECORD_SIBID( i );

	        // Read in the hugechunk headers:
                //
		boHdrSizeB = p->info.bo.hugechunk_count * sizeof(Hugechunk_Header);
		//
		boHdrs = (Hugechunk_Header*) MALLOC (boHdrSizeB);
		//
		heapio__read_block (bp, boHdrs, boHdrSizeB);

	        // Read in the hugechunks:
                //
		heapio__read_block( bp, (void *)(free_chunk->chunk), totSizeB );
		//
		if (ilk == CODE__HUGE_SIB) {					// ilk = 0 == CODE__HUGE_SIB	def in    src/c/h/sibid.h
		    //
		    flush_instruction_cache ((void *)(free_chunk->chunk), totSizeB);
		}

	        // Set up the hugechunk descriptors 
                // and per-chunk relocation info:
                //
		for (k = 0;  k < p->info.bo.hugechunk_count;  k++) {
		    //
		    // Find the region relocation info for the
		    // chunk's region in the exported heap:
		    //
		    for (index = GET_BOOK_CONTAINING_POINTEE(boHdrs[k].base_address);
			!SIBID_ID_IS_BIGCHUNK_RECORD(oldBOOK2SIBID[index]);
			index--)
			continue;

		    region = LOOK_UP_HUGECHUNK_REGION (boRegionTable, index);

		    // Allocate the hugechunk record for
		    // the chunk and link it into the list
                    // of hugechunks for its agegroup.
		    //
		    bdp = allocate_a_hugechunk( free_chunk, &(boHdrs[k]), region );

		    bdp->next = age->hugechunks[ ilk ];

		    age->hugechunks[ ilk ] = bdp;

		    ASSERT( bdp->gen == i+1 );

		    if (codechunk_comment_display_is_enabled__global
                    &&  ilk == CODE__HUGE_SIB
                    ){
		        // Dump the comment string of the code chunk.

			Unt8* namestring;
			//
			if ((namestring = get_codechunk_comment_string_else_null( bdp ))) {
			    debug_say ("[%6d bytes] %s\n", bdp->bytesize, (char*)namestring);
                        }
		    }
		}

		if (free_chunk != bdp) {					// if p->info.bo.hugechunk_count can be zero, 'bdp' value here may be bogus. XXX BUGGO FIXME.
		    //
		    // There was some extra space left in the region:
		    //
		    insert_hugechunk_in_doubly_linked_list( heap->hugechunk_freelist, free_chunk);						// insert_hugechunk_in_doubly_linked_list	def in   src/c/h/heap.h
		}

		FREE (boHdrs);
	    }

	    if (verbosity__global > 0)   say(".");

	    p++;
	}
    }

    repair_heap (heap, oldBOOK2SIBID, addrOffset, boRegionTable, externs);

    // Adjust the run-time globals
    // that point into the heap:
    //
    *PTR_CAST( Val*, PERVASIVE_PACKAGE_PICKLE_LIST_REFCELL__GLOBAL )
        =
        repair_word(
            *PTR_CAST( Val*, PERVASIVE_PACKAGE_PICKLE_LIST_REFCELL__GLOBAL ),
	    oldBOOK2SIBID,
            addrOffset,
            boRegionTable,
            externs
        );

    runtime_package__global = repair_word( runtime_package__global, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

#ifdef ASM_MATH
    mathvec__global = repair_word (mathvec__global, oldBOOK2SIBID, addrOffset, boRegionTable, externs);
#endif

    // Adjust the Mythryl registers
    // to the new address space:
    //
    ASSIGN(
        POSIX_INTERPROCESS_SIGNAL_HANDLER_REFCELL__GLOBAL,
	//
        repair_word (
	    //
	    DEREF( POSIX_INTERPROCESS_SIGNAL_HANDLER_REFCELL__GLOBAL ),
	    oldBOOK2SIBID,
	    addrOffset,
	    boRegionTable,
            externs
	)
    );

    task->argument
	=
	repair_word( task->argument, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->fate
	=
	repair_word( task->fate, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->current_closure
	=
	repair_word( task->current_closure, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->program_counter
	=
	repair_word(  task->program_counter, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->link_register
	=
	repair_word (task->link_register, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->exception_fate
	=
	repair_word( task->exception_fate, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->current_thread
	=
	repair_word( task->current_thread, oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->callee_saved_registers[0]
	=
	repair_word( task->callee_saved_registers[0], oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->callee_saved_registers[1]
	=
	repair_word( task->callee_saved_registers[1], oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    task->callee_saved_registers[2]
	=
	repair_word( task->callee_saved_registers[2], oldBOOK2SIBID, addrOffset, boRegionTable, externs );

    // Release storage:
    //
    for (i = 0; i < header->hugechunk_quire_count;  i++) {
      //
	Hugechunk_Relocation_Info*	p;
	for (p = NULL, j = 0;  j < boRelocInfo[i].page_count;  j++) {
	    if ((boRelocInfo[i].hugechunk_page_to_hugechunk[j] != NULL)
	    && (boRelocInfo[i].hugechunk_page_to_hugechunk[j] != p)) {
		FREE (boRelocInfo[i].hugechunk_page_to_hugechunk[j]);
		p = boRelocInfo[i].hugechunk_page_to_hugechunk[j];
	    }
	}
    }

    free_address_table( boRegionTable, FALSE );

    FREE( boRelocInfo    );
    FREE( sib_headers  );
    FREE( oldBOOK2SIBID       );

    // Reset the tospace.swept_end pointers:
    //
    for (int i = 0;  i < heap->active_agegroups;  i++) {
        //
	Agegroup*	age =  heap->agegroup[i];
        //
	for (int j = 0;  j < MAX_PLAIN_SIBS;  j++) {
	    //
	    Sib* ap =  age->sib[ j ];
	    //
	    if (sib_is_active(ap)) {							// sib_is_active	def in    src/c/h/heap.h
		//
		ap->tospace.swept_end
		    =
		    ap->tospace.used_end;
	    }
	}
    }
}                                                       // fun read_heap
void   set_up_heap   (			// Create and initialize the heap.
    // ===========
    //
    Task*              task,
    Bool               is_boot,
    Heapcleaner_Args*  params
) {
    // We are called (only) from
    //
    //     make_task()
    // in
    //     src/c/main/runtime-state.c

    int		max_size = 0;		// Initialized only to suppress a gcc -Wall warning.

    Heap*	heap;
    Agegroup*	ag;

    Quire*  quire;

    Val* agegroup0_master_buffer;

    // Default any parameters unspecified by user:
    //
    if (params->agegroup0_buffer_bytesize == 0)  params->agegroup0_buffer_bytesize  = DEFAULT_AGEGROUP0_BUFFER_BYTESIZE;		// From   src/c/h/runtime-configuration.h
    if (params->active_agegroups           < 0)  params->active_agegroups           = DEFAULT_ACTIVE_AGEGROUPS;				// From   src/c/h/runtime-configuration.h

    if (params->oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings < 0) {
        params->oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings =  DEFAULT_OLDEST_AGEGROUP_RETAINING_FROMSPACE_SIBS_BETWEEN_HEAPCLEANINGS;		// From   src/c/h/runtime-configuration.h
    }

    // First we initialize the underlying memory system:
    //
    set_up_quire_os_interface ();						// set_up_quire_os_interface	def in   src/c/ram/get-quire-from-mach.c
										// set_up_quire_os_interface	def in   src/c/ram/get-quire-from-mmap.c
										// set_up_quire_os_interface	def in   src/c/ram/get-quire-from-win32.c

    // Allocate a ram region to hold
    // the book_to_sibid__global and agegroup0 buffer:
    //
    {   long	book2sibid_bytesize;

	#ifdef TWO_LEVEL_MAP
	    #error two level map not supported
	#else
		book2sibid_bytesize = BOOK2SIBID_TABLE_SIZE_IN_SLOTS * sizeof( Sibid );
	#endif

	quire = obtain_quire_from_os(
		    //
		    MAX_HOSTTHREADS * params->agegroup0_buffer_bytesize
		    +
		    book2sibid_bytesize
	       );

	if (quire == NULL) 	   die ("Unable to allocate ram region for book_to_sibid__global");

	book_to_sibid__global = (Sibid*) BASE_ADDRESS_OF_QUIRE( quire );

	agegroup0_master_buffer = (Val*) (((Vunt)book_to_sibid__global) + book2sibid_bytesize);
    }

    // Initialize the book_to_sibid__global:
    //
    #ifdef TWO_LEVEL_MAP
        #error two level map not supported
    #else
	for (int i = 0;  i < BOOK2SIBID_TABLE_SIZE_IN_SLOTS;  i++) {
	    //
	    book_to_sibid__global[ i ] = UNMAPPED_BOOK_SIBID;
	}
    #endif

    // Initialize heap descriptor:
    //
    heap = MALLOC_CHUNK(Heap);
    //
    memset ((char*)heap, 0, sizeof(Heap));
    //
    for (int age = 0;  age < MAX_AGEGROUPS;  age++) {
	//
	if (age == 0) {   max_size = MAX_SZ1( params->agegroup0_buffer_bytesize * MAX_HOSTTHREADS );	// MAX_SZ1 just multiplies by 6 (why??) -- def in  src/c/h/runtime-configuration.h
	} else {          max_size = (5 * max_size)/2;
	    //
	    if (max_size > 64 * ONE_MEG_BINARY)  {				// WTF? This silliness probably needs to Just Die.  XXX BUGGO FIXME. -- 2011-11-01 CrT
                max_size = 64 * ONE_MEG_BINARY;
	    }
	}

	ag			=
	heap->agegroup[ age ]	=  MALLOC_CHUNK( Agegroup );

	ag->heap		=  heap;
	ag->age			=  age + 1;
	ag->heapcleanings_count	=  0;

	ag->target_heapcleaning_frequency_ratio
	    =
	    default_agegroup_size_ratio__local[ age ];

	ag->heapcleanings_count_of_younger_agegroup_during_last_heapcleaning
	    =
	    0;
	//
	ag->tospace_quire			= NULL;
	ag->fromspace_quire		= NULL;
	ag->retained_fromspace_quire		= NULL;
	ag->coarse_inter_agegroup_pointers_map	= NULL;

	for (int s = 0;  s < MAX_PLAIN_SIBS;  s++) {				// MAX_PLAIN_SIBS		def in    src/c/h/sibid.h
	    //
	    ag->sib[ s ] = MALLOC_CHUNK( Sib );
	    //
	    ag->sib[ s ]->tospace.bytesize              = 0;
	    ag->sib[ s ]->requested_extra_free_bytes = 0;
	    ag->sib[ s ]->soft_max_bytesize             = max_size;
	    //
	    ag->sib[ s ]->id =   MAKE_SIBID( age+1, s+1, 0);
	}
	for (int s = 0;  s < MAX_HUGE_SIBS;  s++) {				// MAX_HUGE_SIBS		def in    src/c/h/sibid.h
	    //
	    ag->hugechunks[ s ] = NULL;						// s = 0 == CODE__HUGE_SIB	def in    src/c/h/sibid.h
	}
    }

    for (int a = 0;   a < params->active_agegroups;   a++) {
	//
	int k = (a == params->active_agegroups -1)
                     ?  a
                     :  a+1;

	for (int s = 0;  s < MAX_PLAIN_SIBS;  s++) {
	    //
	    heap->agegroup[ a ]->sib[ s ]->sib_for_promoted_chunks
                =
                heap->agegroup[ k ]->sib[ s ];

	    heap->agegroup[ a ]->sib[ s ]->current_bytes_in_use  = 0;		// This field is only for display/debugging; it plays no algorithmic role.
	    heap->agegroup[ a ]->sib[ s ]->previous_bytes_in_use = 0;		// This field is only for display/debugging; it plays no algorithmic role.
	}
    }

    heap->oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings
	=
	params->oldest_agegroup_retaining_fromspace_sibs_between_heapcleanings;

    heap->active_agegroups			= params->active_agegroups;
    //
    heap->agegroup0_heapcleanings_count		= 0;
    heap->hugechunk_quire_count			= 0;
    heap->hugechunk_quires			= NULL;
    //
    heap->hugechunk_freelist			= MALLOC_CHUNK( Hugechunk );
    heap->hugechunk_freelist->chunk		= (Vunt)0;
    //
    heap->hugechunk_freelist->bytesize		= 0;
    heap->hugechunk_freelist->hugechunk_state	= FREE_HUGECHUNK;
    heap->hugechunk_freelist->prev		= heap->hugechunk_freelist;
    //
    heap->hugechunk_freelist->next		= heap->hugechunk_freelist;
    //
    heap->weakrefs_forwarded_during_heapcleaning		= NULL;

    // Initialize new space:
    //
    heap->quire       =  quire;
    //
    heap->agegroup0_master_buffer    =  agegroup0_master_buffer;
    //
    heap->agegroup0_master_buffer_bytesize
        =
        params->agegroup0_buffer_bytesize * MAX_HOSTTHREADS;			// "* MAX_HOSTTHREADS" because it gets partitioned into MAX_HOSTTHREADS separate buffers by
										// partition_agegroup0_buffer_between_hostthreads() in   src/c/heapcleaner/hostthread-heapcleaner-stuff.c
    //
    set_book2sibid_entries_for_range (
	//
	book_to_sibid__global,
	(Val*) book_to_sibid__global,
	BYTESIZE_OF_QUIRE( heap->quire ),
	AGEGROUP0_SIBID
    );


    clear_heapcleaner_statistics( heap );


    //
    if (heapcleaner_statistics_fd__global > 0) {
	//	
      Cleaner_Statistics_Header   header;									// Cleaner_Statistics_Header		is from   src/c/h/heapcleaner-statistics-2.h
	//
	ZERO_BIGCOUNTER( &heap->total_bytes_allocated );
	//
	header.mask = STATMASK_ALLOC
		    | STATMASK_NGENS
		    | STATMASK_START
		    | STATMASK_STOP;

	header.is_new_runtime = 1;
	//
	header.agegroup0_buffer_bytesize = params->agegroup0_buffer_bytesize;
	header.active_agegroups        = params->active_agegroups;
	//
	{   struct timeval tv;
	    //
	    gettimeofday ( &tv, NULL);
	    //
	    header.start_time.seconds  =  tv.tv_sec;	
	    header.start_time.uSeconds =  tv.tv_usec;	
	};
	//
	write( heapcleaner_statistics_fd__global, (char*)&header, sizeof( Cleaner_Statistics_Header ) );
    }


    if (is_boot) {
	//
	// Create agegroup 1's to-space:
	//
        for (int s = 0;  s < MAX_PLAIN_SIBS;  s++) {
	    //
	    heap->agegroup[ 0 ]->sib[ s ]->tospace.bytesize
                =
                BOOKROUNDED_BYTESIZE( 2 * (heap->agegroup0_master_buffer_bytesize / MAX_HOSTTHREADS) );
	}

	if (set_up_tospace_sib_buffers_for_agegroup( heap->agegroup[0] ) == FALSE)	    die ("unable to allocate initial agegroup 1 buffer\n");

	for (int s = 0;  s < MAX_PLAIN_SIBS;  s++) {
	    //
	    heap->agegroup[ 0 ]->sib[ s ]->fromspace.seniorchunks_end
		=
		heap->agegroup[ 0 ]->sib[ s ]->tospace.start;
	}
    }

    // Initialize the cleaner-related
    // parts of the Mythryl state:
    //
    task->heap	                          =  heap;
    task->heap_allocation_buffer          =  task->heap->agegroup0_master_buffer;
    task->heap_allocation_pointer         =  task->heap->agegroup0_master_buffer;
    task->heap_allocation_buffer_bytesize =  heap->agegroup0_master_buffer_bytesize / MAX_HOSTTHREADS; 

    #if NEED_SOFTWARE_GENERATED_PERIODIC_EVENTS
	//
	reset_heap_allocation_limit_for_software_generated_periodic_events( task );
    #else
	task->heap_allocation_limit
	    =
	    HEAP_ALLOCATION_LIMIT( task );
    #endif
}										// fun set_up_heap