diff options
Diffstat (limited to 'chromium/mojo/system/waiter.cc')
-rw-r--r-- | chromium/mojo/system/waiter.cc | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/chromium/mojo/system/waiter.cc b/chromium/mojo/system/waiter.cc new file mode 100644 index 00000000000..5a3150d3bce --- /dev/null +++ b/chromium/mojo/system/waiter.cc @@ -0,0 +1,98 @@ +// 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_), +#ifndef NDEBUG + initialized_(false), +#endif + awoken_(false), + awake_result_(MOJO_RESULT_INTERNAL), + awake_context_(static_cast<uint32_t>(-1)) { +} + +Waiter::~Waiter() { +} + +void Waiter::Init() { +#ifndef NDEBUG + initialized_ = true; +#endif + awoken_ = false; + // NOTE(vtl): If performance ever becomes an issue, we can disable the setting + // of |awake_result_| (except the first one in |Awake()|) in Release builds. + awake_result_ = MOJO_RESULT_INTERNAL; +} + +// TODO(vtl): Fast-path the |deadline == 0| case? +MojoResult Waiter::Wait(MojoDeadline deadline, uint32_t* context) { + base::AutoLock locker(lock_); + +#ifndef NDEBUG + DCHECK(initialized_); + // It'll need to be re-initialized after this. + initialized_ = false; +#endif + + // Fast-path the already-awoken case: + if (awoken_) { + DCHECK_NE(awake_result_, MOJO_RESULT_INTERNAL); + if (context) + *context = awake_context_; + return awake_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(awake_result_, MOJO_RESULT_INTERNAL); + if (context) + *context = awake_context_; + return awake_result_; +} + +void Waiter::Awake(MojoResult result, uint32_t context) { + base::AutoLock locker(lock_); + + if (awoken_) + return; + + awoken_ = true; + awake_result_ = result; + awake_context_ = context; + cv_.Signal(); + // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released. +} + +} // namespace system +} // namespace mojo |