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