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 12 namespace mojo { 13 namespace system { 14 15 Waiter::Waiter() 16 : cv_(&lock_), 17 #ifndef NDEBUG 18 initialized_(false), 19 #endif 20 awoken_(false), 21 wait_result_(MOJO_RESULT_INTERNAL) { 22 } 23 24 Waiter::~Waiter() { 25 } 26 27 void 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? 38 MojoResult 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 79 void 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