Exemple #1
0
Val   _util_NetDB_mknetent   (Task *task, struct netent* nentry)   {
    //====================
    //
    // Allocate a Mythryl value of type
    //    Null_Or(   (String, List(String), Addr_Family, Sysword)   )
    // to represent a struct netent value.

    if (nentry == NULL)   return OPTION_NULL;

    // Build the return result:

    // If our agegroup0 buffer is more than half full,
    // empty it by doing a heapcleaning.  This is very
    // conservative -- which is the way I like it. :-)
    //
    if (agegroup0_freespace_in_bytes( task )
      < agegroup0_usedspace_in_bytes( task )
    ){
	call_heapcleaner( task, 0 );
    }

    Val name    =  make_ascii_string_from_c_string__may_heapclean(		task,                    nentry->n_name,     NULL	);		Roots roots1 = { &name,    NULL	    };
    Val aliases =  make_ascii_strings_from_vector_of_c_strings__may_heapclean(	task,                    nentry->n_aliases,  &roots1	);		Roots roots2 = { &aliases, &roots1  };
    Val af      =  make_system_constant__may_heapclean(				task, &_Sock_AddrFamily, nentry->n_addrtype, &roots2	);	//	Roots roots3 = { &af,      &roots2  };
    Val net     =  make_one_word_unt(						task,  (Vunt) (nentry->n_net)			);	//	Roots roots4 = { &net,	   &roots3  };

    Val	result  =  make_four_slot_record(					task,  name, aliases, af, net  );

    return   OPTION_THE( task, result );
}
Exemple #2
0
Val   _util_NetDB_mkservent   (Task* task,  struct servent* sentry)   {
    //=====================
    //
    // Mythryl type:
    //
    // Allocate an Lib7 value of type:
    //    Null_Or(   (String, List(String), Int, String)   )
    // to represent a struct servent value.  Note that the port number is returned
    // in network byteorder, so we need to map it to host order.


    if (sentry == NULL)   return OPTION_NULL;

    // If our agegroup0 buffer is more than half full,
    // empty it by doing a heapcleaning.  This is very
    // conservative -- which is the way I like it. :-)
    //
    if (agegroup0_freespace_in_bytes( task )
      < agegroup0_usedspace_in_bytes( task )
    ){
	call_heapcleaner( task,  0 );
    }

    // Build the return result:

    Val name    =  make_ascii_string_from_c_string__may_heapclean(		task, sentry->s_name,     NULL	);		Roots roots1 = { &name,	    NULL };
    Val aliases =  make_ascii_strings_from_vector_of_c_strings__may_heapclean(	task, sentry->s_aliases, &roots1);		Roots roots2 = { &aliases,  &roots1 };
    Val proto   =  make_ascii_string_from_c_string__may_heapclean(		task, sentry->s_proto,   &roots2);	//	Roots roots3 = { &proto,    &roots2 };
    Val port    =  TAGGED_INT_FROM_C_INT(					ntohs(sentry->s_port)		);

    Val result  =  make_four_slot_record(task,  name, aliases, port, proto);

    return OPTION_THE( task, result );
}
Exemple #3
0
static Val   read_in_compiled_file_list__may_heapclean   (
    //       =========================================
    //
    Task*          task,
    const char*    compiled_files_to_load_filename,
    int*           return_max_boot_path_len,
    Roots*         extra_roots
){
    // Open given file and read from it the list of
    // filenames of compiled_files to be later loaded.
    // Return them as a Mythryl list of Mythryl strings:

    #define    BUF_LEN	1024		//  "This should be plenty for two numbers."   "640K should be enough for anyone."
    char  buf[ BUF_LEN ];

//  Val*   file_names = NULL;
    char*  name_buf   = NULL;

    int    max_num_boot_files = MAX_NUMBER_OF_BOOT_FILES;
    int    max_boot_path_len  = MAX_LENGTH_FOR_A_BOOTFILE_PATHNAME;

    int    file_count = 0;

    FILE*  list_fd =  open_file( compiled_files_to_load_filename, FALSE );

    fprintf (
        stderr,
        "                    load-compiledfiles.c:   Reading   file          %s\n",
        compiled_files_to_load_filename
    );

    if (log_fd) {
	//
	fprintf (
	    log_fd,
	    "                    load-compiledfiles.c:   Reading   file                    %s\n",
	    compiled_files_to_load_filename
	);
    }

    Val  file_list = LIST_NIL;			Roots roots1 = { &file_list, extra_roots };

    if (list_fd) {

        // Read header:
        //
        for (;;) {
	    //
	    if (!fgets (buf, BUF_LEN, list_fd)) {
                die (
                    "compiled_files_to_load file \"%s\" ends before end-of-header (first empty line)",
                    compiled_files_to_load_filename
                );
            }

	    {    char* p = buf;
                 while (*p == ' ' || *p == '\t')   ++p;		// Skip leading whitespace.

		if (p[0] == '\n')   break;			// Header ends at first empty line.

		if (p[0] == '#')   continue;			// Ignore comment lines.

                if (strstr( p,"FILES=") == p) {
		    //
		    max_num_boot_files = strtoul(p+6, NULL, 0);
                    continue;
                }

                if (strstr(p,"MAX_LINE_LENGTH=") == p) {
		    //
		    max_boot_path_len  = strtoul(p+16, NULL, 0) +2;
                    continue;
                }

                die (
                    "compiled_files_to_load file \"%s\" contains unrecognized header line \"%s\"",
                    compiled_files_to_load_filename,
                    p
                );
	    }
        }

        if (max_num_boot_files < 0)  {
	    //
            die("compiled_files_to_load file \"%s\" contains negative files count?! (%d)",
                compiled_files_to_load_filename,
                max_num_boot_files
            );
        } 

        if (max_boot_path_len  < 0) {
	    //
            die("compiled_file_to_load file \"%s\" contains negative boot path len?! (%d)",
                compiled_files_to_load_filename,
                max_boot_path_len
            );
        }


	*return_max_boot_path_len =   max_boot_path_len;		// Tell the calling function.

	if (!(name_buf = MALLOC( max_boot_path_len ))) {
	    //
	    die ("unable to allocate space for .compiled file filenames");
        }

//	if (!(file_names = MALLOC( max_num_boot_files * sizeof(char*) ))) {
//	    //
//	    die ("Unable to allocate space for compiledfiles-to-load name table");
//        }

        // Read in the file names, converting them to
	// Mythryl strings and saving them in a list:
        //
	while (fgets( name_buf, max_boot_path_len, list_fd )) {

	    // Skip leading whitespace:
	    //
	    char* p = name_buf;
            while (*p == ' ' || *p == '\t')   ++p;

	    // Ignore empty lines and comment lines:
	    //
	    if (*p == '\n')   continue;
	    if (*p ==  '#')   continue;

	    // Strip any trailing newline:
	    //
	    {   int j = strlen(p)-1;
		//
	        if (p[j] == '\n') p[j] = '\0';
	    }	

	    if (file_count >= max_num_boot_files)   die ("too many files\n");

	    // If our agegroup0 buffer is more than half full,
	    // empty it by doing a heapcleaning.  This is very
	    // conservative -- which is the way I like it. *grin*
	    //
	    if (agegroup0_freespace_in_bytes( task )
	      < agegroup0_usedspace_in_bytes( task )
	    ){
		call_heapcleaner_with_extra_roots( task,  0, &roots1 );
	    }

	    Val file_name = make_ascii_string_from_c_string__may_heapclean(task, p, &roots1 );

	    file_list = LIST_CONS(task, file_name, file_list);
	}

	if (name_buf)    FREE( name_buf );

	fclose( list_fd );
    }


    // Reverse filename list (to restore
    // original order) and return it:
    //
    {   Val file_list2 = LIST_NIL;			Roots roots2 = { &file_list2, &roots1 };
	//
	for (; file_list != LIST_NIL;  file_list = LIST_TAIL(file_list)) {
	    //
	    Val file_name = LIST_HEAD(file_list);
	    //
	    file_list2 = LIST_CONS(task, file_name, file_list2);

	    // Again, if our agegroup0 buffer is more than
	    // half full, empty it by doing a heapcleaning:
	    //
	    if (agegroup0_freespace_in_bytes( task )
	      < agegroup0_usedspace_in_bytes( task )
	    ){
		call_heapcleaner_with_extra_roots( task,  0, &roots2 );
	    }
	}

	return file_list2;
    }
}
void   heapclean_agegroup0   (Task* task,  Val** roots) {
    // ===================
    //
    // Do "garbage collection" on just agegroup0.
    //
    // 'roots' is a vector of live pointers into agegroup0,
    // harvested from the live register set, global variables
    // into the heap maintained by C code, etc.
    //
    // This fun is called (only) from:
    //
    //     src/c/heapcleaner/call-heapcleaner.c
    //
    // NB: If we have multiple hostthreads running,
    // each has its own agegroup0, but we process
    // all of those during this call, by virtue
    // of being passed all the roots from all the
    // running hostthreads. 

    Heap*      heap =  task->heap;
    Agegroup*  age1 =  heap->agegroup[0];

													    Vunt  age1_tospace_top   [ MAX_PLAIN_SIBS ];
														//
														// Heapcleaner statistics support: We use this to note the
														// current start-of-freespace in each generation-one sib buffer.
														// At the bottom of this fn, the difference between this and
														// the new start-of-freespace gives us the amount of live stuff
														// we've copied into that sib.  This is pure reportage;
														// our algorithms do not depend in any way on this information.

													    long bytes_allocated = agegroup0_usedspace_in_bytes( task );
													    //	
													    INCREASE_BIGCOUNTER( &heap->total_bytes_allocated, bytes_allocated );
														//
														// More heapcleaner statistics reportage.

													    for (int i = 0;  i < MAX_PLAIN_SIBS;  i++) {
														//
														age1_tospace_top[i]
														    =
														    (Vunt)   age1->sib[ i ]->tospace.first_free;
													    }

													    static int callcount = 0;
													    ++callcount;
													    #ifdef VERBOSE
													    if (! (callcount & 0xf)) {
														//
														log_if ("Agegroup 1 before cleaning agegroup0:   (call %d) -- heapclean-agegroup0.c", callcount);
														//
														for (int i = 0;  i < MAX_PLAIN_SIBS;  i++) {
														    //
														    log_if("  %s: to-space bottom = %#x, end of fromspace oldstuff = %#x, tospace.first_free = %#x",
															//
															sib_name__global[ i+1 ],
															//
															age1->sib[ i ]->tospace,
															age1->sib[ i ]->fromspace.seniorchunks_end,
															age1->sib[ i ]->tospace.first_free
														    );
														}
													    }
													    #endif

    // Scan the standard roots.  These are pointers
    // to live data harvested from the live registers,
    // C globals etc, so all agegroup0 records pointed
    // to by them are definitely "live" (nongarbage):
    //
    {   Sibid*  b2s = book_to_sibid__global;									// Cache global locally for speed.   book_to_sibid__global	def in    src/c/heapcleaner/heapcleaner-initialization.c
	Val*    rp;
	while ((rp = *roots++) != NULL) {
	    //
	    forward_to_agegroup1_if_in_agegroup0( b2s, age1, rp, task );
	}
    }
															// The changelog records all writes to refcells or rw_vectors containing pointer data,
															// because such writes might introduce cross-generation pointers that we need to know
    // Scan the changelog -- if there are any new									// about when doing partial heapcleanings.  This makes each such write cost one CONS cell.
    // pointers into agegroup0 from other agegroups									//
    // we need to know about them now:											// Updates to tagged-integer values refcells or rw_vectors cannot introduce such pointers,
    //															// so we do not track them in the changelog and they suffer no slowdown.
    //
    {    for (int i = 0;  i < MAX_HOSTTHREADS;  i++) {									// Potentially need to process one heap storelog per hostthread.
	    //
	    Hostthread* hostthread =  hostthread_table__global[ i ];
	    //
	    Task*   task     =  hostthread->task;
	    //
	    if (hostthread->mode != HOSTTHREAD_IS_VOID) {
		//
		process_task_heap_changelog( task, heap );
	    }
	}
    }

    copy_all_remaining_reachable_values_in_agegroup0_to_agegroup1( age1, task );
								    ++heap->agegroup0_heapcleanings_count;
    null_out_newly_dead_weakrefs( heap );										// null_out_newly_dead_weakrefs		def in    src/c/heapcleaner/heapcleaner-stuff.c

    //////////////////////////////////////////////////////////// 
    // At this point there is nothing left in the agegroup0
    // buffer(s) that we care about, so we're done.  Our caller
    // will reset the agegroup0 buffer(s) to empty and resume
    // allocating linearly in it/them from start to end.
    //////////////////////////////////////////////////////////// 

								    #ifdef VERBOSE
								    if (! (callcount & 0xf)) {
									log_if ("Agegroup 1 after minorgc:    (call %d) -- heapclean-agegroup0.c", callcount);
									for (int i = 0;  i < MAX_PLAIN_SIBS;  i++) {
									  log_if ("  %s: base = %#x, oldTop = %%#x, tospace.first_free = %#x",
									    sib_name__global[i+1], age1->sib[i]->tospace,
										  /* age1->sib[i]->oldTop, */ age1->sib[i]->tospace.first_free);
									}
								    }
								    #endif

								    // Cleaner statistics stuff:
								    {
									long bytes_copied = 0;

									for (int i = 0;  i < MAX_PLAIN_SIBS;  i++) {
									    //
									    int bytes = (Vunt) age1->sib[ i ]->tospace.first_free - age1_tospace_top[ i ];

									    bytes_copied += bytes;

									    INCREASE_BIGCOUNTER( &heap->total_bytes_copied_to_sib[ 0 ][ i ], bytes );
									}

									total_bytes_allocated__global  +=  bytes_allocated;				// Never used otherwise.
									total_bytes_copied__global     +=  bytes_copied;				// Never used otherwise.

									#ifndef VERBOSE
									if (! (callcount & 0xff)) {
									    log_if ("DONE minorgc #%d: %d/%d (%5.2f%%) bytes copied; %%d updates    (callcount %d) -- heapclean-agegroup0.c",
									    callcount,
									    bytes_copied, bytes_allocated,
									    (bytes_allocated ? (double)(100*bytes_copied)/(double)bytes_allocated : 0.0)
									    /* update_count__global - nUpdates */);
									}
									#endif
								    }


								    #ifdef CHECK_HEAP
									check_heap( heap, 1 );								// check_heap		def in    src/c/heapcleaner/check-heap.c
								    #endif

}												// fun heapclean_agegroup0