Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / mojo / edk / 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/edk/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       awake_result_(MOJO_RESULT_INTERNAL),
22       awake_context_(static_cast<uint32_t>(-1)) {
23 }
24
25 Waiter::~Waiter() {
26 }
27
28 void Waiter::Init() {
29 #ifndef NDEBUG
30   initialized_ = true;
31 #endif
32   awoken_ = false;
33   // NOTE(vtl): If performance ever becomes an issue, we can disable the setting
34   // of |awake_result_| (except the first one in |Awake()|) in Release builds.
35   awake_result_ = MOJO_RESULT_INTERNAL;
36 }
37
38 // TODO(vtl): Fast-path the |deadline == 0| case?
39 MojoResult Waiter::Wait(MojoDeadline deadline, uint32_t* context) {
40   base::AutoLock locker(lock_);
41
42 #ifndef NDEBUG
43   DCHECK(initialized_);
44   // It'll need to be re-initialized after this.
45   initialized_ = false;
46 #endif
47
48   // Fast-path the already-awoken case:
49   if (awoken_) {
50     DCHECK_NE(awake_result_, MOJO_RESULT_INTERNAL);
51     if (context)
52       *context = awake_context_;
53     return awake_result_;
54   }
55
56   // |MojoDeadline| is actually a |uint64_t|, but we need a signed quantity.
57   // Treat any out-of-range deadline as "forever" (which is wrong, but okay
58   // since 2^63 microseconds is ~300000 years). Note that this also takes care
59   // of the |MOJO_DEADLINE_INDEFINITE| (= 2^64 - 1) case.
60   if (deadline > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
61     do {
62       cv_.Wait();
63     } while (!awoken_);
64   } else {
65     // NOTE(vtl): This is very inefficient on POSIX, since pthreads condition
66     // variables take an absolute deadline.
67     const base::TimeTicks end_time =
68         base::TimeTicks::Now() +
69         base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline));
70     do {
71       base::TimeTicks now_time = base::TimeTicks::Now();
72       if (now_time >= end_time)
73         return MOJO_RESULT_DEADLINE_EXCEEDED;
74
75       cv_.TimedWait(end_time - now_time);
76     } while (!awoken_);
77   }
78
79   DCHECK_NE(awake_result_, MOJO_RESULT_INTERNAL);
80   if (context)
81     *context = awake_context_;
82   return awake_result_;
83 }
84
85 void Waiter::Awake(MojoResult result, uint32_t context) {
86   base::AutoLock locker(lock_);
87
88   if (awoken_)
89     return;
90
91   awoken_ = true;
92   awake_result_ = result;
93   awake_context_ = context;
94   cv_.Signal();
95   // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released.
96 }
97
98 }  // namespace system
99 }  // namespace mojo