14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "mojo/system/waiter.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <limits>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/time/time.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace mojo {
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace system {
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)Waiter::Waiter()
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : cv_(&lock_),
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#ifndef NDEBUG
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      initialized_(false),
198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      awoken_(false),
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      wait_result_(MOJO_RESULT_INTERNAL) {
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)Waiter::~Waiter() {
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void Waiter::Init() {
288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#ifndef NDEBUG
298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  initialized_ = true;
308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  awoken_ = false;
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // NOTE(vtl): If performance ever becomes an issue, we can disable the setting
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // of |wait_result_| (except the first one in |Awake()|) in Release builds.
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  wait_result_ = MOJO_RESULT_INTERNAL;
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// TODO(vtl): Fast-path the |deadline == 0| case?
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)MojoResult Waiter::Wait(MojoDeadline deadline) {
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#ifndef NDEBUG
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(initialized_);
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // It'll need to be re-initialized after this.
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  initialized_ = false;
458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Fast-path the already-awoken case:
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (awoken_) {
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK_NE(wait_result_, MOJO_RESULT_INTERNAL);
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return wait_result_;
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |MojoDeadline| is actually a |uint64_t|, but we need a signed quantity.
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Treat any out-of-range deadline as "forever" (which is wrong, but okay
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // since 2^63 microseconds is ~300000 years). Note that this also takes care
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // of the |MOJO_DEADLINE_INDEFINITE| (= 2^64 - 1) case.
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (deadline > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    do {
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      cv_.Wait();
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } while (!awoken_);
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // NOTE(vtl): This is very inefficient on POSIX, since pthreads condition
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // variables take an absolute deadline.
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const base::TimeTicks end_time = base::TimeTicks::HighResNow() +
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline));
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    do {
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::TimeTicks now_time = base::TimeTicks::HighResNow();
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (now_time >= end_time)
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return MOJO_RESULT_DEADLINE_EXCEEDED;
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      cv_.TimedWait(end_time - now_time);
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } while (!awoken_);
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_NE(wait_result_, MOJO_RESULT_INTERNAL);
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return wait_result_;
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void Waiter::Awake(MojoResult wait_result) {
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (awoken_)
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  awoken_ = true;
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  wait_result_ = wait_result;
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  cv_.Signal();
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released.
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace system
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace mojo
93