Index: mojo/system/waiter.cc |
diff --git a/mojo/system/waiter.cc b/mojo/system/waiter.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6dda21fbc50bd5593928f542e49fc8a16397442f |
--- /dev/null |
+++ b/mojo/system/waiter.cc |
@@ -0,0 +1,80 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "mojo/system/waiter.h" |
+ |
+#include <limits> |
+ |
+#include "base/logging.h" |
+#include "base/time/time.h" |
+ |
+namespace mojo { |
+namespace system { |
+ |
+Waiter::Waiter() |
+ : cv_(&lock_), |
+ awoken_(false), |
+ wait_result_(MOJO_RESULT_INTERNAL) { |
+} |
+ |
+Waiter::~Waiter() { |
+} |
+ |
+void Waiter::Init() { |
+ awoken_ = false; |
+ // NOTE(vtl): If performance ever becomes an issue, we can disable the setting |
+ // of |wait_result_| (except the first one in |Awake()|) in Release builds. |
+ wait_result_ = MOJO_RESULT_INTERNAL; |
+} |
+ |
+// TODO(vtl): Fast-path the |deadline == 0| case? |
+MojoResult Waiter::Wait(MojoDeadline deadline) { |
+ base::AutoLock locker(lock_); |
+ |
+ // Fast-path the already-awoken case: |
+ if (awoken_) { |
+ DCHECK_NE(wait_result_, MOJO_RESULT_INTERNAL); |
+ return wait_result_; |
+ } |
+ |
+ // |MojoDeadline| is actually a |uint64_t|, but we need a signed quantity. |
+ // Treat any out-of-range deadline as "forever" (which is wrong, but okay |
+ // since 2^63 microseconds is ~300000 years). Note that this also takes care |
+ // of the |MOJO_DEADLINE_INDEFINITE| (= 2^64 - 1) case. |
+ if (deadline > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) { |
+ do { |
+ cv_.Wait(); |
+ } while (!awoken_); |
+ } else { |
+ // NOTE(vtl): This is very inefficient on POSIX, since pthreads condition |
+ // variables take an absolute deadline. |
+ const base::TimeTicks end_time = base::TimeTicks::HighResNow() + |
+ base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline)); |
+ do { |
+ base::TimeTicks now_time = base::TimeTicks::HighResNow(); |
+ if (now_time >= end_time) |
+ return MOJO_RESULT_DEADLINE_EXCEEDED; |
+ |
+ cv_.TimedWait(end_time - now_time); |
+ } while (!awoken_); |
+ } |
+ |
+ DCHECK_NE(wait_result_, MOJO_RESULT_INTERNAL); |
+ return wait_result_; |
+} |
+ |
+void Waiter::Awake(MojoResult wait_result) { |
+ base::AutoLock locker(lock_); |
+ |
+ if (awoken_) |
+ return; |
+ |
+ awoken_ = true; |
+ wait_result_ = wait_result; |
+ cv_.Signal(); |
+ // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released. |
+} |
+ |
+} // namespace system |
+} // namespace mojo |