/**
 * 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.");
    }
  }
}
Exemple #2
0
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;
        }
    }
}