diff options
Diffstat (limited to 'mojo/system/waiter.cc')
-rw-r--r-- | mojo/system/waiter.cc | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/mojo/system/waiter.cc b/mojo/system/waiter.cc new file mode 100644 index 0000000..6dda21f --- /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 |