Home | History | Annotate | Download | only in system
      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