Chromium Code Reviews| Index: mojo/system/waiter.cc |
| diff --git a/mojo/system/waiter.cc b/mojo/system/waiter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fc94c38c487fe74c96cea8a145c4cb81192f834c |
| --- /dev/null |
| +++ b/mojo/system/waiter.cc |
| @@ -0,0 +1,79 @@ |
| +// 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(); |
|
darin (slow to review)
2013/09/27 15:34:47
You probably had this in mind at the time, but jus
viettrungluu
2013/09/27 17:58:01
Actually, |cv_.Wait()| only returns after |lock_|
|
| +} |
| + |
| +} // namespace system |
| +} // namespace mojo |