/** * Main function for the worker thread. */ static void worker_thread_main(void *thread_) { workerthread_t *thread = thread_; threadpool_t *pool = thread->in_pool; workqueue_entry_t *work; workqueue_reply_t result; tor_mutex_acquire(&pool->lock); while (1) { /* lock must be held at this point. */ while (worker_thread_has_work(thread)) { /* lock must be held at this point. */ if (thread->in_pool->generation != thread->generation) { void *arg = thread->in_pool->update_args[thread->index]; thread->in_pool->update_args[thread->index] = NULL; workqueue_reply_t (*update_fn)(void*,void*) = thread->in_pool->update_fn; thread->generation = thread->in_pool->generation; tor_mutex_release(&pool->lock); workqueue_reply_t r = update_fn(thread->state, arg); if (r != WQ_RPL_REPLY) { return; } tor_mutex_acquire(&pool->lock); continue; } work = TOR_TAILQ_FIRST(&pool->work); TOR_TAILQ_REMOVE(&pool->work, work, next_work); work->pending = 0; tor_mutex_release(&pool->lock); /* We run the work function without holding the thread lock. This * is the main thread's first opportunity to give us more work. */ result = work->fn(thread->state, work->arg); /* Queue the reply for the main thread. */ queue_reply(thread->reply_queue, work); /* We may need to exit the thread. */ if (result != WQ_RPL_REPLY) { return; } tor_mutex_acquire(&pool->lock); } /* At this point the lock is held, and there is no work in this thread's * queue. */ /* TODO: support an idle-function */ /* Okay. Now, wait till somebody has work for us. */ if (tor_cond_wait(&pool->condition, &pool->lock, NULL) < 0) { log_warn(LD_GENERAL, "Fail tor_cond_wait."); } } }
static bool _ui_call_update(void) { ui_page_update_fn_t update_fn = pgm_read_word(ui_func_update + ui.page); return update_fn(); }
/** * Works with any update function. */ static void run_main_loop( void (*update_fn)( LoopData*, bool ), LoopData* data, real_t ups ) { assert( data->running && ups > 0 ); // maximum number of frame skips before we force a render static const int MAX_SKIPS = 3; // the maximum possible lag time, lag is capped here static const int MAX_LAG_TIME = 100; // frequency at which to print frame rate info static const int FRAME_RATE_PRINT_TIME = 600; int period = static_cast< int >( 1000.0 / ups ); // frame period in milliseconds // how far we are behind the target framerate int lag_time = 0; // the number of updates since the last render int num_skips = 0; // time since last frame counter start int frame_rate_counter_start = SDL_GetTicks(); // frame rate counter int frame_rate_counter = 0; int total_frame_time = 0; while ( *data->running ) { int start_time = SDL_GetTicks(); // update, only if we are not too far behind, or if we've skipped too many frames if ( lag_time < period || num_skips >= MAX_SKIPS ) { // update update_fn( data, false ); num_skips = 0; frame_rate_counter++; } else { update_fn( data, true ); num_skips++; } if ( frame_rate_counter == FRAME_RATE_PRINT_TIME ) { int curr_time = SDL_GetTicks(); printf( "frame rate: %f, avg frame time: %f\n", FRAME_RATE_PRINT_TIME * 1000 / real_t(curr_time - frame_rate_counter_start), real_t(total_frame_time) / FRAME_RATE_PRINT_TIME ); frame_rate_counter_start = curr_time; frame_rate_counter = 0; total_frame_time = 0; } // compute sleep time until end of period, may be negative int end_time = SDL_GetTicks(); int time_diff = end_time - start_time; int sleep_time = period - time_diff - lag_time; total_frame_time += time_diff; // always yield at least once to keep system responsive SDL_Delay( 1 ); if ( sleep_time > 0 ) { // sleep until end of period while ( int(SDL_GetTicks()) < end_time + sleep_time ) { SDL_Delay( sleep_time - 1 ); } // if we oversleep, add to lag. note this must be nonnegative // because of the while loop above lag_time = (int)(SDL_GetTicks()) - (end_time + sleep_time); } else { // otherwise mark how much we're falling behind // sleep time is negative here, so it's like adding the time we went over lag_time = -sleep_time; } // cap the lag time to avoid lots of skips if ( lag_time > MAX_LAG_TIME ) { lag_time = MAX_LAG_TIME; } } }