runtime/realm/tasks.cc
// waits until new work arrives - this will possibly take the counter lock and 
// sleep, so should not be called while holding another lock
waits until new work arrives - this will possibly take the counter lock and
sleep, so should not be called while holding another lock
waits until new work arrives - this will possibly take the counter lock and sleep so should not be called while holding another lock
void ThreadedTaskScheduler::WorkCounter::wait_for_work(long long old_counter)
  {
    AutoLock<> al(mutex);
    if(counter.load_acquire() != old_counter)
      return;
    long long wv_read = wait_value.load();
    if((wv_read >= 0) && (wv_read < old_counter)) {
#ifdef DEBUG_WORK_COUNTER
      printf("WC(%p) broadcast(2) %lld\n", this, wv_read);
#endif
      condvar.broadcast();
    }
    assert(wv_read <= old_counter);
#ifdef DEBUG_REALM
    long long wv_expected = wv_read;
    bool ok = wait_value.compare_exchange(wv_expected, old_counter);
    assert(ok);
#else
    wait_value.store(old_counter);
#endif
    while(counter.fetch_add(0) == old_counter) {
#ifndef NDEBUG
      long long wv_check = wait_value.load();
      assert(wv_check == old_counter);
#endif
#ifdef DEBUG_WORK_COUNTER
      printf("WC(%p) wait %lld (%lld)\n", this, old_counter, wait_value.load());
#endif
#define WORK_COUNTER_TIMEOUT_CHECK
#ifdef WORK_COUNTER_TIMEOUT_CHECK
      bool awakened = condvar.timedwait(1000000000LL);
      if(!awakened && (counter.load_acquire() != old_counter)) {
	static atomic<int> warncount(0);
	static const int MAX_WARNINGS = 10;
	int c = warncount.fetch_add(1) + 1;
	if(c <= MAX_WARNINGS)
	  log_task.warning() << "missed work counter wakeup?"
			     << ((c == MAX_WARNINGS) ? " - suppressing further messages" : "");
	break;
      }
#else
      condvar.wait();
#endif
#ifdef DEBUG_WORK_COUNTER
      printf("WC(%p) ready %lld\n", this, old_counter);
#endif
    }
    wait_value.compare_exchange(old_counter, -1);
  }
void ThreadedTaskScheduler :: WorkCounter :: wait_for_work ( long long old_counter ) { AutoLock < > al ( mutex ) ; if ( counter . load_acquire ( ) != old_counter ) return ; long long wv_read = wait_value . load ( ) ; if ( ( wv_read >= 0 ) && ( wv_read < old_counter ) ) { #ifdef DEBUG_WORK_COUNTER printf ( " \n " , this , wv_read ) ; #endif condvar . broadcast ( ) ; } assert ( wv_read <= old_counter ) ; #ifdef DEBUG_REALM long long wv_expected = wv_read ; bool ok = wait_value . compare_exchange ( wv_expected , old_counter ) ; assert ( ok ) ; #else wait_value . store ( old_counter ) ; #endif while ( counter . fetch_add ( 0 ) == old_counter ) { #ifndef NDEBUG long long wv_check = wait_value . load ( ) ; assert ( wv_check == old_counter ) ; #endif #ifdef DEBUG_WORK_COUNTER printf ( " \n " , this , old_counter , wait_value . load ( ) ) ; #endif #define WORK_COUNTER_TIMEOUT_CHECK #ifdef WORK_COUNTER_TIMEOUT_CHECK bool awakened = condvar . timedwait ( 1000000000LL ) ; if ( ! awakened && ( counter . load_acquire ( ) != old_counter ) ) { static atomic < int > warncount ( 0 ) ; static const int MAX_WARNINGS = 10 ; int c = warncount . fetch_add ( 1 ) + 1 ; if ( c <= MAX_WARNINGS ) log_task . warning ( ) << " " << ( ( c == MAX_WARNINGS ) ? " " : " " ) ; break ; } #else condvar . wait ( ) ; #endif #ifdef DEBUG_WORK_COUNTER printf ( " \n " , this , old_counter ) ; #endif } wait_value . compare_exchange ( old_counter , -1 ) ; }
waits until new work arrives - this will possibly take the counter lock and
sleep, so should not be called while holding another lock
waits until new work arrives - this will possibly take the counter lock and sleep so should not be called while holding another lock
// we assume the caller tried check_for_work() before dropping //  their locks and calling us, so take and hold the lock the entire time // an early out is still needed to make sure the counter hasn't moved on and somebody //  isn't trying to wait on a later value // first, see if we catch anybody waiting on an older version of the counter - they can //  definitely be awakened // blind store - nobody's allowed to change wait_value outside the lock // now that people know we're waiting, wait until the counter updates - //  check before each wait and use a fetch_add to force the reload // sanity-check //while(counter == old_counter) { mutex.unlock(); Thread::yield(); mutex.lock(); } // once we're done, clear the wait value, but only if it's for us