- add sources.
[platform/framework/web/crosswalk.git] / src / mojo / system / waiter.cc
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