Пример #1
0
Val   _lib7_Sock_to_log   (Task* task,  Val arg)   {
    //===============================================
    //
    // Mythryl type:   String -> Void
    //
    // Write string to currently open logfile via log_if from
    //
    //     src/c/main/error-reporting.c

									    ENTER_MYTHRYL_CALLABLE_C_FN(__func__);

    char* string = HEAP_STRING_AS_C_STRING( arg );

    log_if ("%s", string);				// Safer than doing just log_if(string) -- the string might have a '%' in it.

									    EXIT_MYTHRYL_CALLABLE_C_FN(__func__);
    return HEAP_VOID;
}
Пример #2
0
static void   c_signal_handler   (int sig,  siginfo_t* si,  void* c)   {
    //        ================
    //
    // This is the C signal handler for
    // signals that are to be passed to
    // the Mythryl level via signal_handler in
    //
    //     src/lib/std/src/nj/runtime-signals-guts.pkg
    //

    ucontext_t* scp		/* This variable is unused on some platforms, so suppress 'unused var' compiler warning: */   __attribute__((unused))
        =
        (ucontext_t*) c;

    Pthread* pthread = SELF_PTHREAD;


    // Sanity check:  We compile in a MAX_POSIX_SIGNALS value but
    // have no way to ensure that we don't wind up getting run
    // on some custom kernel supporting more than MAX_POSIX_SIGNAL,
    // so we check here to be safe:
    //
    if (sig >= MAX_POSIX_SIGNALS)    die ("posix-signal.c: c_signal_handler: sig d=%d >= MAX_POSIX_SIGNAL %d\n", sig, MAX_POSIX_SIGNALS ); 


    // Remember that we have seen signal number 'sig'.
    //
    // This will eventually get noticed by  choose_signal()  in
    //
    //     src/c/machine-dependent/signal-stuff.c
    //
    pthread->posix_signal_counts[sig].seen_count++;
    pthread->all_posix_signals.seen_count++;

    log_if(
        "posix-signal.c/c_signal_handler: signal d=%d  seen_count d=%d  done_count d=%d   diff d=%d",
        sig,
        pthread->posix_signal_counts[sig].seen_count,
        pthread->posix_signal_counts[sig].done_count,
        pthread->posix_signal_counts[sig].seen_count - pthread->posix_signal_counts[sig].done_count
    );

    #ifdef SIGNAL_DEBUG
    debug_say ("c_signal_handler: sig = %d, pending = %d, inHandler = %d\n", sig, pthread->posix_signal_pending, pthread->mythryl_handler_for_posix_signal_is_running);
    #endif

    // The following line is needed only when
    // currently executing "pure" C code, but
    // doing it anyway in all other cases will
    // not hurt:
    //
    pthread->ccall_limit_pointer_mask = 0;

    if (  pthread->executing_mythryl_code
    &&  ! pthread->posix_signal_pending
    &&  ! pthread->mythryl_handler_for_posix_signal_is_running
    ){
	pthread->posix_signal_pending = TRUE;

	#ifdef USE_ZERO_LIMIT_PTR_FN
	    //
	    SIG_SavePC( pthread->task, scp );
	    SET_SIGNAL_PROGRAM_COUNTER( scp, Zero_Heap_Allocation_Limit );
	#else
	    SIG_Zero_Heap_Allocation_Limit( scp );			// OK to adjust the heap limit directly.
	#endif
    }
}
Пример #3
0
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
Пример #4
0
static Val   forward_agegroup0_chunk_to_agegroup1   (Agegroup* ag1,  Val v, Task* task, int caller)   {		// 'task' arg is only for debugging, can be removed in production use.
    //       =====================================
    // 
    // Forward pair/record/vector/string 'v' from agegroup0 to agegroup 1.
    // This involves:
    // 
    //   o Duplicating v in the appropriate agegroup 1 to-space buffer.
    //   o Setting v's tagword to FORWARDED_CHUNK_TAGWORD.
    //   o Setting v's first slot to point to the duplicate.
    //   o Returning a pointer to the duplicate.

    Val*           new_chunk;
    Vunt  len_in_words;
    Sib*           sib;

    Val*  chunk =   PTR_CAST(Val*, v);
    Val tagword =   chunk[-1];


    switch (GET_BTAG_FROM_TAGWORD( tagword )) {
    //
    case PAIRS_AND_RECORDS_BTAG:
	//
	len_in_words =  GET_LENGTH_IN_WORDS_FROM_TAGWORD( tagword );

	#ifdef NO_PAIR_STRIP							// 'NO_PAIR_STRIP' appears nowhere else in the codebase.
	    sib = ag1->sib[RO_POINTERS_SIB];
	#else
	    if (len_in_words != 2) {
		sib = ag1->sib[ RO_POINTERS_SIB ];					// This v is not a pair, so fall through to default code.
	    } else {
		//								// This v is a pair, so we'll use special-case code.
		sib = ag1->sib[ RO_CONSCELL_SIB ];					// We'll copy it into the dedicated pairs-only sib in agegroup1.
		new_chunk = sib->tospace.first_free;			// Where to copy it in that sib.
		sib->tospace.first_free += 2;			// Allocate the space for it.
		new_chunk[0] = chunk[0];					// Copy first  word of pair.
		new_chunk[1] = chunk[1];					// Copy second word of pair.
										// Notice that we don't need to copy the tagword -- it is implicit in the fact that we're in the pairsib.
		// Set up the forward pointer in the old pair:
		//
		chunk[-1] = FORWARDED_CHUNK_TAGWORD;
		chunk[0] = (Val)(Vunt)new_chunk;
		return PTR_CAST( Val, new_chunk );				// Done!
	    }
        #endif
	break;


    case RO_VECTOR_HEADER_BTAG:
    case RW_VECTOR_HEADER_BTAG:
	//
	len_in_words =  2;
	//
	sib = ag1->sib[ RO_POINTERS_SIB ];
	break;									// Fall through to generic-case code.


    case RW_VECTOR_DATA_BTAG:
	//
	len_in_words =  GET_LENGTH_IN_WORDS_FROM_TAGWORD( tagword );
	//
	sib = ag1->sib[ RW_POINTERS_SIB ];					// The RW_POINTERS_SIB allows updates, which the RO_POINTERS_SIB does not.
	break;									// Fall through to generic-case code.


    case FOUR_BYTE_ALIGNED_NONPOINTER_DATA_BTAG:
	//
	len_in_words = GET_LENGTH_IN_WORDS_FROM_TAGWORD( tagword );
	//
	sib = ag1->sib[ NONPTR_DATA_SIB ];
	break;									// Fall through to generic-case code.


    case EIGHT_BYTE_ALIGNED_NONPOINTER_DATA_BTAG:
	//
	len_in_words = GET_LENGTH_IN_WORDS_FROM_TAGWORD( tagword );
	//
	sib = ag1->sib[ NONPTR_DATA_SIB ];
	//
	#ifdef ALIGN_FLOAT64S
	#  ifdef CHECK_HEAP
		if (((Vunt)sib->tospace.first_free & WORD_BYTESIZE) == 0) {
		    //
		    *sib->tospace.first_free++ = (Val) 0;
		}
	#  else
		sib->tospace.first_free = (Val*) (((Vunt)sib->tospace.first_free) | WORD_BYTESIZE);
	#  endif
	#endif
	break;									// Fall through to generic-case code.

    case WEAK_POINTER_OR_SUSPENSION_BTAG:
	//
	return forward_special_chunk ( ag1, chunk, tagword );

    case FORWARDED_CHUNK_BTAG:
	//
	return PTR_CAST( Val, FOLLOW_FORWARDING_POINTER(chunk));				// We've already copied this one to agegroup1, so just return pointer to copy.

    default:
	log_if("bad chunk tag %d, chunk = %#x, tagword = %#x   -- forward_agegroup0_chunk_to_agegroup1() in src/c/heapcleaner/heapclean-agegroup0.c", GET_BTAG_FROM_TAGWORD(tagword), chunk, tagword);
	log_if("forward_agegroup0_chunk_to_agegroup1 was called by %s", caller ? "process_task_heap_changelog" : "forward_to_agegroup1_if_in_agegroup0");
	dump_task(task,"forward_agegroup0_chunk_to_agegroup1/default");
	die ("bad chunk tag %d, chunk = %#x, tagword = %#x   -- forward_agegroup0_chunk_to_agegroup1() in src/c/heapcleaner/heapclean-agegroup0.c", GET_BTAG_FROM_TAGWORD(tagword), chunk, tagword);
	exit(1);									// Cannot execute -- just to quiet gcc -Wall.
    }

    // Make an agegroup1 copy of the chunk
    // in the appropriate agegroup1 sib (buffer):
    //
    new_chunk = sib->tospace.first_free;				// Figure out where copy will be located.
    sib->tospace.first_free += (len_in_words + 1);			// Allocate space needed by the copy.
    *new_chunk++ = tagword;							// Install tagword at start of copy.  (Note that 'sib' cannot be RO_CONSCELL_SIB, we handled that case above.)
    ASSERT( sib->tospace.first_free <= sib->tospace.limit );

    COPYLOOP(chunk, new_chunk, len_in_words);					// Copy over the rest of the chunk.
										// COPYLOOP	def in   src/c/heapcleaner/copy-loop.h
    // Set up the forwarding pointer in the original
    // to the copy and return the new chunk:
    //
    chunk[-1] =  FORWARDED_CHUNK_TAGWORD;
    chunk[ 0] =  (Val) (Vunt) new_chunk;

    return PTR_CAST( Val, new_chunk );
}										// fun forward_agegroup0_chunk_to_agegroup1