Example #1
0
static void   set_up_pthread_state   (Pthread* pthread)   {
    //        ====================
    //
    pthread->heap				= pthread->task->heap;
    pthread->task->pthread			= pthread;
    //
    pthread->executing_mythryl_code		= FALSE;
    pthread->posix_signal_pending		= FALSE;
    pthread->mythryl_handler_for_posix_signal_is_running		= FALSE;
    //
    pthread->all_posix_signals.seen_count	= 0;
    pthread->all_posix_signals.done_count	= 0;
    pthread->next_posix_signal_id		= 0;
    pthread->next_posix_signal_count			= 0;
    //
    pthread->posix_signal_rotor		= MIN_SYSTEM_SIG;
    pthread->cleaning_signal_handler_state			= LIB7_SIG_IGNORE;
    pthread->cpu_time_at_start_of_last_cleaning		= MALLOC_CHUNK(Time);
    pthread->cumulative_cleaning_cpu_time			= MALLOC_CHUNK(Time);

    for (int i = 0;  i < MAX_POSIX_SIGNALS;  i++) {
	//
	pthread->posix_signal_counts[i].seen_count = 0;
	pthread->posix_signal_counts[i].done_count = 0;
    }

    // Initialize the Mythryl state, including the roots:
    //
    initialize_task( pthread->task );
    //
    pthread->task->argument			= HEAP_VOID;
    pthread->task->fate				= HEAP_VOID;
    pthread->task->current_closure		= HEAP_VOID;
    pthread->task->link_register		= HEAP_VOID;
    pthread->task->program_counter		= HEAP_VOID;
    pthread->task->exception_fate		= HEAP_VOID;
    pthread->task->current_thread		= HEAP_VOID;
    pthread->task->callee_saved_registers[0]	= HEAP_VOID;
    pthread->task->callee_saved_registers[1]	= HEAP_VOID;
    pthread->task->callee_saved_registers[2]	= HEAP_VOID;

    #if NEED_PTHREAD_SUPPORT
	pthread->pid		= 0;
	pthread->status		= NO_PTHREAD_ALLOCATED;
    #endif
}									// fun set_up_pthread_state
Example #2
0
Writer*   WR_OpenFile   (FILE* f)   {
    // 
    // Open a file for writing, and make a writer for it.
    ///
    Writer*	wr;

    if (f == NULL)   return NULL;

    wr = MALLOC_CHUNK(Writer);
    wr->seen_error	= FALSE;
    wr->data	= (void *)f;
    wr->put_word	= Put;
    wr->write	= Write;
    wr->flush	= Flush;
    wr->tell	= Tell;
    wr->seek	= Seek;
    wr->free	= Free;

    return wr;
}
Example #3
0
static Hugechunk*   allocate_a_hugechunk   (
    //              ====================
    //
    Hugechunk*                          free,
    Hugechunk_Header*                   header,
    Hugechunk_Quire_Relocation_Info*   old_region
) {
    Hugechunk*  new_chunk;

    Hugechunk_Relocation_Info* reloc_info;

    int	 first_ram_quantum;

    int total_bytesize
	=
	ROUND_UP_TO_POWER_OF_TWO(
	    //
	    header->bytesize,
	    HUGECHUNK_RAM_QUANTUM_IN_BYTES
	);

    int npages =   total_bytesize >> LOG2_HUGECHUNK_RAM_QUANTUM_IN_BYTES;

    Hugechunk_Quire* hq =  free->hugechunk_quire;

    if (free->bytesize == total_bytesize) {

        // Allocate the whole
        // free area to the chunk:
        //
	new_chunk = free;

    } else {

        // Split the free chunk:
        //
	new_chunk		    =  MALLOC_CHUNK( Hugechunk );
	new_chunk->chunk	    =  free->chunk;
	new_chunk->hugechunk_quire  =  hq;
	//
	free->chunk	     = (Punt)(free->chunk) + total_bytesize;
	free->bytesize -= total_bytesize;
        //
	first_ram_quantum =  GET_HUGECHUNK_FOR_POINTER_PAGE( hq, new_chunk->chunk );

	for (int i = 0;  i < npages;  i++) {
	    //
	    hq->hugechunk_page_to_hugechunk[ first_ram_quantum + i ]
		=
		new_chunk;
        }
    }

    new_chunk->bytesize   =  header->bytesize;
    new_chunk->hugechunk_state =  JUNIOR_HUGECHUNK;

    new_chunk->age	       =  header->age;
    new_chunk->huge_ilk        =  header->huge_ilk;

    hq->free_pages -=  npages;

    // Set up the relocation info:
    //
    reloc_info = MALLOC_CHUNK( Hugechunk_Relocation_Info );
    reloc_info->old_address = header->base_address;
    reloc_info->new_chunk = new_chunk;
    //
    first_ram_quantum = GET_HUGECHUNK_FOR_POINTER_PAGE(old_region, header->base_address);
    //
    for (int i = 0;  i < npages;  i++) {
	//
	old_region->hugechunk_page_to_hugechunk[ first_ram_quantum + i ]
	    =
	    reloc_info;
    }

    return new_chunk;
}									// fun allocate_a_hugechunk
Example #4
0
Task*   make_task   (Bool is_boot,  Heapcleaner_Args* cleaner_args)    {
    //  =========
    //
    // This function is called two places, one each in:
    //
    //     src/c/heapcleaner/import-heap.c
    //     src/c/main/load-compiledfiles.c

    Task* task =  NULL;

    #if NEED_PTHREAD_SUPPORT

	//
	for (int i = 0;   i < MAX_PTHREADS;   i++) {
	    //
	    if (((pthread_table__global[i] = MALLOC_CHUNK(Pthread)) == NULL)
	    ||  ((task = MALLOC_CHUNK(Task)) == NULL)
            ){
		die ("runtime-state.c: unable to allocate pthread_table__global entry");
	    }

	    pthread_table__global[i]->task =  task;
	}
	task =  pthread_table__global[0]->task;

    #else
	if (((pthread_table__global[0] = MALLOC_CHUNK(Pthread)) == NULL)
	||  ((task = MALLOC_CHUNK(Task)) == NULL)
        ){
	    die ("unable to allocate Lib7 state vector");
	}

	pthread_table__global[0]->task =  task;

    #endif

    // Allocate and initialize the heap data structures:
    //
    set_up_heap( task, is_boot, cleaner_args );							// set_up_heap					def in    src/c/heapcleaner/heapcleaner-initialization.c

    #if !NEED_PTHREAD_SUPPORT
	//
	set_up_pthread_state( pthread_table__global[ 0 ] );
    #else
        // 'set_up_heap' has created an agegroup0 buffer;
	//  partition it between our MAX_PTHREADS pthreads:
        //
	partition_agegroup0_buffer_between_pthreads( pthread_table__global );			// partition_agegroup0_buffer_between_pthreads	def in   src/c/heapcleaner/pthread-heapcleaner-stuff.c

        // Initialize the per-Pthread Mythryl state:
        //
	for (int i = 0;  i < MAX_PTHREADS;  i++) {
	    //
	    set_up_pthread_state( pthread_table__global[i] );

	    // Single timers are currently shared
	    // among multiple pthreads:
	    //
	    if (i != 0) {
		pthread_table__global[ i ] -> cpu_time_at_start_of_last_cleaning
              = pthread_table__global[ 0 ] -> cpu_time_at_start_of_last_cleaning;
		//
		pthread_table__global[ i ] -> cumulative_cleaning_cpu_time
	      = pthread_table__global[ 0 ] -> cumulative_cleaning_cpu_time;
	    }
	}

	// Initialize the first Pthread here:
	//
	pthread_table__global[0]->pid  =  pth__get_pthread_id ();				// pth__get_pthread_id				def in    src/c/pthread/pthread-on-posix-threads.c
												// pth__get_pthread_id				def in    src/c/pthread/pthread-on-sgi.c
												// pth__get_pthread_id				def in    src/c/pthread/pthread-on-solaris.c
	pthread_table__global[0]->status =  PTHREAD_IS_RUNNING;
    #endif						// NEED_PTHREAD_SUPPORT

    // Initialize the timers:
    //
    reset_timers( pthread_table__global[0] );		// NEED_PTHREAD_SUPPORT note: For now, only Pthread 0 has timers.

    return task;
}							// fun make_task
Heapcleaner_Args*   handle_cleaner_commandline_arguments   (char **argv) {
    //          ====================================
    //
    // Parse any heapcleaner args from the user commandline:

    char     option[ MAX_COMMANDLINE_ARGUMENT_PART_LENGTH ];
    char*    option_arg;
    Bool     seen_error = FALSE;
    char*    arg;

    Heapcleaner_Args* params;

    if ((params = MALLOC_CHUNK(Heapcleaner_Args)) == NULL) {
	die("unable to allocate heap_params");
    }

    // We use 0 or "-1" to signify that
    // the default value should be used:
    //
    params->agegroup0_buffer_bytesize = 0;
    params->active_agegroups = -1;
    params->oldest_agegroup_keeping_idle_fromspace_buffers = -1;

    #define MATCH(opt)	(strcmp(opt, option) == 0)
    #define CHECK(opt)	{						\
	if (option_arg[0] == '\0') {					\
	    seen_error = TRUE;						\
	    say_error("missing argument for \"%s\" option\n", opt);		\
	    continue;							\
	}								\
    }			// CHECK

    while ((arg = *argv++) != NULL) {
	//								// is_runtime_option		def in    src/c/main/runtime-options.c
        if (is_runtime_option(arg, option, &option_arg)) {		// A runtime option is one starting with "--runtime-".
	    //
	    if (MATCH("gc-gen0-bufsize")) { 				// Set cleaner agegroup0 buffer size.
		//
		CHECK("gc-gen0-bufsize");

		params->agegroup0_buffer_bytesize
		    =
                    get_size_option( ONE_K_BINARY, option_arg );

		if (params->agegroup0_buffer_bytesize < 0) {
		    //
		    seen_error = TRUE;
		    say_error( "bad argument for \"--runtime-gc-gen0-bufsize\" option\n" );
		}

	    } else if (MATCH("gc-generations")) {

		CHECK("gc-generations");
		params->active_agegroups = atoi(option_arg);
		if (params->active_agegroups < 1)
		    params->active_agegroups = 1;
		else if (params->active_agegroups > MAX_ACTIVE_AGEGROUPS)
		    params->active_agegroups = MAX_ACTIVE_AGEGROUPS;

	    } else if (MATCH("vmcache")) {

		CHECK("vmcache");
		params->oldest_agegroup_keeping_idle_fromspace_buffers = atoi(option_arg);
		if (params->oldest_agegroup_keeping_idle_fromspace_buffers < 0) {
		    params->oldest_agegroup_keeping_idle_fromspace_buffers = 0;
		} else if (params->oldest_agegroup_keeping_idle_fromspace_buffers > MAX_ACTIVE_AGEGROUPS) {
		    params->oldest_agegroup_keeping_idle_fromspace_buffers = MAX_ACTIVE_AGEGROUPS;
		}
	    } else if (MATCH("unlimited-heap")) {

		unlimited_heap_is_enabled__global = TRUE;
	    }
	}

	if (seen_error)  return NULL;
    }								// while

    return params;
}
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
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