static void dump_component(struct component *c) { struct constant *constant; struct block *block; int bytes; if (c->nconstants <= UCHAR_MAX && c->bytes <= USHRT_MAX) { dump_op(fop_SHORT_COMPONENT); dump_byte(c->nconstants); dump_short((short)(c->bytes)); } else { dump_op(fop_COMPONENT); dump_int(c->nconstants); dump_int(c->bytes); } if (c->debug_name) dump_literal(c->debug_name); else dump_op(fop_FALSE); dump_integer(c->frame_size); dump_debug_info(c); for (constant = c->constants; constant != NULL; constant = constant->next) dump_constant(constant); bytes = 0; for (block = c->blocks; block != NULL; block = block->next) { int count = block->end - block->bytes; dump_bytes(block->bytes, count); bytes += count; } if (bytes != c->bytes) lose("Planned on writing %d bytes, but ended up writing %d instead.", c->bytes, bytes); }
/** * Main scheduling loop **/ static void* do_scheduler(void *arg) { static cpu_tick_t next_poll=0, next_overload_check=0, next_info_dump=0, next_graph_stats=0, now=0; static int pollcount=1000; static int init_done = 0; (void) arg; // suppress GCC "unused parameter" warning in_scheduler = 1; // make sure we start out by saving edge stats for a while if( !init_done ) { init_done = 1; if (conf_no_statcollect) bg_save_stats = 0; else bg_save_stats = 1; GET_REAL_CPU_TICKS( now ); next_graph_stats = now + 1 * ticks_per_second; start_timer(&scheduler_timer); } while( 1 ) { //current_thread = scheduler_thread; sanity_check_threadcounts(); sanity_check_io_stats(); // wake up threads that have timeouts sleepq_check(0); sanity_check_threadcounts(); // break out if there are only daemon threads if(unlikely (num_suspended_threads == 0 && num_runnable_threads == num_daemon_threads)) { // dump the blocking graph if( exit_func_done && conf_dump_blocking_graph ) { tdebug("dumping blocking graph from do_scheduler()\n"); dump_blocking_graph(); } // go back to mainthread, which should now be in exit_func() current_thread = main_thread; in_scheduler = 0; co_call(main_thread->coro, NULL); in_scheduler = 1; if( unlikely(current_thread_exited) ) { // free memory from deleted threads current_thread_exited=0; if (current_thread != main_thread) // main_thread is needed for whole program exit free_thread( current_thread ); } return NULL; } // cheesy way of handling things with timing requirements { GET_REAL_CPU_TICKS( now ); // toggle stats collection if( conf_no_statcollect == 0 && next_graph_stats < now ) { bg_save_stats = 1 - bg_save_stats; if( bg_save_stats ) { // record stats for 100 ms next_graph_stats = now + 100 * ticks_per_millisecond; // update the stats epoch, to allow proper handling of the first data items bg_stats_epoch++; } else { // avoid stats for 2000 ms next_graph_stats = now + 2000 * ticks_per_millisecond; } //output(" *********************** graph stats %s\n", bg_save_stats ? "ON" : "OFF" ); } // resource utalization if( unlikely (next_overload_check < now) ) { check_overload( now ); next_overload_check = now + OVERLOAD_CHECK_INTERVAL; } // poll if( likely( (int)io_polling_func) ) { if( num_runnable_threads==0 || --pollcount <= 0 || next_poll < now ) { //if( num_runnable_threads==0 ) { // poll long long timeout = 0; if( num_runnable_threads==0 ) { if (first_wake_usecs == 0) { timeout = -1; } else { // there are threads in the sleep queue // so poll for i/o till at most that time unsigned long long now; now = current_usecs(); tdebug ("first_wake: %lld, now: %lld\n", first_wake_usecs, now); if (first_wake_usecs > now) timeout = first_wake_usecs - now; } } stop_timer(&scheduler_timer); //if( timeout != -1 ) output("timeout is not zero\n"); io_polling_func( timeout ); // allow blocking start_timer(&scheduler_timer); sanity_check_threadcounts(); #ifndef USE_NIO // sleep for a bit, if there was nothing to do // FIXME: let the IO functions block instead?? if( num_runnable_threads == 0 ) { syscall(SYS_sched_yield); } #endif // vary the poll rate depending on the workload #if 0 if( num_runnable_threads < 5 ) { next_poll = now + (10*ticks_per_millisecond); pollcount = 1000; } else if( num_runnable_threads < 10 ) { next_poll = now + (50*ticks_per_millisecond); pollcount = 2000; } else { next_poll = now + (100*ticks_per_millisecond); pollcount = 3000; } #else next_poll = now + (ticks_per_millisecond << 13); pollcount = 10000; #endif } } // debug stats if( 0 && next_info_dump < now ) { dump_debug_info(); next_info_dump = now + 5 * ticks_per_second; } } // get the head of the run list current_thread = sched_next_thread(); // scheduler gave an invlid even though there are runnable // threads. This indicates that every runnable thead is likely to // require use of an overloaded resource. if( !valid_thread(current_thread) ) { pollcount = 0; continue; } // barf, if the returned thread is still on the sleep queue assert( current_thread->sleep == -1 ); tdebug("running TID %d (%s)\n", current_thread->tid, current_thread->name ? current_thread->name : "no name"); sanity_check_threadcounts(); // call thread stop_timer(&scheduler_timer); start_timer(&app_timer); in_scheduler = 0; co_call(current_thread->coro, NULL); in_scheduler = 1; stop_timer(&app_timer); start_timer(&scheduler_timer); if( unlikely(current_thread_exited) ) { // free memory from deleted threads current_thread_exited=0; if (current_thread != main_thread) // main_thread is needed for whole program exit free_thread( current_thread ); } #ifdef NO_SCHEDULER_THREAD return NULL; #endif } return NULL; }