1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "mojo/system/waiter.h" 6 7#include <limits> 8 9#include "base/logging.h" 10#include "base/time/time.h" 11 12namespace mojo { 13namespace system { 14 15Waiter::Waiter() 16 : cv_(&lock_), 17#ifndef NDEBUG 18 initialized_(false), 19#endif 20 awoken_(false), 21 wait_result_(MOJO_RESULT_INTERNAL) { 22} 23 24Waiter::~Waiter() { 25} 26 27void Waiter::Init() { 28#ifndef NDEBUG 29 initialized_ = true; 30#endif 31 awoken_ = false; 32 // NOTE(vtl): If performance ever becomes an issue, we can disable the setting 33 // of |wait_result_| (except the first one in |Awake()|) in Release builds. 34 wait_result_ = MOJO_RESULT_INTERNAL; 35} 36 37// TODO(vtl): Fast-path the |deadline == 0| case? 38MojoResult Waiter::Wait(MojoDeadline deadline) { 39 base::AutoLock locker(lock_); 40 41#ifndef NDEBUG 42 DCHECK(initialized_); 43 // It'll need to be re-initialized after this. 44 initialized_ = false; 45#endif 46 47 // Fast-path the already-awoken case: 48 if (awoken_) { 49 DCHECK_NE(wait_result_, MOJO_RESULT_INTERNAL); 50 return wait_result_; 51 } 52 53 // |MojoDeadline| is actually a |uint64_t|, but we need a signed quantity. 54 // Treat any out-of-range deadline as "forever" (which is wrong, but okay 55 // since 2^63 microseconds is ~300000 years). Note that this also takes care 56 // of the |MOJO_DEADLINE_INDEFINITE| (= 2^64 - 1) case. 57 if (deadline > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { 58 do { 59 cv_.Wait(); 60 } while (!awoken_); 61 } else { 62 // NOTE(vtl): This is very inefficient on POSIX, since pthreads condition 63 // variables take an absolute deadline. 64 const base::TimeTicks end_time = base::TimeTicks::HighResNow() + 65 base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline)); 66 do { 67 base::TimeTicks now_time = base::TimeTicks::HighResNow(); 68 if (now_time >= end_time) 69 return MOJO_RESULT_DEADLINE_EXCEEDED; 70 71 cv_.TimedWait(end_time - now_time); 72 } while (!awoken_); 73 } 74 75 DCHECK_NE(wait_result_, MOJO_RESULT_INTERNAL); 76 return wait_result_; 77} 78 79void Waiter::Awake(MojoResult wait_result) { 80 base::AutoLock locker(lock_); 81 82 if (awoken_) 83 return; 84 85 awoken_ = true; 86 wait_result_ = wait_result; 87 cv_.Signal(); 88 // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released. 89} 90 91} // namespace system 92} // namespace mojo 93